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

Generated by: LCOV version 1.10

Generated at Sun, 17 Aug 2014 15:21:54 +0000 (5 days ago)

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