PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - ext/mysqlnd - mysqlnd_net.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 392 471 83.2 %
Date: 2014-10-30 Functions: 27 30 90.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   +----------------------------------------------------------------------+
       3             :   | PHP Version 7                                                        |
       4             :   +----------------------------------------------------------------------+
       5             :   | Copyright (c) 2006-2014 The PHP Group                                |
       6             :   +----------------------------------------------------------------------+
       7             :   | This source file is subject to version 3.01 of the PHP license,      |
       8             :   | that is bundled with this package in the file LICENSE, and is        |
       9             :   | available through the world-wide-web at the following url:           |
      10             :   | http://www.php.net/license/3_01.txt                                  |
      11             :   | If you did not receive a copy of the PHP license and are unable to   |
      12             :   | obtain it through the world-wide-web, please send a note to          |
      13             :   | license@php.net so we can mail you a copy immediately.               |
      14             :   +----------------------------------------------------------------------+
      15             :   | Authors: Andrey Hristov <andrey@mysql.com>                           |
      16             :   |          Ulf Wendel <uwendel@mysql.com>                              |
      17             :   |          Georg Richter <georg@mysql.com>                             |
      18             :   +----------------------------------------------------------------------+
      19             : */
      20             : 
      21             : /* $Id: mysqlnd_ps.c 316906 2011-09-17 10:24:18Z pajoye $ */
      22             : #include "php.h"
      23             : #include "php_globals.h"
      24             : #include "mysqlnd.h"
      25             : #include "mysqlnd_priv.h"
      26             : #include "mysqlnd_wireprotocol.h"
      27             : #include "mysqlnd_statistics.h"
      28             : #include "mysqlnd_debug.h"
      29             : #include "mysqlnd_ext_plugin.h"
      30             : #include "php_network.h"
      31             : #include "zend_ini.h"
      32             : #ifdef MYSQLND_COMPRESSION_ENABLED
      33             : #include <zlib.h>
      34             : #endif
      35             : 
      36             : #ifndef PHP_WIN32
      37             : #include <netinet/tcp.h>
      38             : #else
      39             : #include <winsock.h>
      40             : #endif
      41             : 
      42             : 
      43             : /* {{{ mysqlnd_set_sock_no_delay */
      44             : static int
      45           2 : mysqlnd_set_sock_no_delay(php_stream * stream TSRMLS_DC)
      46             : {
      47             : 
      48           2 :         int socketd = ((php_netstream_data_t*)stream->abstract)->socket;
      49           2 :         int ret = SUCCESS;
      50           2 :         int flag = 1;
      51           2 :         int result = setsockopt(socketd, IPPROTO_TCP,  TCP_NODELAY, (char *) &flag, sizeof(int));
      52             : 
      53           2 :         DBG_ENTER("mysqlnd_set_sock_no_delay");
      54             : 
      55           2 :         if (result == -1) {
      56           0 :                 ret = FAILURE;
      57             :         }
      58             : 
      59           2 :         DBG_RETURN(ret);
      60             : }
      61             : /* }}} */
      62             : 
      63             : 
      64             : /* {{{ mysqlnd_net::network_read_ex */
      65             : static enum_func_status
      66      556792 : MYSQLND_METHOD(mysqlnd_net, network_read_ex)(MYSQLND_NET * const net, zend_uchar * const buffer, const size_t count,
      67             :                                                                                          MYSQLND_STATS * const stats, MYSQLND_ERROR_INFO * const error_info TSRMLS_DC)
      68             : {
      69      556792 :         enum_func_status return_value = PASS;
      70      556792 :         php_stream * net_stream = net->data->m.get_stream(net TSRMLS_CC);
      71      556792 :         size_t old_chunk_size = net_stream->chunk_size;
      72      556792 :         size_t to_read = count, ret;
      73      556792 :         zend_uchar * p = buffer;
      74             : 
      75      556792 :         DBG_ENTER("mysqlnd_net::network_read_ex");
      76      556792 :         DBG_INF_FMT("count="MYSQLND_SZ_T_SPEC, count);
      77             : 
      78      556792 :         net_stream->chunk_size = MIN(to_read, net->data->options.net_read_buffer_size);
      79     1670438 :         while (to_read) {
      80      556857 :                 if (!(ret = php_stream_read(net_stream, (char *) p, to_read))) {
      81           3 :                         DBG_ERR_FMT("Error while reading header from socket");
      82           3 :                         return_value = FAIL;
      83           3 :                         break;
      84             :                 }
      85      556854 :                 p += ret;
      86      556854 :                 to_read -= ret;
      87             :         }
      88      556792 :         MYSQLND_INC_CONN_STATISTIC_W_VALUE(stats, STAT_BYTES_RECEIVED, count - to_read);
      89      556792 :         net_stream->chunk_size = old_chunk_size;
      90      556792 :         DBG_RETURN(return_value);
      91             : }
      92             : /* }}} */
      93             : 
      94             : 
      95             : /* {{{ mysqlnd_net::network_write_ex */
      96             : static size_t
      97       40294 : MYSQLND_METHOD(mysqlnd_net, network_write_ex)(MYSQLND_NET * const net, const zend_uchar * const buffer, const size_t count,
      98             :                                                                                           MYSQLND_STATS * const stats, MYSQLND_ERROR_INFO * const error_info TSRMLS_DC)
      99             : {
     100             :         size_t ret;
     101       40294 :         DBG_ENTER("mysqlnd_net::network_write_ex");
     102       40294 :         DBG_INF_FMT("sending %u bytes", count);
     103       40294 :         ret = php_stream_write(net->data->m.get_stream(net TSRMLS_CC), (char *)buffer, count);
     104       40294 :         DBG_RETURN(ret);
     105             : }
     106             : /* }}} */
     107             : 
     108             : 
     109             : /* {{{ mysqlnd_net::open_pipe */
     110             : static php_stream *
     111           0 : MYSQLND_METHOD(mysqlnd_net, open_pipe)(MYSQLND_NET * const net, const char * const scheme, const size_t scheme_len,
     112             :                                                                            const zend_bool persistent,
     113             :                                                                            MYSQLND_STATS * const conn_stats, MYSQLND_ERROR_INFO * const error_info TSRMLS_DC)
     114             : {
     115             : #if PHP_API_VERSION < 20100412
     116             :         unsigned int streams_options = ENFORCE_SAFE_MODE;
     117             : #else
     118           0 :         unsigned int streams_options = 0;
     119             : #endif
     120             :         dtor_func_t origin_dtor;
     121           0 :         php_stream * net_stream = NULL;
     122             : 
     123           0 :         DBG_ENTER("mysqlnd_net::open_pipe");
     124           0 :         if (persistent) {
     125           0 :                 streams_options |= STREAM_OPEN_PERSISTENT;
     126             :         }
     127           0 :         streams_options |= IGNORE_URL;
     128           0 :         net_stream = php_stream_open_wrapper((char*) scheme + sizeof("pipe://") - 1, "r+", streams_options, NULL);
     129           0 :         if (!net_stream) {
     130           0 :                 SET_CLIENT_ERROR(*error_info, CR_CONNECTION_ERROR, UNKNOWN_SQLSTATE, "Unknown errror while connecting");
     131           0 :                 DBG_RETURN(NULL);
     132             :         }
     133             :         /*
     134             :           Streams are not meant for C extensions! Thus we need a hack. Every connected stream will
     135             :           be registered as resource (in EG(regular_list). So far, so good. However, it won't be
     136             :           unregistered until the script ends. So, we need to take care of that.
     137             :         */
     138           0 :         origin_dtor = EG(regular_list).pDestructor;
     139           0 :         EG(regular_list).pDestructor = NULL;
     140           0 :         zend_hash_index_del(&EG(regular_list), net_stream->res->handle); /* ToDO: should it be res->handle, do streams register with addref ?*/
     141           0 :         EG(regular_list).pDestructor = origin_dtor;
     142           0 :         net_stream->res = NULL;
     143             : 
     144           0 :         DBG_RETURN(net_stream);
     145             : }
     146             : /* }}} */
     147             : 
     148             : 
     149             : /* {{{ mysqlnd_net::open_tcp_or_unix */
     150             : static php_stream *
     151        1875 : MYSQLND_METHOD(mysqlnd_net, open_tcp_or_unix)(MYSQLND_NET * const net, const char * const scheme, const size_t scheme_len,
     152             :                                                                                           const zend_bool persistent,
     153             :                                                                                           MYSQLND_STATS * const conn_stats, MYSQLND_ERROR_INFO * const error_info TSRMLS_DC)
     154             : {
     155             : #if PHP_API_VERSION < 20100412
     156             :         unsigned int streams_options = ENFORCE_SAFE_MODE;
     157             : #else
     158        1875 :         unsigned int streams_options = 0;
     159             : #endif
     160        1875 :         unsigned int streams_flags = STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT;
     161        1875 :         char * hashed_details = NULL;
     162        1875 :         int hashed_details_len = 0;
     163        1875 :         zend_string *errstr = NULL;
     164        1875 :         int errcode = 0;
     165             :         struct timeval tv;
     166             :         dtor_func_t origin_dtor;
     167        1875 :         php_stream * net_stream = NULL;
     168             : 
     169        1875 :         DBG_ENTER("mysqlnd_net::open_tcp_or_unix");
     170             : 
     171        1875 :         net->data->stream = NULL;
     172             : 
     173        1875 :         if (persistent) {
     174        1138 :                 hashed_details_len = mnd_sprintf(&hashed_details, 0, "%p", net);
     175        1138 :                 DBG_INF_FMT("hashed_details=%s", hashed_details);
     176             :         }
     177             : 
     178        1875 :         if (net->data->options.timeout_connect) {
     179         238 :                 tv.tv_sec = net->data->options.timeout_connect;
     180         238 :                 tv.tv_usec = 0;
     181             :         }
     182             : 
     183        1875 :         DBG_INF_FMT("calling php_stream_xport_create");
     184        1875 :         net_stream = php_stream_xport_create(scheme, scheme_len, streams_options, streams_flags,
     185             :                                                                                   hashed_details, (net->data->options.timeout_connect) ? &tv : NULL,
     186             :                                                                                   NULL /*ctx*/, &errstr, &errcode);
     187        1875 :         if (errstr || !net_stream) {
     188          14 :                 DBG_ERR("Error");
     189          14 :                 if (hashed_details) {
     190           2 :                         mnd_sprintf_free(hashed_details);
     191             :                 }
     192          14 :                 errcode = CR_CONNECTION_ERROR;
     193          14 :                 SET_CLIENT_ERROR(*error_info, errcode? errcode:CR_CONNECTION_ERROR, UNKNOWN_SQLSTATE, errstr->val);
     194          14 :                 if (errstr) {
     195             :                         /* no mnd_ since we don't allocate it */
     196          14 :                         zend_string_release(errstr);
     197             :                 }
     198          14 :                 DBG_RETURN(NULL);
     199             :         }
     200        1861 :         if (hashed_details) {
     201             :                 /*
     202             :                   If persistent, the streams register it in EG(persistent_list).
     203             :                   This is unwanted. ext/mysql or ext/mysqli are responsible to clean,
     204             :                   whatever they have to.
     205             :                 */
     206             :                 zend_resource *le;
     207             : 
     208        2272 :                 if ((le = zend_hash_str_find_ptr(&EG(persistent_list), hashed_details, hashed_details_len))) {
     209        1136 :                         origin_dtor = EG(persistent_list).pDestructor;
     210             :                         /*
     211             :                           in_free will let streams code skip destructing - big HACK,
     212             :                           but STREAMS suck big time regarding persistent streams.
     213             :                           Just not compatible for extensions that need persistency.
     214             :                         */
     215        1136 :                         EG(persistent_list).pDestructor = NULL;
     216        1136 :                         zend_hash_str_del(&EG(persistent_list), hashed_details, hashed_details_len);
     217        1136 :                         EG(persistent_list).pDestructor = origin_dtor;
     218        1136 :                         pefree(le, 1);
     219             :                 }
     220             : #if ZEND_DEBUG
     221             :                 /* Shut-up the streams, they don't know what they are doing */
     222             :                 net_stream->__exposed = 1;
     223             : #endif
     224        1136 :                 mnd_sprintf_free(hashed_details);
     225             :         }
     226             : 
     227             :         /*
     228             :           Streams are not meant for C extensions! Thus we need a hack. Every connected stream will
     229             :           be registered as resource (in EG(regular_list). So far, so good. However, it won't be
     230             :           unregistered until the script ends. So, we need to take care of that.
     231             :         */
     232        1861 :         origin_dtor = EG(regular_list).pDestructor;
     233        1861 :         EG(regular_list).pDestructor = NULL;
     234        1861 :         zend_hash_index_del(&EG(regular_list), net_stream->res->handle); /* ToDO: should it be res->handle, do streams register with addref ?*/
     235        1861 :         efree(net_stream->res);
     236        1861 :         net_stream->res = NULL;
     237        1861 :         EG(regular_list).pDestructor = origin_dtor;
     238        1861 :         DBG_RETURN(net_stream);
     239             : }
     240             : /* }}} */
     241             : 
     242             : 
     243             : /* {{{ mysqlnd_net::post_connect_set_opt */
     244             : static void
     245        1861 : MYSQLND_METHOD(mysqlnd_net, post_connect_set_opt)(MYSQLND_NET * const net,
     246             :                                                                                                   const char * const scheme, const size_t scheme_len,
     247             :                                                                                                   MYSQLND_STATS * const conn_stats, MYSQLND_ERROR_INFO * const error_info TSRMLS_DC)
     248             : {
     249        1861 :         php_stream * net_stream = net->data->m.get_stream(net TSRMLS_CC);
     250        1861 :         DBG_ENTER("mysqlnd_net::post_connect_set_opt");
     251        1861 :         if (net_stream) {
     252        1861 :                 if (net->data->options.timeout_read) {
     253             :                         struct timeval tv;
     254        1858 :                         DBG_INF_FMT("setting %u as PHP_STREAM_OPTION_READ_TIMEOUT", net->data->options.timeout_read);
     255        1858 :                         tv.tv_sec = net->data->options.timeout_read;
     256        1858 :                         tv.tv_usec = 0;
     257        1858 :                         php_stream_set_option(net_stream, PHP_STREAM_OPTION_READ_TIMEOUT, 0, &tv);
     258             :                 }
     259             : 
     260        1861 :                 if (!memcmp(scheme, "tcp://", sizeof("tcp://") - 1)) {
     261             :                         /* TCP -> Set TCP_NODELAY */
     262           2 :                         mysqlnd_set_sock_no_delay(net_stream TSRMLS_CC);
     263             :                 }
     264             :         }
     265             : 
     266        1861 :         DBG_VOID_RETURN;
     267             : }
     268             : /* }}} */
     269             : 
     270             : 
     271             : /* {{{ mysqlnd_net::get_open_stream */
     272             : static func_mysqlnd_net__open_stream
     273        1875 : MYSQLND_METHOD(mysqlnd_net, get_open_stream)(MYSQLND_NET * const net, const char * const scheme, const size_t scheme_len,
     274             :                                                                                          MYSQLND_ERROR_INFO * const error_info TSRMLS_DC)
     275             : {
     276        1875 :         func_mysqlnd_net__open_stream ret = NULL;
     277        1875 :         DBG_ENTER("mysqlnd_net::get_open_stream");
     278        1875 :         if (scheme_len > (sizeof("pipe://") - 1) && !memcmp(scheme, "pipe://", sizeof("pipe://") - 1)) {
     279           0 :                 ret = net->data->m.open_pipe;
     280        3739 :         } else if ((scheme_len > (sizeof("tcp://") - 1) && !memcmp(scheme, "tcp://", sizeof("tcp://") - 1))
     281             :                                 ||
     282        1864 :                                 (scheme_len > (sizeof("unix://") - 1) && !memcmp(scheme, "unix://", sizeof("unix://") - 1)))
     283             :         {
     284        1875 :                 ret = net->data->m.open_tcp_or_unix;
     285             :         }
     286             : 
     287        1875 :         if (!ret) {
     288           0 :                 SET_CLIENT_ERROR(*error_info, CR_CONNECTION_ERROR, UNKNOWN_SQLSTATE, "No handler for this scheme");
     289             :         }       
     290             :         
     291        1875 :         DBG_RETURN(ret);
     292             : }
     293             : /* }}} */
     294             : 
     295             : 
     296             : /* {{{ mysqlnd_net::connect_ex */
     297             : static enum_func_status
     298        1875 : MYSQLND_METHOD(mysqlnd_net, connect_ex)(MYSQLND_NET * const net, const char * const scheme, const size_t scheme_len,
     299             :                                                                                 const zend_bool persistent,
     300             :                                                                                 MYSQLND_STATS * const conn_stats, MYSQLND_ERROR_INFO * const error_info TSRMLS_DC)
     301             : {
     302        1875 :         enum_func_status ret = FAIL;
     303        1875 :         func_mysqlnd_net__open_stream open_stream = NULL;
     304        1875 :         DBG_ENTER("mysqlnd_net::connect_ex");
     305             : 
     306        1875 :         net->packet_no = net->compressed_envelope_packet_no = 0;
     307             : 
     308        1875 :         net->data->m.close_stream(net, conn_stats, error_info TSRMLS_CC);
     309             : 
     310        1875 :         open_stream = net->data->m.get_open_stream(net, scheme, scheme_len, error_info TSRMLS_CC);
     311        1875 :         if (open_stream) {
     312        1875 :                 php_stream * net_stream = open_stream(net, scheme, scheme_len, persistent, conn_stats, error_info TSRMLS_CC);
     313        1875 :                 if (net_stream) {
     314        1861 :                         (void) net->data->m.set_stream(net, net_stream TSRMLS_CC);
     315        1861 :                         net->data->m.post_connect_set_opt(net, scheme, scheme_len, conn_stats, error_info TSRMLS_CC);
     316        1861 :                         ret = PASS;
     317             :                 }
     318             :         }
     319             : 
     320        1875 :         DBG_RETURN(ret);
     321             : }
     322             : /* }}} */
     323             : 
     324             : 
     325             : /* We assume that MYSQLND_HEADER_SIZE is 4 bytes !! */
     326             : #define COPY_HEADER(T,A)  do { \
     327             :                 *(((char *)(T)))   = *(((char *)(A)));\
     328             :                 *(((char *)(T))+1) = *(((char *)(A))+1);\
     329             :                 *(((char *)(T))+2) = *(((char *)(A))+2);\
     330             :                 *(((char *)(T))+3) = *(((char *)(A))+3); } while (0)
     331             : #define STORE_HEADER_SIZE(safe_storage, buffer)  COPY_HEADER((safe_storage), (buffer))
     332             : #define RESTORE_HEADER_SIZE(buffer, safe_storage) STORE_HEADER_SIZE((safe_storage), (buffer))
     333             : 
     334             : 
     335             : /* {{{ mysqlnd_net::send_ex */
     336             : /*
     337             :   IMPORTANT : It's expected that buffer has place in the beginning for MYSQLND_HEADER_SIZE !!!!
     338             :                           This is done for performance reasons in the caller of this function.
     339             :                           Otherwise we will have to do send two TCP packets, or do new alloc and memcpy.
     340             :                           Neither are quick, thus the clients of this function are obligated to do
     341             :                           what they are asked for.
     342             : 
     343             :   `count` is actually the length of the payload data. Thus :
     344             :   count + MYSQLND_HEADER_SIZE = sizeof(buffer) (not the pointer but the actual buffer)
     345             : */
     346             : static size_t
     347       40294 : MYSQLND_METHOD(mysqlnd_net, send_ex)(MYSQLND_NET * const net, zend_uchar * const buffer, const size_t count,
     348             :                                                                          MYSQLND_STATS * const conn_stats, MYSQLND_ERROR_INFO * const error_info TSRMLS_DC)
     349             : {
     350             :         zend_uchar safe_buf[((MYSQLND_HEADER_SIZE) + (sizeof(zend_uchar)) - 1) / (sizeof(zend_uchar))];
     351       40294 :         zend_uchar * safe_storage = safe_buf;
     352       40294 :         size_t bytes_sent, packets_sent = 1;
     353       40294 :         size_t left = count;
     354       40294 :         zend_uchar * p = (zend_uchar *) buffer;
     355       40294 :         zend_uchar * compress_buf = NULL;
     356             :         size_t to_be_sent;
     357             : 
     358       40294 :         DBG_ENTER("mysqlnd_net::send_ex");
     359       40294 :         DBG_INF_FMT("count=" MYSQLND_SZ_T_SPEC " compression=%u", count, net->data->compressed);
     360             : 
     361       40294 :         if (net->data->compressed == TRUE) {
     362          13 :                 size_t comp_buf_size = MYSQLND_HEADER_SIZE + COMPRESSED_HEADER_SIZE + MYSQLND_HEADER_SIZE + MIN(left, MYSQLND_MAX_PACKET_SIZE);
     363          13 :                 DBG_INF_FMT("compress_buf_size="MYSQLND_SZ_T_SPEC, comp_buf_size);
     364          13 :                 compress_buf = mnd_emalloc(comp_buf_size);
     365             :         }
     366             : 
     367             :         do {
     368       40294 :                 to_be_sent = MIN(left, MYSQLND_MAX_PACKET_SIZE);
     369       40294 :                 DBG_INF_FMT("to_be_sent=%u", to_be_sent);
     370       40294 :                 DBG_INF_FMT("packets_sent=%u", packets_sent);
     371       40294 :                 DBG_INF_FMT("compressed_envelope_packet_no=%u", net->compressed_envelope_packet_no);
     372       40294 :                 DBG_INF_FMT("packet_no=%u", net->packet_no);
     373             : #ifdef MYSQLND_COMPRESSION_ENABLED
     374       40294 :                 if (net->data->compressed == TRUE) {
     375             :                         /* here we need to compress the data and then write it, first comes the compressed header */
     376          13 :                         size_t tmp_complen = to_be_sent;
     377             :                         size_t payload_size;
     378          13 :                         zend_uchar * uncompressed_payload = p; /* should include the header */
     379             : 
     380          13 :                         STORE_HEADER_SIZE(safe_storage, uncompressed_payload);
     381          13 :                         int3store(uncompressed_payload, to_be_sent);
     382          13 :                         int1store(uncompressed_payload + 3, net->packet_no);
     383          13 :                         if (PASS == net->data->m.encode((compress_buf + COMPRESSED_HEADER_SIZE + MYSQLND_HEADER_SIZE), &tmp_complen,
     384             :                                                                            uncompressed_payload, to_be_sent + MYSQLND_HEADER_SIZE TSRMLS_CC))
     385             :                         {
     386           2 :                                 int3store(compress_buf + MYSQLND_HEADER_SIZE, to_be_sent + MYSQLND_HEADER_SIZE);
     387           2 :                                 payload_size = tmp_complen;
     388             :                         } else {
     389          11 :                                 int3store(compress_buf + MYSQLND_HEADER_SIZE, 0);
     390          11 :                                 memcpy(compress_buf + MYSQLND_HEADER_SIZE + COMPRESSED_HEADER_SIZE, uncompressed_payload, to_be_sent + MYSQLND_HEADER_SIZE);
     391          11 :                                 payload_size = to_be_sent + MYSQLND_HEADER_SIZE;
     392             :                         }
     393          13 :                         RESTORE_HEADER_SIZE(uncompressed_payload, safe_storage);
     394             : 
     395          13 :                         int3store(compress_buf, payload_size);
     396          13 :                         int1store(compress_buf + 3, net->packet_no);
     397          13 :                         DBG_INF_FMT("writing "MYSQLND_SZ_T_SPEC" bytes to the network", payload_size + MYSQLND_HEADER_SIZE + COMPRESSED_HEADER_SIZE);
     398          13 :                         bytes_sent = net->data->m.network_write_ex(net, compress_buf, payload_size + MYSQLND_HEADER_SIZE + COMPRESSED_HEADER_SIZE,
     399             :                                                                                                  conn_stats, error_info TSRMLS_CC);
     400          13 :                         net->compressed_envelope_packet_no++;
     401             :   #if WHEN_WE_NEED_TO_CHECK_WHETHER_COMPRESSION_WORKS_CORRECTLY
     402             :                         if (res == Z_OK) {
     403             :                                 size_t decompressed_size = left + MYSQLND_HEADER_SIZE;
     404             :                                 zend_uchar * decompressed_data = mnd_malloc(decompressed_size);
     405             :                                 int error = net->data->m.decode(decompressed_data, decompressed_size,
     406             :                                                                                   compress_buf + MYSQLND_HEADER_SIZE + COMPRESSED_HEADER_SIZE, payload_size);
     407             :                                 if (error == Z_OK) {
     408             :                                         int i;
     409             :                                         DBG_INF("success decompressing");
     410             :                                         for (i = 0 ; i < decompressed_size; i++) {
     411             :                                                 if (i && (i % 30 == 0)) {
     412             :                                                         printf("\n\t\t");
     413             :                                                 }
     414             :                                                 printf("%.2X ", (int)*((char*)&(decompressed_data[i])));
     415             :                                                 DBG_INF_FMT("%.2X ", (int)*((char*)&(decompressed_data[i])));
     416             :                                         }
     417             :                                 } else {
     418             :                                         DBG_INF("error decompressing");
     419             :                                 }
     420             :                                 mnd_free(decompressed_data);
     421             :                         }
     422             :   #endif /* WHEN_WE_NEED_TO_CHECK_WHETHER_COMPRESSION_WORKS_CORRECTLY */
     423             :                 } else
     424             : #endif /* MYSQLND_COMPRESSION_ENABLED */
     425             :                 {
     426       40281 :                         DBG_INF("no compression");
     427       40281 :                         STORE_HEADER_SIZE(safe_storage, p);
     428       40281 :                         int3store(p, to_be_sent);
     429       40281 :                         int1store(p + 3, net->packet_no);
     430       40281 :                         bytes_sent = net->data->m.network_write_ex(net, p, to_be_sent + MYSQLND_HEADER_SIZE, conn_stats, error_info TSRMLS_CC);
     431       40281 :                         RESTORE_HEADER_SIZE(p, safe_storage);
     432       40281 :                         net->compressed_envelope_packet_no++;
     433             :                 }
     434       40294 :                 net->packet_no++;
     435             : 
     436       40294 :                 p += to_be_sent;
     437       40294 :                 left -= to_be_sent;
     438       40294 :                 packets_sent++;
     439             :                 /*
     440             :                   if left is 0 then there is nothing more to send, but if the last packet was exactly 
     441             :                   with the size MYSQLND_MAX_PACKET_SIZE we need to send additional packet, which has
     442             :                   empty payload. Thus if left == 0 we check for to_be_sent being the max size. If it is
     443             :                   indeed it then loop once more, then to_be_sent will become 0, left will stay 0. Empty
     444             :                   packet will be sent and this loop will end.
     445             :                 */
     446       40294 :         } while (bytes_sent && (left > 0 || to_be_sent == MYSQLND_MAX_PACKET_SIZE));
     447             : 
     448       40294 :         DBG_INF_FMT("packet_size="MYSQLND_SZ_T_SPEC" packet_no=%u", left, net->packet_no);
     449             : 
     450       40294 :         MYSQLND_INC_CONN_STATISTIC_W_VALUE3(conn_stats,
     451             :                         STAT_BYTES_SENT, count + packets_sent * MYSQLND_HEADER_SIZE,
     452             :                         STAT_PROTOCOL_OVERHEAD_OUT, packets_sent * MYSQLND_HEADER_SIZE,
     453             :                         STAT_PACKETS_SENT, packets_sent);
     454             : 
     455       40294 :         if (compress_buf) {
     456          13 :                 mnd_efree(compress_buf);
     457             :         }
     458             : 
     459             :         /* Even for zero size payload we have to send a packet */
     460       40294 :         if (!bytes_sent) {
     461          12 :                 DBG_ERR_FMT("Can't %u send bytes", count);
     462          12 :                 SET_CLIENT_ERROR(*error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);
     463             :         }
     464       40294 :         DBG_RETURN(bytes_sent);
     465             : }
     466             : /* }}} */
     467             : 
     468             : 
     469             : #ifdef MYSQLND_COMPRESSION_ENABLED
     470             : /* {{{ php_mysqlnd_read_buffer_is_empty */
     471             : static zend_bool
     472       32200 : php_mysqlnd_read_buffer_is_empty(MYSQLND_READ_BUFFER * buffer)
     473             : {
     474       32200 :         return buffer->len? FALSE:TRUE;
     475             : }
     476             : /* }}} */
     477             : 
     478             : 
     479             : /* {{{ php_mysqlnd_read_buffer_read */
     480             : static void
     481       32200 : php_mysqlnd_read_buffer_read(MYSQLND_READ_BUFFER * buffer, size_t count, zend_uchar * dest)
     482             : {
     483       32200 :         if (buffer->len >= count) {
     484       32200 :                 memcpy(dest, buffer->data + buffer->offset, count);
     485       32200 :                 buffer->offset += count;
     486       32200 :                 buffer->len -= count;
     487             :         }
     488       32200 : }
     489             : /* }}} */
     490             : 
     491             : 
     492             : /* {{{ php_mysqlnd_read_buffer_bytes_left */
     493             : static size_t
     494       32204 : php_mysqlnd_read_buffer_bytes_left(MYSQLND_READ_BUFFER * buffer)
     495             : {
     496       32204 :         return buffer->len;
     497             : }
     498             : /* }}} */
     499             : 
     500             : 
     501             : /* {{{ php_mysqlnd_read_buffer_free */
     502             : static void
     503          14 : php_mysqlnd_read_buffer_free(MYSQLND_READ_BUFFER ** buffer TSRMLS_DC)
     504             : {
     505          14 :         DBG_ENTER("php_mysqlnd_read_buffer_free");
     506          14 :         if (*buffer) {
     507          14 :                 mnd_efree((*buffer)->data);
     508          14 :                 mnd_efree(*buffer);
     509          14 :                 *buffer = NULL;
     510             :         }
     511          14 :         DBG_VOID_RETURN;
     512             : }
     513             : /* }}} */
     514             : 
     515             : 
     516             : /* {{{ php_mysqlnd_create_read_buffer */
     517             : static MYSQLND_READ_BUFFER *
     518          14 : mysqlnd_create_read_buffer(size_t count TSRMLS_DC)
     519             : {
     520          14 :         MYSQLND_READ_BUFFER * ret = mnd_emalloc(sizeof(MYSQLND_READ_BUFFER));
     521          14 :         DBG_ENTER("mysqlnd_create_read_buffer");
     522          14 :         ret->is_empty = php_mysqlnd_read_buffer_is_empty;
     523          14 :         ret->read = php_mysqlnd_read_buffer_read;
     524          14 :         ret->bytes_left = php_mysqlnd_read_buffer_bytes_left;
     525          14 :         ret->free_buffer = php_mysqlnd_read_buffer_free;
     526          14 :         ret->data = mnd_emalloc(count);
     527          14 :         ret->size = ret->len = count;
     528          14 :         ret->offset = 0;
     529          14 :         DBG_RETURN(ret);
     530             : }
     531             : /* }}} */
     532             : 
     533             : 
     534             : /* {{{ mysqlnd_net::read_compressed_packet_from_stream_and_fill_read_buffer */
     535             : static enum_func_status
     536          14 : MYSQLND_METHOD(mysqlnd_net, read_compressed_packet_from_stream_and_fill_read_buffer)
     537             :                 (MYSQLND_NET * net, size_t net_payload_size, MYSQLND_STATS * conn_stats, MYSQLND_ERROR_INFO * error_info TSRMLS_DC)
     538             : {
     539             :         size_t decompressed_size;
     540          14 :         enum_func_status retval = PASS;
     541          14 :         zend_uchar * compressed_data = NULL;
     542             :         zend_uchar comp_header[COMPRESSED_HEADER_SIZE];
     543          14 :         DBG_ENTER("mysqlnd_net::read_compressed_packet_from_stream_and_fill_read_buffer");
     544             : 
     545             :         /* Read the compressed header */
     546          14 :         if (FAIL == net->data->m.network_read_ex(net, comp_header, COMPRESSED_HEADER_SIZE, conn_stats, error_info TSRMLS_CC)) {
     547           0 :                 DBG_RETURN(FAIL);
     548             :         }
     549          14 :         decompressed_size = uint3korr(comp_header);
     550             : 
     551             :         /* When decompressed_size is 0, then the data is not compressed, and we have wasted 3 bytes */
     552             :         /* we need to decompress the data */
     553             : 
     554          14 :         if (decompressed_size) {
     555          10 :                 compressed_data = mnd_emalloc(net_payload_size);
     556          10 :                 if (FAIL == net->data->m.network_read_ex(net, compressed_data, net_payload_size, conn_stats, error_info TSRMLS_CC)) {
     557           0 :                         retval = FAIL;
     558           0 :                         goto end;
     559             :                 }
     560          10 :                 net->uncompressed_data = mysqlnd_create_read_buffer(decompressed_size TSRMLS_CC);
     561          10 :                 retval = net->data->m.decode(net->uncompressed_data->data, decompressed_size, compressed_data, net_payload_size TSRMLS_CC);
     562          10 :                 if (FAIL == retval) {
     563           0 :                         goto end;
     564             :                 }
     565             :         } else {
     566           4 :                 DBG_INF_FMT("The server decided not to compress the data. Our job is easy. Copying %u bytes", net_payload_size);
     567           4 :                 net->uncompressed_data = mysqlnd_create_read_buffer(net_payload_size TSRMLS_CC);
     568           4 :                 if (FAIL == net->data->m.network_read_ex(net, net->uncompressed_data->data, net_payload_size, conn_stats, error_info TSRMLS_CC)) {
     569           0 :                         retval = FAIL;
     570             :                         goto end;
     571             :                 }
     572             :         }
     573             : end:
     574          14 :         if (compressed_data) {
     575          10 :                 mnd_efree(compressed_data);
     576             :         }
     577          14 :         DBG_RETURN(retval);
     578             : }
     579             : /* }}} */
     580             : #endif /* MYSQLND_COMPRESSION_ENABLED */
     581             : 
     582             : 
     583             : /* {{{ mysqlnd_net::decode */
     584             : static enum_func_status
     585          10 : MYSQLND_METHOD(mysqlnd_net, decode)(zend_uchar * uncompressed_data, const size_t uncompressed_data_len,
     586             :                                                                         const zend_uchar * const compressed_data, const size_t compressed_data_len TSRMLS_DC)
     587             : {
     588             : #ifdef MYSQLND_COMPRESSION_ENABLED
     589             :         int error;
     590          10 :         uLongf tmp_complen = uncompressed_data_len;
     591          10 :         DBG_ENTER("mysqlnd_net::decode");
     592          10 :         error = uncompress(uncompressed_data, &tmp_complen, compressed_data, compressed_data_len);
     593             : 
     594          10 :         DBG_INF_FMT("compressed data: decomp_len=%lu compressed_size="MYSQLND_SZ_T_SPEC, tmp_complen, compressed_data_len);
     595          10 :         if (error != Z_OK) {
     596           0 :                 DBG_INF_FMT("decompression NOT successful. error=%d Z_OK=%d Z_BUF_ERROR=%d Z_MEM_ERROR=%d", error, Z_OK, Z_BUF_ERROR, Z_MEM_ERROR);
     597             :         }
     598          10 :         DBG_RETURN(error == Z_OK? PASS:FAIL);
     599             : #else
     600             :         DBG_ENTER("mysqlnd_net::decode");
     601             :         DBG_RETURN(FAIL);
     602             : #endif
     603             : }
     604             : /* }}} */
     605             : 
     606             : 
     607             : /* {{{ mysqlnd_net::encode */
     608             : static enum_func_status
     609          13 : MYSQLND_METHOD(mysqlnd_net, encode)(zend_uchar * compress_buffer, size_t * compress_buffer_len,
     610             :                                                                         const zend_uchar * const uncompressed_data, const size_t uncompressed_data_len TSRMLS_DC)
     611             : {
     612             : #ifdef MYSQLND_COMPRESSION_ENABLED
     613             :         int error;
     614          13 :         uLongf tmp_complen = *compress_buffer_len;
     615          13 :         DBG_ENTER("mysqlnd_net::encode");
     616          13 :         error = compress(compress_buffer, &tmp_complen, uncompressed_data, uncompressed_data_len);
     617             : 
     618          13 :         if (error != Z_OK) {
     619          11 :                 DBG_INF_FMT("compression NOT successful. error=%d Z_OK=%d Z_BUF_ERROR=%d Z_MEM_ERROR=%d", error, Z_OK, Z_BUF_ERROR, Z_MEM_ERROR);
     620             :         } else {
     621           2 :                 *compress_buffer_len = tmp_complen;
     622           2 :                 DBG_INF_FMT("compression successful. compressed size=%lu", tmp_complen);
     623             :         }
     624             :         
     625          13 :         DBG_RETURN(error == Z_OK? PASS:FAIL);
     626             : #else
     627             :         DBG_ENTER("mysqlnd_net::encode");
     628             :         DBG_RETURN(FAIL);
     629             : #endif
     630             : }
     631             : /* }}} */
     632             : 
     633             : 
     634             : /* {{{ mysqlnd_net::receive_ex */
     635             : static enum_func_status
     636      588960 : MYSQLND_METHOD(mysqlnd_net, receive_ex)(MYSQLND_NET * const net, zend_uchar * const buffer, const size_t count, 
     637             :                                                                                 MYSQLND_STATS * const conn_stats, MYSQLND_ERROR_INFO * const error_info TSRMLS_DC)
     638             : {
     639      588960 :         size_t to_read = count;
     640      588960 :         zend_uchar * p = buffer;
     641             : 
     642      588960 :         DBG_ENTER("mysqlnd_net::receive_ex");
     643             : #ifdef MYSQLND_COMPRESSION_ENABLED
     644      588960 :         if (net->data->compressed) {
     645       32210 :                 if (net->uncompressed_data) {
     646       32200 :                         size_t to_read_from_buffer = MIN(net->uncompressed_data->bytes_left(net->uncompressed_data), to_read);
     647       32200 :                         DBG_INF_FMT("reading "MYSQLND_SZ_T_SPEC" from uncompressed_data buffer", to_read_from_buffer);
     648       32200 :                         if (to_read_from_buffer) {
     649       32200 :                                 net->uncompressed_data->read(net->uncompressed_data, to_read_from_buffer, (zend_uchar *) p);
     650       32200 :                                 p += to_read_from_buffer;
     651       32200 :                                 to_read -= to_read_from_buffer;
     652             :                         }
     653       32200 :                         DBG_INF_FMT("left "MYSQLND_SZ_T_SPEC" to read", to_read);
     654       32200 :                         if (TRUE == net->uncompressed_data->is_empty(net->uncompressed_data)) {
     655             :                                 /* Everything was consumed. This should never happen here, but for security */
     656          14 :                                 net->uncompressed_data->free_buffer(&net->uncompressed_data TSRMLS_CC);
     657             :                         }
     658             :                 }
     659       32210 :                 if (to_read) {
     660             :                         zend_uchar net_header[MYSQLND_HEADER_SIZE];
     661             :                         size_t net_payload_size;
     662             :                         zend_uchar packet_no;
     663             : 
     664          14 :                         if (FAIL == net->data->m.network_read_ex(net, net_header, MYSQLND_HEADER_SIZE, conn_stats, error_info TSRMLS_CC)) {
     665           0 :                                 DBG_RETURN(FAIL);
     666             :                         }
     667          14 :                         net_payload_size = uint3korr(net_header);
     668          14 :                         packet_no = uint1korr(net_header + 3);
     669          14 :                         if (net->compressed_envelope_packet_no != packet_no) {
     670           0 :                                 DBG_ERR_FMT("Transport level: packets out of order. Expected %u received %u. Packet size="MYSQLND_SZ_T_SPEC,
     671           0 :                                                         net->compressed_envelope_packet_no, packet_no, net_payload_size);
     672             : 
     673           0 :                                 php_error(E_WARNING, "Packets out of order. Expected %u received %u. Packet size="MYSQLND_SZ_T_SPEC,
     674           0 :                                                   net->compressed_envelope_packet_no, packet_no, net_payload_size);
     675           0 :                                 DBG_RETURN(FAIL);
     676             :                         }
     677          14 :                         net->compressed_envelope_packet_no++;
     678             : #ifdef MYSQLND_DUMP_HEADER_N_BODY
     679             :                         DBG_INF_FMT("HEADER: hwd_packet_no=%u size=%3u", packet_no, (zend_ulong) net_payload_size);
     680             : #endif
     681             :                         /* Now let's read from the wire, decompress it and fill the read buffer */
     682          14 :                         net->data->m.read_compressed_packet_from_stream_and_fill_read_buffer(net, net_payload_size, conn_stats, error_info TSRMLS_CC);
     683             : 
     684             :                         /*
     685             :                           Now a bit of recursion - read from the read buffer,
     686             :                           if the data which we have just read from the wire
     687             :                           is not enough, then the recursive call will try to
     688             :                           satisfy it until it is satisfied.
     689             :                         */
     690          14 :                         DBG_RETURN(net->data->m.receive_ex(net, p, to_read, conn_stats, error_info TSRMLS_CC));
     691             :                 }
     692       32196 :                 DBG_RETURN(PASS);
     693             :         }
     694             : #endif /* MYSQLND_COMPRESSION_ENABLED */
     695      556750 :         DBG_RETURN(net->data->m.network_read_ex(net, p, to_read, conn_stats, error_info TSRMLS_CC));
     696             : }
     697             : /* }}} */
     698             : 
     699             : 
     700             : /* {{{ mysqlnd_net::set_client_option */
     701             : static enum_func_status
     702        6081 : MYSQLND_METHOD(mysqlnd_net, set_client_option)(MYSQLND_NET * const net, enum mysqlnd_option option, const char * const value TSRMLS_DC)
     703             : {
     704        6081 :         DBG_ENTER("mysqlnd_net::set_client_option");
     705        6081 :         DBG_INF_FMT("option=%u", option);
     706        6081 :         switch (option) {
     707             :                 case MYSQLND_OPT_NET_CMD_BUFFER_SIZE:
     708        1941 :                         DBG_INF("MYSQLND_OPT_NET_CMD_BUFFER_SIZE");
     709        1941 :                         if (*(unsigned int*) value < MYSQLND_NET_CMD_BUFFER_MIN_SIZE) {
     710           0 :                                 DBG_RETURN(FAIL);
     711             :                         }
     712        1941 :                         net->cmd_buffer.length = *(unsigned int*) value;
     713        1941 :                         DBG_INF_FMT("new_length="MYSQLND_SZ_T_SPEC, net->cmd_buffer.length);
     714        1941 :                         if (!net->cmd_buffer.buffer) {
     715        1941 :                                 net->cmd_buffer.buffer = mnd_pemalloc(net->cmd_buffer.length, net->persistent);
     716             :                         } else {
     717           0 :                                 net->cmd_buffer.buffer = mnd_perealloc(net->cmd_buffer.buffer, net->cmd_buffer.length, net->persistent);
     718             :                         }
     719        1941 :                         break;
     720             :                 case MYSQLND_OPT_NET_READ_BUFFER_SIZE:
     721        1941 :                         DBG_INF("MYSQLND_OPT_NET_READ_BUFFER_SIZE");
     722        1941 :                         net->data->options.net_read_buffer_size = *(unsigned int*) value;
     723        1941 :                         DBG_INF_FMT("new_length="MYSQLND_SZ_T_SPEC, net->data->options.net_read_buffer_size);
     724        1941 :                         break;
     725             :                 case MYSQL_OPT_CONNECT_TIMEOUT:
     726         240 :                         DBG_INF("MYSQL_OPT_CONNECT_TIMEOUT");
     727         240 :                         net->data->options.timeout_connect = *(unsigned int*) value;
     728         240 :                         break;
     729             :                 case MYSQLND_OPT_SSL_KEY:
     730             :                         {
     731           3 :                                 zend_bool pers = net->persistent;
     732           3 :                                 if (net->data->options.ssl_key) {
     733           0 :                                         mnd_pefree(net->data->options.ssl_key, pers);
     734             :                                 }
     735           3 :                                 net->data->options.ssl_key = value? mnd_pestrdup(value, pers) : NULL;
     736           3 :                                 break;
     737             :                         }
     738             :                 case MYSQLND_OPT_SSL_CERT:
     739             :                         {
     740           3 :                                 zend_bool pers = net->persistent;
     741           3 :                                 if (net->data->options.ssl_cert) {
     742           0 :                                         mnd_pefree(net->data->options.ssl_cert, pers);
     743             :                                 }
     744           3 :                                 net->data->options.ssl_cert = value? mnd_pestrdup(value, pers) : NULL;
     745           3 :                                 break;
     746             :                         }
     747             :                 case MYSQLND_OPT_SSL_CA:
     748             :                         {
     749           3 :                                 zend_bool pers = net->persistent;
     750           3 :                                 if (net->data->options.ssl_ca) {
     751           0 :                                         mnd_pefree(net->data->options.ssl_ca, pers);
     752             :                                 }
     753           3 :                                 net->data->options.ssl_ca = value? mnd_pestrdup(value, pers) : NULL;
     754           3 :                                 break;
     755             :                         }
     756             :                 case MYSQLND_OPT_SSL_CAPATH:
     757             :                         {
     758           3 :                                 zend_bool pers = net->persistent;
     759           3 :                                 if (net->data->options.ssl_capath) {
     760           0 :                                         mnd_pefree(net->data->options.ssl_capath, pers);
     761             :                                 }
     762           3 :                                 net->data->options.ssl_capath = value? mnd_pestrdup(value, pers) : NULL;
     763           3 :                                 break;
     764             :                         }
     765             :                 case MYSQLND_OPT_SSL_CIPHER:
     766             :                         {
     767           3 :                                 zend_bool pers = net->persistent;
     768           3 :                                 if (net->data->options.ssl_cipher) {
     769           0 :                                         mnd_pefree(net->data->options.ssl_cipher, pers);
     770             :                                 }
     771           3 :                                 net->data->options.ssl_cipher = value? mnd_pestrdup(value, pers) : NULL;
     772           3 :                                 break;
     773             :                         }
     774             :                 case MYSQLND_OPT_SSL_PASSPHRASE:
     775             :                         {
     776           0 :                                 zend_bool pers = net->persistent;
     777           0 :                                 if (net->data->options.ssl_passphrase) {
     778           0 :                                         mnd_pefree(net->data->options.ssl_passphrase, pers);
     779             :                                 }
     780           0 :                                 net->data->options.ssl_passphrase = value? mnd_pestrdup(value, pers) : NULL;
     781           0 :                                 break;
     782             :                         }
     783             :                 case MYSQL_OPT_SSL_VERIFY_SERVER_CERT:
     784           3 :                         net->data->options.ssl_verify_peer = value? ((*(zend_bool *)value)? TRUE:FALSE): FALSE;
     785           3 :                         break;
     786             :                 case MYSQL_OPT_READ_TIMEOUT:
     787        1941 :                         net->data->options.timeout_read = *(unsigned int*) value;
     788        1941 :                         break;
     789             : #ifdef WHEN_SUPPORTED_BY_MYSQLI
     790             :                 case MYSQL_OPT_WRITE_TIMEOUT:
     791             :                         net->data->options.timeout_write = *(unsigned int*) value;
     792             :                         break;
     793             : #endif
     794             :                 case MYSQL_OPT_COMPRESS:
     795           0 :                         net->data->options.flags |= MYSQLND_NET_FLAG_USE_COMPRESSION;
     796           0 :                         break;
     797             :                 case MYSQL_SERVER_PUBLIC_KEY:
     798             :                         {
     799           0 :                                 zend_bool pers = net->persistent;
     800           0 :                                 if (net->data->options.sha256_server_public_key) {
     801           0 :                                         mnd_pefree(net->data->options.sha256_server_public_key, pers);
     802             :                                 }
     803           0 :                                 net->data->options.sha256_server_public_key = value? mnd_pestrdup(value, pers) : NULL;
     804           0 :                                 break;
     805             :                         }
     806             :                 default:
     807           0 :                         DBG_RETURN(FAIL);
     808             :         }
     809        6081 :         DBG_RETURN(PASS);
     810             : }
     811             : /* }}} */
     812             : 
     813             : /* {{{ mysqlnd_net::consume_uneaten_data */
     814             : size_t 
     815           0 : MYSQLND_METHOD(mysqlnd_net, consume_uneaten_data)(MYSQLND_NET * const net, enum php_mysqlnd_server_command cmd TSRMLS_DC)
     816             : {
     817             : #ifdef MYSQLND_DO_WIRE_CHECK_BEFORE_COMMAND
     818             :         /*
     819             :           Switch to non-blocking mode and try to consume something from
     820             :           the line, if possible, then continue. This saves us from looking for
     821             :           the actual place where out-of-order packets have been sent.
     822             :           If someone is completely sure that everything is fine, he can switch it
     823             :           off.
     824             :         */
     825             :         char tmp_buf[256];
     826             :         size_t skipped_bytes = 0;
     827             :         int opt = PHP_STREAM_OPTION_BLOCKING;
     828             :         php_stream * net_stream = net->data->get_stream(net TSRMLS_CC);
     829             :         int was_blocked = net_stream->ops->set_option(net_stream, opt, 0, NULL TSRMLS_CC);
     830             : 
     831             :         DBG_ENTER("mysqlnd_net::consume_uneaten_data");
     832             : 
     833             :         if (PHP_STREAM_OPTION_RETURN_ERR != was_blocked) {
     834             :                 /* Do a read of 1 byte */
     835             :                 int bytes_consumed;
     836             : 
     837             :                 do {
     838             :                         skipped_bytes += (bytes_consumed = php_stream_read(net_stream, tmp_buf, sizeof(tmp_buf)));
     839             :                 } while (bytes_consumed == sizeof(tmp_buf));
     840             : 
     841             :                 if (was_blocked) {
     842             :                         net_stream->ops->set_option(net_stream, opt, 1, NULL TSRMLS_CC);
     843             :                 }
     844             : 
     845             :                 if (bytes_consumed) {
     846             :                         DBG_ERR_FMT("Skipped %u bytes. Last command %s hasn't consumed all the output from the server",
     847             :                                                 bytes_consumed, mysqlnd_command_to_text[net->last_command]);
     848             :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Skipped %u bytes. Last command %s hasn't "
     849             :                                                          "consumed all the output from the server",
     850             :                                                          bytes_consumed, mysqlnd_command_to_text[net->last_command]);
     851             :                 }
     852             :         }
     853             :         net->last_command = cmd;
     854             : 
     855             :         DBG_RETURN(skipped_bytes);
     856             : #else
     857           0 :         return 0;
     858             : #endif
     859             : }
     860             : /* }}} */
     861             : 
     862             : /*
     863             :   in libmyusql, if cert and !key then key=cert
     864             : */
     865             : /* {{{ mysqlnd_net::enable_ssl */
     866             : static enum_func_status
     867           3 : MYSQLND_METHOD(mysqlnd_net, enable_ssl)(MYSQLND_NET * const net TSRMLS_DC)
     868             : {
     869             : #ifdef MYSQLND_SSL_SUPPORTED
     870           3 :         php_stream_context * context = php_stream_context_alloc(TSRMLS_C);
     871           3 :         php_stream * net_stream = net->data->m.get_stream(net TSRMLS_CC);
     872             : 
     873           3 :         DBG_ENTER("mysqlnd_net::enable_ssl");
     874           3 :         if (!context) {
     875           0 :                 DBG_RETURN(FAIL);
     876             :         }
     877             : 
     878           3 :         if (net->data->options.ssl_key) {
     879             :                 zval key_zval;
     880           2 :                 ZVAL_STRING(&key_zval, net->data->options.ssl_key);
     881           1 :                 php_stream_context_set_option(context, "ssl", "local_pk", &key_zval);
     882             :         }
     883           3 :         if (net->data->options.ssl_verify_peer) {
     884             :                 zval verify_peer_zval;
     885           0 :                 ZVAL_TRUE(&verify_peer_zval);
     886           0 :                 php_stream_context_set_option(context, "ssl", "verify_peer", &verify_peer_zval);
     887             :         }
     888           3 :         if (net->data->options.ssl_cert) {
     889             :                 zval cert_zval;
     890           2 :                 ZVAL_STRING(&cert_zval, net->data->options.ssl_cert);
     891           1 :                 php_stream_context_set_option(context, "ssl", "local_cert", &cert_zval);
     892           1 :                 if (!net->data->options.ssl_key) {
     893           0 :                         php_stream_context_set_option(context, "ssl", "local_pk", &cert_zval);
     894             :                 }
     895             :         }
     896           3 :         if (net->data->options.ssl_ca) {
     897             :                 zval cafile_zval;
     898           2 :                 ZVAL_STRING(&cafile_zval, net->data->options.ssl_ca);
     899           1 :                 php_stream_context_set_option(context, "ssl", "cafile", &cafile_zval);
     900             :         }
     901           3 :         if (net->data->options.ssl_capath) {
     902             :                 zval capath_zval;
     903           0 :                 ZVAL_STRING(&capath_zval, net->data->options.ssl_capath);
     904           0 :                 php_stream_context_set_option(context, "ssl", "cafile", &capath_zval);
     905             :         }
     906           3 :         if (net->data->options.ssl_passphrase) {
     907             :                 zval passphrase_zval;
     908           0 :                 ZVAL_STRING(&passphrase_zval, net->data->options.ssl_passphrase);
     909           0 :                 php_stream_context_set_option(context, "ssl", "passphrase", &passphrase_zval);
     910             :         }
     911           3 :         if (net->data->options.ssl_cipher) {
     912             :                 zval cipher_zval;
     913           4 :                 ZVAL_STRING(&cipher_zval, net->data->options.ssl_cipher);
     914           2 :                 php_stream_context_set_option(context, "ssl", "ciphers", &cipher_zval);
     915             :         }
     916             : #if PHP_API_VERSION >= 20131106
     917           3 :         php_stream_context_set(net_stream, context TSRMLS_CC);
     918             : #else
     919             :         php_stream_context_set(net_stream, context);
     920             : #endif
     921           3 :         if (php_stream_xport_crypto_setup(net_stream, STREAM_CRYPTO_METHOD_TLS_CLIENT, NULL TSRMLS_CC) < 0 ||
     922           0 :             php_stream_xport_crypto_enable(net_stream, 1 TSRMLS_CC) < 0)
     923             :         {
     924           3 :                 DBG_ERR("Cannot connect to MySQL by using SSL");
     925           3 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot connect to MySQL by using SSL");
     926           3 :                 DBG_RETURN(FAIL);
     927             :         }
     928           0 :         net->data->ssl = TRUE;
     929             :         /*
     930             :           get rid of the context. we are persistent and if this is a real pconn used by mysql/mysqli,
     931             :           then the context would not survive cleaning of EG(regular_list), where it is registered, as a
     932             :           resource. What happens is that after this destruction any use of the network will mean usage
     933             :           of the context, which means usage of already freed memory, bad. Actually we don't need this
     934             :           context anymore after we have enabled SSL on the connection. Thus it is very simple, we remove it.
     935             :         */
     936             : #if PHP_API_VERSION >= 20131106
     937           0 :         php_stream_context_set(net_stream, NULL TSRMLS_CC);
     938             : #else
     939             :         php_stream_context_set(net_stream, NULL);
     940             : #endif
     941             : 
     942           0 :         if (net->data->options.timeout_read) {
     943             :                 struct timeval tv;
     944           0 :                 DBG_INF_FMT("setting %u as PHP_STREAM_OPTION_READ_TIMEOUT", net->data->options.timeout_read);
     945           0 :                 tv.tv_sec = net->data->options.timeout_read;
     946           0 :                 tv.tv_usec = 0;
     947           0 :                 php_stream_set_option(net_stream, PHP_STREAM_OPTION_READ_TIMEOUT, 0, &tv);
     948             :         }
     949             : 
     950           0 :         DBG_RETURN(PASS);
     951             : #else
     952             :         DBG_ENTER("mysqlnd_net::enable_ssl");
     953             :         DBG_INF("MYSQLND_SSL_SUPPORTED is not defined");
     954             :         DBG_RETURN(PASS);
     955             : #endif
     956             : }
     957             : /* }}} */
     958             : 
     959             : 
     960             : /* {{{ mysqlnd_net::disable_ssl */
     961             : static enum_func_status
     962           0 : MYSQLND_METHOD(mysqlnd_net, disable_ssl)(MYSQLND_NET * const net TSRMLS_DC)
     963             : {
     964           0 :         DBG_ENTER("mysqlnd_net::disable_ssl");
     965           0 :         DBG_RETURN(PASS);
     966             : }
     967             : /* }}} */
     968             : 
     969             : 
     970             : /* {{{ mysqlnd_net::free_contents */
     971             : static void
     972        3851 : MYSQLND_METHOD(mysqlnd_net, free_contents)(MYSQLND_NET * net TSRMLS_DC)
     973             : {
     974        3851 :         zend_bool pers = net->persistent;
     975        3851 :         DBG_ENTER("mysqlnd_net::free_contents");
     976             : 
     977             : #ifdef MYSQLND_COMPRESSION_ENABLED
     978        3851 :         if (net->uncompressed_data) {
     979           0 :                 net->uncompressed_data->free_buffer(&net->uncompressed_data TSRMLS_CC);
     980             :         }
     981             : #endif
     982        3851 :         if (net->data->options.ssl_key) {
     983           1 :                 mnd_pefree(net->data->options.ssl_key, pers);
     984           1 :                 net->data->options.ssl_key = NULL;
     985             :         }
     986        3851 :         if (net->data->options.ssl_cert) {
     987           1 :                 mnd_pefree(net->data->options.ssl_cert, pers);
     988           1 :                 net->data->options.ssl_cert = NULL;
     989             :         }
     990        3851 :         if (net->data->options.ssl_ca) {
     991           1 :                 mnd_pefree(net->data->options.ssl_ca, pers);
     992           1 :                 net->data->options.ssl_ca = NULL;
     993             :         }
     994        3851 :         if (net->data->options.ssl_capath) {
     995           0 :                 mnd_pefree(net->data->options.ssl_capath, pers);
     996           0 :                 net->data->options.ssl_capath = NULL;
     997             :         }
     998        3851 :         if (net->data->options.ssl_cipher) {
     999           2 :                 mnd_pefree(net->data->options.ssl_cipher, pers);
    1000           2 :                 net->data->options.ssl_cipher = NULL;
    1001             :         }
    1002        3851 :         if (net->data->options.sha256_server_public_key) {
    1003           0 :                 mnd_pefree(net->data->options.sha256_server_public_key, pers);
    1004           0 :                 net->data->options.sha256_server_public_key = NULL;
    1005             :         }
    1006             : 
    1007        3851 :         DBG_VOID_RETURN;
    1008             : }
    1009             : /* }}} */
    1010             : 
    1011             : 
    1012             : /* {{{ mysqlnd_net::close_stream */
    1013             : static void
    1014        7595 : MYSQLND_METHOD(mysqlnd_net, close_stream)(MYSQLND_NET * const net, MYSQLND_STATS * const stats, MYSQLND_ERROR_INFO * const error_info TSRMLS_DC)
    1015             : {
    1016             :         php_stream * net_stream;
    1017        7595 :         DBG_ENTER("mysqlnd_net::close_stream");
    1018        7595 :         if (net && (net_stream = net->data->m.get_stream(net TSRMLS_CC))) {
    1019        1861 :                 zend_bool pers = net->persistent;
    1020        1861 :                 DBG_INF_FMT("Freeing stream. abstract=%p", net_stream->abstract);
    1021        1861 :                 if (pers) {
    1022        1136 :                         if (EG(active)) {
    1023        1087 :                                 php_stream_free(net_stream, PHP_STREAM_FREE_CLOSE_PERSISTENT | PHP_STREAM_FREE_RSRC_DTOR);
    1024             :                         } else {
    1025             :                                 /*
    1026             :                                   otherwise we will crash because the EG(persistent_list) has been freed already,
    1027             :                                   before the modules are shut down
    1028             :                                 */
    1029          49 :                                 php_stream_free(net_stream, PHP_STREAM_FREE_CLOSE | PHP_STREAM_FREE_RSRC_DTOR);
    1030             :                         }
    1031             :                 } else {
    1032         725 :                         php_stream_free(net_stream, PHP_STREAM_FREE_CLOSE);
    1033             :                 }
    1034        1861 :                 (void) net->data->m.set_stream(net, NULL TSRMLS_CC);
    1035             :         }
    1036             : 
    1037        7595 :         DBG_VOID_RETURN;
    1038             : }
    1039             : /* }}} */
    1040             : 
    1041             : 
    1042             : /* {{{ mysqlnd_net::init */
    1043             : static enum_func_status
    1044        1941 : MYSQLND_METHOD(mysqlnd_net, init)(MYSQLND_NET * const net, MYSQLND_STATS * const stats, MYSQLND_ERROR_INFO * const error_info TSRMLS_DC)
    1045             : {
    1046             :         unsigned int buf_size;
    1047        1941 :         DBG_ENTER("mysqlnd_net::init");
    1048             : 
    1049        1941 :         buf_size = MYSQLND_G(net_cmd_buffer_size); /* this is long, cast to unsigned int*/
    1050        1941 :         net->data->m.set_client_option(net, MYSQLND_OPT_NET_CMD_BUFFER_SIZE, (char *) &buf_size TSRMLS_CC);
    1051             : 
    1052        1941 :         buf_size = MYSQLND_G(net_read_buffer_size); /* this is long, cast to unsigned int*/
    1053        1941 :         net->data->m.set_client_option(net, MYSQLND_OPT_NET_READ_BUFFER_SIZE, (char *)&buf_size TSRMLS_CC);
    1054             : 
    1055        1941 :         buf_size = MYSQLND_G(net_read_timeout); /* this is long, cast to unsigned int*/
    1056        1941 :         net->data->m.set_client_option(net, MYSQL_OPT_READ_TIMEOUT, (char *)&buf_size TSRMLS_CC);
    1057             : 
    1058        1941 :         DBG_RETURN(PASS);
    1059             : }
    1060             : /* }}} */
    1061             : 
    1062             : 
    1063             : /* {{{ mysqlnd_net::dtor */
    1064             : static void
    1065        1899 : MYSQLND_METHOD(mysqlnd_net, dtor)(MYSQLND_NET * const net, MYSQLND_STATS * const stats, MYSQLND_ERROR_INFO * const error_info TSRMLS_DC)
    1066             : {
    1067        1899 :         DBG_ENTER("mysqlnd_net::dtor");
    1068        1899 :         if (net) {
    1069        1899 :                 net->data->m.free_contents(net TSRMLS_CC);
    1070        1899 :                 net->data->m.close_stream(net, stats, error_info TSRMLS_CC);
    1071             : 
    1072        1899 :                 if (net->cmd_buffer.buffer) {
    1073        1899 :                         DBG_INF("Freeing cmd buffer");
    1074        1899 :                         mnd_pefree(net->cmd_buffer.buffer, net->persistent);
    1075        1899 :                         net->cmd_buffer.buffer = NULL;
    1076             :                 }
    1077             : 
    1078        1899 :                 mnd_pefree(net->data, net->data->persistent);
    1079        1899 :                 mnd_pefree(net, net->persistent);
    1080             :         }
    1081        1899 :         DBG_VOID_RETURN;
    1082             : }
    1083             : /* }}} */
    1084             : 
    1085             : 
    1086             : /* {{{ mysqlnd_net::get_stream */
    1087             : static php_stream *
    1088      612442 : MYSQLND_METHOD(mysqlnd_net, get_stream)(const MYSQLND_NET * const net TSRMLS_DC)
    1089             : {
    1090      612442 :         DBG_ENTER("mysqlnd_net::get_stream");
    1091      612442 :         DBG_INF_FMT("%p", net? net->data->stream:NULL);
    1092      612442 :         DBG_RETURN(net? net->data->stream:NULL);
    1093             : }
    1094             : /* }}} */
    1095             : 
    1096             : 
    1097             : /* {{{ mysqlnd_net::set_stream */
    1098             : static php_stream *
    1099        3722 : MYSQLND_METHOD(mysqlnd_net, set_stream)(MYSQLND_NET * const net, php_stream * net_stream TSRMLS_DC)
    1100             : {
    1101        3722 :         php_stream * ret = NULL;
    1102        3722 :         DBG_ENTER("mysqlnd_net::set_stream");
    1103        3722 :         if (net) {
    1104        3722 :                 net->data->stream = net_stream;
    1105        3722 :                 ret = net->data->stream;
    1106             :         }
    1107        3722 :         DBG_RETURN(ret);
    1108             : }
    1109             : /* }}} */
    1110             : 
    1111             : 
    1112             : MYSQLND_CLASS_METHODS_START(mysqlnd_net)
    1113             :         MYSQLND_METHOD(mysqlnd_net, init),
    1114             :         MYSQLND_METHOD(mysqlnd_net, dtor),
    1115             :         MYSQLND_METHOD(mysqlnd_net, connect_ex),
    1116             :         MYSQLND_METHOD(mysqlnd_net, close_stream),
    1117             :         MYSQLND_METHOD(mysqlnd_net, open_pipe),
    1118             :         MYSQLND_METHOD(mysqlnd_net, open_tcp_or_unix),
    1119             :         MYSQLND_METHOD(mysqlnd_net, get_stream),
    1120             :         MYSQLND_METHOD(mysqlnd_net, set_stream),
    1121             :         MYSQLND_METHOD(mysqlnd_net, get_open_stream),
    1122             :         MYSQLND_METHOD(mysqlnd_net, post_connect_set_opt),
    1123             :         MYSQLND_METHOD(mysqlnd_net, set_client_option),
    1124             :         MYSQLND_METHOD(mysqlnd_net, decode),
    1125             :         MYSQLND_METHOD(mysqlnd_net, encode),
    1126             :         MYSQLND_METHOD(mysqlnd_net, consume_uneaten_data),
    1127             :         MYSQLND_METHOD(mysqlnd_net, free_contents),
    1128             :         MYSQLND_METHOD(mysqlnd_net, enable_ssl),
    1129             :         MYSQLND_METHOD(mysqlnd_net, disable_ssl),
    1130             :         MYSQLND_METHOD(mysqlnd_net, network_read_ex),
    1131             :         MYSQLND_METHOD(mysqlnd_net, network_write_ex),
    1132             :         MYSQLND_METHOD(mysqlnd_net, send_ex),
    1133             :         MYSQLND_METHOD(mysqlnd_net, receive_ex),
    1134             : #ifdef MYSQLND_COMPRESSION_ENABLED
    1135             :         MYSQLND_METHOD(mysqlnd_net, read_compressed_packet_from_stream_and_fill_read_buffer),
    1136             : #else
    1137             :         NULL,
    1138             : #endif
    1139             :         NULL, /* unused 1 */
    1140             :         NULL, /* unused 2 */
    1141             :         NULL, /* unused 3 */
    1142             :         NULL, /* unused 4 */
    1143             :         NULL  /* unused 5 */
    1144             : MYSQLND_CLASS_METHODS_END;
    1145             : 
    1146             : 
    1147             : /* {{{ mysqlnd_net_init */
    1148             : PHPAPI MYSQLND_NET *
    1149        1941 : mysqlnd_net_init(zend_bool persistent, MYSQLND_STATS * stats, MYSQLND_ERROR_INFO * error_info TSRMLS_DC)
    1150             : {
    1151             :         MYSQLND_NET * net;
    1152        1941 :         DBG_ENTER("mysqlnd_net_init");
    1153        1941 :         net = MYSQLND_CLASS_METHOD_TABLE_NAME(mysqlnd_object_factory).get_io_channel(persistent, stats, error_info TSRMLS_CC);
    1154        1941 :         DBG_RETURN(net);
    1155             : }
    1156             : /* }}} */
    1157             : 
    1158             : 
    1159             : /* {{{ mysqlnd_net_free */
    1160             : PHPAPI void
    1161        1899 : mysqlnd_net_free(MYSQLND_NET * const net, MYSQLND_STATS * stats, MYSQLND_ERROR_INFO * error_info TSRMLS_DC)
    1162             : {
    1163        1899 :         DBG_ENTER("mysqlnd_net_free");
    1164        1899 :         if (net) {
    1165        1899 :                 net->data->m.dtor(net, stats, error_info TSRMLS_CC);
    1166             :         }
    1167        1899 :         DBG_VOID_RETURN;
    1168             : }
    1169             : /* }}} */
    1170             : 
    1171             : 
    1172             : 
    1173             : /*
    1174             :  * Local variables:
    1175             :  * tab-width: 4
    1176             :  * c-basic-offset: 4
    1177             :  * End:
    1178             :  * vim600: noet sw=4 ts=4 fdm=marker
    1179             :  * vim<600: noet sw=4 ts=4
    1180             :  */

Generated by: LCOV version 1.10

Generated at Thu, 30 Oct 2014 07:41:33 +0000 (25 hours ago)

Copyright © 2005-2014 The PHP Group
All rights reserved.