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

Generated by: LCOV version 1.10

Generated at Mon, 04 Aug 2014 15:49:07 +0000 (27 days ago)

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