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: 382 459 83.2 %
Date: 2014-04-16 Functions: 27 30 90.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Wed, 16 Apr 2014 12:47:50 +0000 (2 days ago)

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