]> granicus.if.org Git - php/commitdiff
MNDR:
authorAndrey Hristov <andrey@php.net>
Mon, 9 Nov 2015 14:53:42 +0000 (15:53 +0100)
committerAndrey Hristov <andrey@php.net>
Thu, 12 Nov 2015 15:19:16 +0000 (16:19 +0100)
- intermediate step to move MYSQLND_NET from mysqlnd_vio.c to mysqlnd_wireprotocol.c
  In following commits MYSQLND_NET's methods and data will be moved to MYSQLND_PROTOCOL

ext/mysqlnd/mysqlnd_vio.c
ext/mysqlnd/mysqlnd_wireprotocol.c

index e2c125fdfbbeb44f7d8e63c98e5c4c56b5fee45c..0aa06e21df4d539a8f668ee262492d02ea3dca3f 100644 (file)
@@ -29,9 +29,6 @@
 #include "mysqlnd_ext_plugin.h"
 #include "php_network.h"
 #include "zend_ini.h"
-#ifdef MYSQLND_COMPRESSION_ENABLED
-#include <zlib.h>
-#endif
 
 #ifndef PHP_WIN32
 #include <netinet/tcp.h>
@@ -44,7 +41,6 @@
 static int
 mysqlnd_set_sock_no_delay(php_stream * stream)
 {
-
        int socketd = ((php_netstream_data_t*)stream->abstract)->socket;
        int ret = SUCCESS;
        int flag = 1;
@@ -65,7 +61,6 @@ mysqlnd_set_sock_no_delay(php_stream * stream)
 static int
 mysqlnd_set_sock_keepalive(php_stream * stream)
 {
-
        int socketd = ((php_netstream_data_t*)stream->abstract)->socket;
        int ret = SUCCESS;
        int flag = 1;
@@ -315,18 +310,6 @@ MYSQLND_METHOD(mysqlnd_vio, get_open_stream)(MYSQLND_VIO * const vio, const MYSQ
 /* }}} */
 
 
-/* {{{ mysqlnd_net::connect */
-static enum_func_status
-MYSQLND_METHOD(mysqlnd_net, connect)(MYSQLND_NET * const net, const MYSQLND_CSTRING scheme, const zend_bool persistent,
-                                                                        MYSQLND_STATS * const conn_stats, MYSQLND_ERROR_INFO * const error_info)
-{
-       DBG_ENTER("mysqlnd_net::connect");
-       net->packet_no = net->compressed_envelope_packet_no = 0;
-       DBG_RETURN(PASS);
-}
-/* }}} */
-
-
 /* {{{ mysqlnd_vio::connect */
 static enum_func_status
 MYSQLND_METHOD(mysqlnd_vio, connect)(MYSQLND_VIO * const vio, const MYSQLND_CSTRING scheme, const zend_bool persistent,
@@ -353,407 +336,6 @@ MYSQLND_METHOD(mysqlnd_vio, connect)(MYSQLND_VIO * const vio, const MYSQLND_CSTR
 /* }}} */
 
 
-/* We assume that MYSQLND_HEADER_SIZE is 4 bytes !! */
-#define COPY_HEADER(T,A)  do { \
-               *(((char *)(T)))   = *(((char *)(A)));\
-               *(((char *)(T))+1) = *(((char *)(A))+1);\
-               *(((char *)(T))+2) = *(((char *)(A))+2);\
-               *(((char *)(T))+3) = *(((char *)(A))+3); } while (0)
-#define STORE_HEADER_SIZE(safe_storage, buffer)  COPY_HEADER((safe_storage), (buffer))
-#define RESTORE_HEADER_SIZE(buffer, safe_storage) STORE_HEADER_SIZE((safe_storage), (buffer))
-
-
-/* {{{ mysqlnd_net::send */
-/*
-  IMPORTANT : It's expected that buffer has place in the beginning for MYSQLND_HEADER_SIZE !!!!
-                         This is done for performance reasons in the caller of this function.
-                         Otherwise we will have to do send two TCP packets, or do new alloc and memcpy.
-                         Neither are quick, thus the clients of this function are obligated to do
-                         what they are asked for.
-
-  `count` is actually the length of the payload data. Thus :
-  count + MYSQLND_HEADER_SIZE = sizeof(buffer) (not the pointer but the actual buffer)
-*/
-static size_t
-MYSQLND_METHOD(mysqlnd_net, send)(MYSQLND_NET * const net, MYSQLND_VIO * const vio, zend_uchar * const buffer, const size_t count,
-                                                                 MYSQLND_STATS * const conn_stats, MYSQLND_ERROR_INFO * const error_info)
-{
-       zend_uchar safe_buf[((MYSQLND_HEADER_SIZE) + (sizeof(zend_uchar)) - 1) / (sizeof(zend_uchar))];
-       zend_uchar * safe_storage = safe_buf;
-       size_t bytes_sent, packets_sent = 1;
-       size_t left = count;
-       zend_uchar * p = (zend_uchar *) buffer;
-       zend_uchar * compress_buf = NULL;
-       size_t to_be_sent;
-
-       DBG_ENTER("mysqlnd_net::send");
-       DBG_INF_FMT("count=" MYSQLND_SZ_T_SPEC " compression=%u", count, net->data->compressed);
-
-       if (net->data->compressed == TRUE) {
-               size_t comp_buf_size = MYSQLND_HEADER_SIZE + COMPRESSED_HEADER_SIZE + MYSQLND_HEADER_SIZE + MIN(left, MYSQLND_MAX_PACKET_SIZE);
-               DBG_INF_FMT("compress_buf_size="MYSQLND_SZ_T_SPEC, comp_buf_size);
-               compress_buf = mnd_emalloc(comp_buf_size);
-       }
-
-       do {
-               to_be_sent = MIN(left, MYSQLND_MAX_PACKET_SIZE);
-               DBG_INF_FMT("to_be_sent=%u", to_be_sent);
-               DBG_INF_FMT("packets_sent=%u", packets_sent);
-               DBG_INF_FMT("compressed_envelope_packet_no=%u", net->compressed_envelope_packet_no);
-               DBG_INF_FMT("packet_no=%u", net->packet_no);
-#ifdef MYSQLND_COMPRESSION_ENABLED
-               if (net->data->compressed == TRUE) {
-                       /* here we need to compress the data and then write it, first comes the compressed header */
-                       size_t tmp_complen = to_be_sent;
-                       size_t payload_size;
-                       zend_uchar * uncompressed_payload = p; /* should include the header */
-
-                       STORE_HEADER_SIZE(safe_storage, uncompressed_payload);
-                       int3store(uncompressed_payload, to_be_sent);
-                       int1store(uncompressed_payload + 3, net->packet_no);
-                       if (PASS == net->data->m.encode((compress_buf + COMPRESSED_HEADER_SIZE + MYSQLND_HEADER_SIZE), &tmp_complen,
-                                                                          uncompressed_payload, to_be_sent + MYSQLND_HEADER_SIZE))
-                       {
-                               int3store(compress_buf + MYSQLND_HEADER_SIZE, to_be_sent + MYSQLND_HEADER_SIZE);
-                               payload_size = tmp_complen;
-                       } else {
-                               int3store(compress_buf + MYSQLND_HEADER_SIZE, 0);
-                               memcpy(compress_buf + MYSQLND_HEADER_SIZE + COMPRESSED_HEADER_SIZE, uncompressed_payload, to_be_sent + MYSQLND_HEADER_SIZE);
-                               payload_size = to_be_sent + MYSQLND_HEADER_SIZE;
-                       }
-                       RESTORE_HEADER_SIZE(uncompressed_payload, safe_storage);
-
-                       int3store(compress_buf, payload_size);
-                       int1store(compress_buf + 3, net->packet_no);
-                       DBG_INF_FMT("writing "MYSQLND_SZ_T_SPEC" bytes to the network", payload_size + MYSQLND_HEADER_SIZE + COMPRESSED_HEADER_SIZE);
-                       bytes_sent = vio->data->m.network_write(vio, compress_buf, payload_size + MYSQLND_HEADER_SIZE + COMPRESSED_HEADER_SIZE, conn_stats, error_info);
-                       net->compressed_envelope_packet_no++;
-  #if WHEN_WE_NEED_TO_CHECK_WHETHER_COMPRESSION_WORKS_CORRECTLY
-                       if (res == Z_OK) {
-                               size_t decompressed_size = left + MYSQLND_HEADER_SIZE;
-                               zend_uchar * decompressed_data = mnd_malloc(decompressed_size);
-                               int error = net->data->m.decode(decompressed_data, decompressed_size,
-                                                                                               compress_buf + MYSQLND_HEADER_SIZE + COMPRESSED_HEADER_SIZE, payload_size);
-                               if (error == Z_OK) {
-                                       int i;
-                                       DBG_INF("success decompressing");
-                                       for (i = 0 ; i < decompressed_size; i++) {
-                                               if (i && (i % 30 == 0)) {
-                                                       printf("\n\t\t");
-                                               }
-                                               printf("%.2X ", (int)*((char*)&(decompressed_data[i])));
-                                               DBG_INF_FMT("%.2X ", (int)*((char*)&(decompressed_data[i])));
-                                       }
-                               } else {
-                                       DBG_INF("error decompressing");
-                               }
-                               mnd_free(decompressed_data);
-                       }
-  #endif /* WHEN_WE_NEED_TO_CHECK_WHETHER_COMPRESSION_WORKS_CORRECTLY */
-               } else
-#endif /* MYSQLND_COMPRESSION_ENABLED */
-               {
-                       DBG_INF("no compression");
-                       STORE_HEADER_SIZE(safe_storage, p);
-                       int3store(p, to_be_sent);
-                       int1store(p + 3, net->packet_no);
-                       bytes_sent = vio->data->m.network_write(vio, p, to_be_sent + MYSQLND_HEADER_SIZE, conn_stats, error_info);
-                       RESTORE_HEADER_SIZE(p, safe_storage);
-                       net->compressed_envelope_packet_no++;
-               }
-               net->packet_no++;
-
-               p += to_be_sent;
-               left -= to_be_sent;
-               packets_sent++;
-               /*
-                 if left is 0 then there is nothing more to send, but if the last packet was exactly
-                 with the size MYSQLND_MAX_PACKET_SIZE we need to send additional packet, which has
-                 empty payload. Thus if left == 0 we check for to_be_sent being the max size. If it is
-                 indeed it then loop once more, then to_be_sent will become 0, left will stay 0. Empty
-                 packet will be sent and this loop will end.
-               */
-       } while (bytes_sent && (left > 0 || to_be_sent == MYSQLND_MAX_PACKET_SIZE));
-
-       DBG_INF_FMT("packet_size="MYSQLND_SZ_T_SPEC" packet_no=%u", left, net->packet_no);
-
-       MYSQLND_INC_CONN_STATISTIC_W_VALUE3(conn_stats,
-                       STAT_BYTES_SENT, count + packets_sent * MYSQLND_HEADER_SIZE,
-                       STAT_PROTOCOL_OVERHEAD_OUT, packets_sent * MYSQLND_HEADER_SIZE,
-                       STAT_PACKETS_SENT, packets_sent);
-
-       if (compress_buf) {
-               mnd_efree(compress_buf);
-       }
-
-       /* Even for zero size payload we have to send a packet */
-       if (!bytes_sent) {
-               DBG_ERR_FMT("Can't %u send bytes", count);
-               SET_CLIENT_ERROR(error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);
-       }
-       DBG_RETURN(bytes_sent);
-}
-/* }}} */
-
-
-#ifdef MYSQLND_COMPRESSION_ENABLED
-/* {{{ php_mysqlnd_read_buffer_is_empty */
-static zend_bool
-php_mysqlnd_read_buffer_is_empty(MYSQLND_READ_BUFFER * buffer)
-{
-       return buffer->len? FALSE:TRUE;
-}
-/* }}} */
-
-
-/* {{{ php_mysqlnd_read_buffer_read */
-static void
-php_mysqlnd_read_buffer_read(MYSQLND_READ_BUFFER * buffer, size_t count, zend_uchar * dest)
-{
-       if (buffer->len >= count) {
-               memcpy(dest, buffer->data + buffer->offset, count);
-               buffer->offset += count;
-               buffer->len -= count;
-       }
-}
-/* }}} */
-
-
-/* {{{ php_mysqlnd_read_buffer_bytes_left */
-static size_t
-php_mysqlnd_read_buffer_bytes_left(MYSQLND_READ_BUFFER * buffer)
-{
-       return buffer->len;
-}
-/* }}} */
-
-
-/* {{{ php_mysqlnd_read_buffer_free */
-static void
-php_mysqlnd_read_buffer_free(MYSQLND_READ_BUFFER ** buffer)
-{
-       DBG_ENTER("php_mysqlnd_read_buffer_free");
-       if (*buffer) {
-               mnd_efree((*buffer)->data);
-               mnd_efree(*buffer);
-               *buffer = NULL;
-       }
-       DBG_VOID_RETURN;
-}
-/* }}} */
-
-
-/* {{{ php_mysqlnd_create_read_buffer */
-static MYSQLND_READ_BUFFER *
-mysqlnd_create_read_buffer(size_t count)
-{
-       MYSQLND_READ_BUFFER * ret = mnd_emalloc(sizeof(MYSQLND_READ_BUFFER));
-       DBG_ENTER("mysqlnd_create_read_buffer");
-       ret->is_empty = php_mysqlnd_read_buffer_is_empty;
-       ret->read = php_mysqlnd_read_buffer_read;
-       ret->bytes_left = php_mysqlnd_read_buffer_bytes_left;
-       ret->free_buffer = php_mysqlnd_read_buffer_free;
-       ret->data = mnd_emalloc(count);
-       ret->size = ret->len = count;
-       ret->offset = 0;
-       DBG_RETURN(ret);
-}
-/* }}} */
-
-
-/* {{{ mysqlnd_net::read_compressed_packet_from_stream_and_fill_read_buffer */
-static enum_func_status
-MYSQLND_METHOD(mysqlnd_net, read_compressed_packet_from_stream_and_fill_read_buffer)
-               (MYSQLND_NET * net, MYSQLND_VIO * vio, size_t net_payload_size, MYSQLND_STATS * conn_stats, MYSQLND_ERROR_INFO * error_info)
-{
-       size_t decompressed_size;
-       enum_func_status retval = PASS;
-       zend_uchar * compressed_data = NULL;
-       zend_uchar comp_header[COMPRESSED_HEADER_SIZE];
-       DBG_ENTER("mysqlnd_net::read_compressed_packet_from_stream_and_fill_read_buffer");
-
-       /* Read the compressed header */
-       if (FAIL == vio->data->m.network_read(vio, comp_header, COMPRESSED_HEADER_SIZE, conn_stats, error_info)) {
-               DBG_RETURN(FAIL);
-       }
-       decompressed_size = uint3korr(comp_header);
-
-       /* When decompressed_size is 0, then the data is not compressed, and we have wasted 3 bytes */
-       /* we need to decompress the data */
-
-       if (decompressed_size) {
-               compressed_data = mnd_emalloc(net_payload_size);
-               if (FAIL == vio->data->m.network_read(vio, compressed_data, net_payload_size, conn_stats, error_info)) {
-                       retval = FAIL;
-                       goto end;
-               }
-               net->uncompressed_data = mysqlnd_create_read_buffer(decompressed_size);
-               retval = net->data->m.decode(net->uncompressed_data->data, decompressed_size, compressed_data, net_payload_size);
-               if (FAIL == retval) {
-                       goto end;
-               }
-       } else {
-               DBG_INF_FMT("The server decided not to compress the data. Our job is easy. Copying %u bytes", net_payload_size);
-               net->uncompressed_data = mysqlnd_create_read_buffer(net_payload_size);
-               if (FAIL == vio->data->m.network_read(vio, net->uncompressed_data->data, net_payload_size, conn_stats, error_info)) {
-                       retval = FAIL;
-                       goto end;
-               }
-       }
-end:
-       if (compressed_data) {
-               mnd_efree(compressed_data);
-       }
-       DBG_RETURN(retval);
-}
-/* }}} */
-#endif /* MYSQLND_COMPRESSION_ENABLED */
-
-
-/* {{{ mysqlnd_net::decode */
-static enum_func_status
-MYSQLND_METHOD(mysqlnd_net, decode)(zend_uchar * uncompressed_data, const size_t uncompressed_data_len,
-                                                                       const zend_uchar * const compressed_data, const size_t compressed_data_len)
-{
-#ifdef MYSQLND_COMPRESSION_ENABLED
-       int error;
-       uLongf tmp_complen = uncompressed_data_len;
-       DBG_ENTER("mysqlnd_net::decode");
-       error = uncompress(uncompressed_data, &tmp_complen, compressed_data, compressed_data_len);
-
-       DBG_INF_FMT("compressed data: decomp_len=%lu compressed_size="MYSQLND_SZ_T_SPEC, tmp_complen, compressed_data_len);
-       if (error != Z_OK) {
-               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);
-       }
-       DBG_RETURN(error == Z_OK? PASS:FAIL);
-#else
-       DBG_ENTER("mysqlnd_net::decode");
-       DBG_RETURN(FAIL);
-#endif
-}
-/* }}} */
-
-
-/* {{{ mysqlnd_net::encode */
-static enum_func_status
-MYSQLND_METHOD(mysqlnd_net, encode)(zend_uchar * compress_buffer, size_t * compress_buffer_len,
-                                                                       const zend_uchar * const uncompressed_data, const size_t uncompressed_data_len)
-{
-#ifdef MYSQLND_COMPRESSION_ENABLED
-       int error;
-       uLongf tmp_complen = *compress_buffer_len;
-       DBG_ENTER("mysqlnd_net::encode");
-       error = compress(compress_buffer, &tmp_complen, uncompressed_data, uncompressed_data_len);
-
-       if (error != Z_OK) {
-               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);
-       } else {
-               *compress_buffer_len = tmp_complen;
-               DBG_INF_FMT("compression successful. compressed size=%lu", tmp_complen);
-       }
-
-       DBG_RETURN(error == Z_OK? PASS:FAIL);
-#else
-       DBG_ENTER("mysqlnd_net::encode");
-       DBG_RETURN(FAIL);
-#endif
-}
-/* }}} */
-
-
-/* {{{ mysqlnd_net::receive */
-static enum_func_status
-MYSQLND_METHOD(mysqlnd_net, receive)(MYSQLND_NET * const net, MYSQLND_VIO * const vio, zend_uchar * const buffer, const size_t count,
-                                                                        MYSQLND_STATS * const conn_stats, MYSQLND_ERROR_INFO * const error_info)
-{
-       size_t to_read = count;
-       zend_uchar * p = buffer;
-
-       DBG_ENTER("mysqlnd_net::receive");
-#ifdef MYSQLND_COMPRESSION_ENABLED
-       if (net->data->compressed) {
-               if (net->uncompressed_data) {
-                       size_t to_read_from_buffer = MIN(net->uncompressed_data->bytes_left(net->uncompressed_data), to_read);
-                       DBG_INF_FMT("reading "MYSQLND_SZ_T_SPEC" from uncompressed_data buffer", to_read_from_buffer);
-                       if (to_read_from_buffer) {
-                               net->uncompressed_data->read(net->uncompressed_data, to_read_from_buffer, (zend_uchar *) p);
-                               p += to_read_from_buffer;
-                               to_read -= to_read_from_buffer;
-                       }
-                       DBG_INF_FMT("left "MYSQLND_SZ_T_SPEC" to read", to_read);
-                       if (TRUE == net->uncompressed_data->is_empty(net->uncompressed_data)) {
-                               /* Everything was consumed. This should never happen here, but for security */
-                               net->uncompressed_data->free_buffer(&net->uncompressed_data);
-                       }
-               }
-               if (to_read) {
-                       zend_uchar net_header[MYSQLND_HEADER_SIZE];
-                       size_t net_payload_size;
-                       zend_uchar packet_no;
-
-                       if (FAIL == vio->data->m.network_read(vio, net_header, MYSQLND_HEADER_SIZE, conn_stats, error_info)) {
-                               DBG_RETURN(FAIL);
-                       }
-                       net_payload_size = uint3korr(net_header);
-                       packet_no = uint1korr(net_header + 3);
-                       if (net->compressed_envelope_packet_no != packet_no) {
-                               DBG_ERR_FMT("Transport level: packets out of order. Expected %u received %u. Packet size="MYSQLND_SZ_T_SPEC,
-                                                       net->compressed_envelope_packet_no, packet_no, net_payload_size);
-
-                               php_error(E_WARNING, "Packets out of order. Expected %u received %u. Packet size="MYSQLND_SZ_T_SPEC,
-                                                 net->compressed_envelope_packet_no, packet_no, net_payload_size);
-                               DBG_RETURN(FAIL);
-                       }
-                       net->compressed_envelope_packet_no++;
-#ifdef MYSQLND_DUMP_HEADER_N_BODY
-                       DBG_INF_FMT("HEADER: hwd_packet_no=%u size=%3u", packet_no, (zend_ulong) net_payload_size);
-#endif
-                       /* Now let's read from the wire, decompress it and fill the read buffer */
-                       net->data->m.read_compressed_packet_from_stream_and_fill_read_buffer(net, vio, net_payload_size, conn_stats, error_info);
-
-                       /*
-                         Now a bit of recursion - read from the read buffer,
-                         if the data which we have just read from the wire
-                         is not enough, then the recursive call will try to
-                         satisfy it until it is satisfied.
-                       */
-                       DBG_RETURN(net->data->m.receive(net, vio, p, to_read, conn_stats, error_info));
-               }
-               DBG_RETURN(PASS);
-       }
-#endif /* MYSQLND_COMPRESSION_ENABLED */
-       DBG_RETURN(vio->data->m.network_read(vio, p, to_read, conn_stats, error_info));
-}
-/* }}} */
-
-
-/* {{{ mysqlnd_net::set_client_option */
-static enum_func_status
-MYSQLND_METHOD(mysqlnd_net, set_client_option)(MYSQLND_NET * const net, enum_mysqlnd_client_option option, const char * const value)
-{
-       DBG_ENTER("mysqlnd_net::set_client_option");
-       DBG_INF_FMT("option=%u", option);
-       switch (option) {
-               case MYSQL_OPT_COMPRESS:
-                       net->data->options.flags |= MYSQLND_NET_FLAG_USE_COMPRESSION;
-                       break;
-               case MYSQL_SERVER_PUBLIC_KEY:
-                       {
-                               zend_bool pers = net->persistent;
-                               if (net->data->options.sha256_server_public_key) {
-                                       mnd_pefree(net->data->options.sha256_server_public_key, pers);
-                               }
-                               net->data->options.sha256_server_public_key = value? mnd_pestrdup(value, pers) : NULL;
-                               break;
-                       }
-               default:
-                       DBG_RETURN(FAIL);
-       }
-       DBG_RETURN(PASS);
-}
-/* }}} */
-
-
 /* {{{ mysqlnd_vio::set_client_option */
 static enum_func_status
 MYSQLND_METHOD(mysqlnd_vio, set_client_option)(MYSQLND_VIO * const net, enum_mysqlnd_client_option option, const char * const value)
@@ -1054,28 +636,6 @@ MYSQLND_METHOD(mysqlnd_vio, disable_ssl)(MYSQLND_VIO * const vio)
 /* }}} */
 
 
-/* {{{ mysqlnd_net::free_contents */
-static void
-MYSQLND_METHOD(mysqlnd_net, free_contents)(MYSQLND_NET * net)
-{
-       zend_bool pers = net->persistent;
-       DBG_ENTER("mysqlnd_net::free_contents");
-
-#ifdef MYSQLND_COMPRESSION_ENABLED
-       if (net->uncompressed_data) {
-               net->uncompressed_data->free_buffer(&net->uncompressed_data);
-       }
-#endif
-       if (net->data->options.sha256_server_public_key) {
-               mnd_pefree(net->data->options.sha256_server_public_key, pers);
-               net->data->options.sha256_server_public_key = NULL;
-       }
-
-       DBG_VOID_RETURN;
-}
-/* }}} */
-
-
 /* {{{ mysqlnd_vio::free_contents */
 static void
 MYSQLND_METHOD(mysqlnd_vio, free_contents)(MYSQLND_VIO * net)
@@ -1139,15 +699,6 @@ MYSQLND_METHOD(mysqlnd_vio, close_stream)(MYSQLND_VIO * const net, MYSQLND_STATS
 /* }}} */
 
 
-/* {{{ mysqlnd_net::init */
-static enum_func_status
-MYSQLND_METHOD(mysqlnd_net, init)(MYSQLND_NET * const net, MYSQLND_STATS * const stats, MYSQLND_ERROR_INFO * const error_info)
-{
-       return PASS;
-}
-/* }}} */
-
-
 /* {{{ mysqlnd_vio::init */
 static enum_func_status
 MYSQLND_METHOD(mysqlnd_vio, init)(MYSQLND_VIO * const net, MYSQLND_STATS * const stats, MYSQLND_ERROR_INFO * const error_info)
@@ -1169,22 +720,6 @@ MYSQLND_METHOD(mysqlnd_vio, init)(MYSQLND_VIO * const net, MYSQLND_STATS * const
 /* }}} */
 
 
-/* {{{ mysqlnd_net::dtor */
-static void
-MYSQLND_METHOD(mysqlnd_net, dtor)(MYSQLND_NET * const net, MYSQLND_STATS * const stats, MYSQLND_ERROR_INFO * const error_info)
-{
-       DBG_ENTER("mysqlnd_net::dtor");
-       if (net) {
-               net->data->m.free_contents(net);
-
-               mnd_pefree(net->data, net->data->persistent);
-               mnd_pefree(net, net->persistent);
-       }
-       DBG_VOID_RETURN;
-}
-/* }}} */
-
-
 /* {{{ mysqlnd_vio::dtor */
 static void
 MYSQLND_METHOD(mysqlnd_vio, dtor)(MYSQLND_VIO * const vio, MYSQLND_STATS * const stats, MYSQLND_ERROR_INFO * const error_info)
@@ -1234,29 +769,6 @@ MYSQLND_METHOD(mysqlnd_vio, set_stream)(MYSQLND_VIO * const net, php_stream * ne
 /* }}} */
 
 
-MYSQLND_CLASS_METHODS_START(mysqlnd_net)
-       MYSQLND_METHOD(mysqlnd_net, init),
-       MYSQLND_METHOD(mysqlnd_net, dtor),
-       MYSQLND_METHOD(mysqlnd_net, connect),
-
-       MYSQLND_METHOD(mysqlnd_net, set_client_option),
-
-       MYSQLND_METHOD(mysqlnd_net, decode),
-       MYSQLND_METHOD(mysqlnd_net, encode),
-
-       MYSQLND_METHOD(mysqlnd_net, send),
-       MYSQLND_METHOD(mysqlnd_net, receive),
-
-#ifdef MYSQLND_COMPRESSION_ENABLED
-       MYSQLND_METHOD(mysqlnd_net, read_compressed_packet_from_stream_and_fill_read_buffer),
-#else
-       NULL,
-#endif
-
-       MYSQLND_METHOD(mysqlnd_net, free_contents),
-MYSQLND_CLASS_METHODS_END;
-
-
 MYSQLND_CLASS_METHODS_START(mysqlnd_vio)
        MYSQLND_METHOD(mysqlnd_vio, init),
        MYSQLND_METHOD(mysqlnd_vio, dtor),
@@ -1286,31 +798,6 @@ MYSQLND_CLASS_METHODS_START(mysqlnd_vio)
 MYSQLND_CLASS_METHODS_END;
 
 
-/* {{{ mysqlnd_net_init */
-PHPAPI MYSQLND_NET *
-mysqlnd_net_init(zend_bool persistent, MYSQLND_STATS * stats, MYSQLND_ERROR_INFO * error_info)
-{
-       MYSQLND_NET * net;
-       DBG_ENTER("mysqlnd_net_init");
-       net = MYSQLND_CLASS_METHOD_TABLE_NAME(mysqlnd_object_factory).get_net(persistent, stats, error_info);
-       DBG_RETURN(net);
-}
-/* }}} */
-
-
-/* {{{ mysqlnd_net_free */
-PHPAPI void
-mysqlnd_net_free(MYSQLND_NET * const net, MYSQLND_STATS * stats, MYSQLND_ERROR_INFO * error_info)
-{
-       DBG_ENTER("mysqlnd_net_free");
-       if (net) {
-               net->data->m.dtor(net, stats, error_info);
-       }
-       DBG_VOID_RETURN;
-}
-/* }}} */
-
-
 /* {{{ mysqlnd_vio_init */
 PHPAPI MYSQLND_VIO *
 mysqlnd_vio_init(zend_bool persistent, MYSQLND_STATS * stats, MYSQLND_ERROR_INFO * error_info)
index e2fd68e5d39bfb701c3f8827e0336b24b6e964fa..7199178b2c138349c16f3ef87cd705908ab353e2 100644 (file)
@@ -27,6 +27,9 @@
 #include "mysqlnd_statistics.h"
 #include "mysqlnd_debug.h"
 #include "zend_ini.h"
+#ifdef MYSQLND_COMPRESSION_ENABLED
+#include <zlib.h>
+#endif
 
 #define MYSQLND_SILENT 1
 #define MYSQLND_DUMP_HEADER_N_BODY
@@ -2933,6 +2936,515 @@ MYSQLND_METHOD(mysqlnd_protocol, send_command_handle_response)(
 
 
 
+/* {{{ mysqlnd_net::connect */
+static enum_func_status
+MYSQLND_METHOD(mysqlnd_net, connect)(MYSQLND_NET * const net, const MYSQLND_CSTRING scheme, const zend_bool persistent,
+                                                                        MYSQLND_STATS * const conn_stats, MYSQLND_ERROR_INFO * const error_info)
+{
+       DBG_ENTER("mysqlnd_net::connect");
+       net->packet_no = net->compressed_envelope_packet_no = 0;
+       DBG_RETURN(PASS);
+}
+/* }}} */
+
+
+/* We assume that MYSQLND_HEADER_SIZE is 4 bytes !! */
+#define COPY_HEADER(T,A)  do { \
+               *(((char *)(T)))   = *(((char *)(A)));\
+               *(((char *)(T))+1) = *(((char *)(A))+1);\
+               *(((char *)(T))+2) = *(((char *)(A))+2);\
+               *(((char *)(T))+3) = *(((char *)(A))+3); } while (0)
+#define STORE_HEADER_SIZE(safe_storage, buffer)  COPY_HEADER((safe_storage), (buffer))
+#define RESTORE_HEADER_SIZE(buffer, safe_storage) STORE_HEADER_SIZE((safe_storage), (buffer))
+
+
+/* {{{ mysqlnd_net::send */
+/*
+  IMPORTANT : It's expected that buffer has place in the beginning for MYSQLND_HEADER_SIZE !!!!
+                         This is done for performance reasons in the caller of this function.
+                         Otherwise we will have to do send two TCP packets, or do new alloc and memcpy.
+                         Neither are quick, thus the clients of this function are obligated to do
+                         what they are asked for.
+
+  `count` is actually the length of the payload data. Thus :
+  count + MYSQLND_HEADER_SIZE = sizeof(buffer) (not the pointer but the actual buffer)
+*/
+static size_t
+MYSQLND_METHOD(mysqlnd_net, send)(MYSQLND_NET * const net, MYSQLND_VIO * const vio, zend_uchar * const buffer, const size_t count,
+                                                                 MYSQLND_STATS * const conn_stats, MYSQLND_ERROR_INFO * const error_info)
+{
+       zend_uchar safe_buf[((MYSQLND_HEADER_SIZE) + (sizeof(zend_uchar)) - 1) / (sizeof(zend_uchar))];
+       zend_uchar * safe_storage = safe_buf;
+       size_t bytes_sent, packets_sent = 1;
+       size_t left = count;
+       zend_uchar * p = (zend_uchar *) buffer;
+       zend_uchar * compress_buf = NULL;
+       size_t to_be_sent;
+
+       DBG_ENTER("mysqlnd_net::send");
+       DBG_INF_FMT("count=" MYSQLND_SZ_T_SPEC " compression=%u", count, net->data->compressed);
+
+       if (net->data->compressed == TRUE) {
+               size_t comp_buf_size = MYSQLND_HEADER_SIZE + COMPRESSED_HEADER_SIZE + MYSQLND_HEADER_SIZE + MIN(left, MYSQLND_MAX_PACKET_SIZE);
+               DBG_INF_FMT("compress_buf_size="MYSQLND_SZ_T_SPEC, comp_buf_size);
+               compress_buf = mnd_emalloc(comp_buf_size);
+       }
+
+       do {
+               to_be_sent = MIN(left, MYSQLND_MAX_PACKET_SIZE);
+               DBG_INF_FMT("to_be_sent=%u", to_be_sent);
+               DBG_INF_FMT("packets_sent=%u", packets_sent);
+               DBG_INF_FMT("compressed_envelope_packet_no=%u", net->compressed_envelope_packet_no);
+               DBG_INF_FMT("packet_no=%u", net->packet_no);
+#ifdef MYSQLND_COMPRESSION_ENABLED
+               if (net->data->compressed == TRUE) {
+                       /* here we need to compress the data and then write it, first comes the compressed header */
+                       size_t tmp_complen = to_be_sent;
+                       size_t payload_size;
+                       zend_uchar * uncompressed_payload = p; /* should include the header */
+
+                       STORE_HEADER_SIZE(safe_storage, uncompressed_payload);
+                       int3store(uncompressed_payload, to_be_sent);
+                       int1store(uncompressed_payload + 3, net->packet_no);
+                       if (PASS == net->data->m.encode((compress_buf + COMPRESSED_HEADER_SIZE + MYSQLND_HEADER_SIZE), &tmp_complen,
+                                                                          uncompressed_payload, to_be_sent + MYSQLND_HEADER_SIZE))
+                       {
+                               int3store(compress_buf + MYSQLND_HEADER_SIZE, to_be_sent + MYSQLND_HEADER_SIZE);
+                               payload_size = tmp_complen;
+                       } else {
+                               int3store(compress_buf + MYSQLND_HEADER_SIZE, 0);
+                               memcpy(compress_buf + MYSQLND_HEADER_SIZE + COMPRESSED_HEADER_SIZE, uncompressed_payload, to_be_sent + MYSQLND_HEADER_SIZE);
+                               payload_size = to_be_sent + MYSQLND_HEADER_SIZE;
+                       }
+                       RESTORE_HEADER_SIZE(uncompressed_payload, safe_storage);
+
+                       int3store(compress_buf, payload_size);
+                       int1store(compress_buf + 3, net->packet_no);
+                       DBG_INF_FMT("writing "MYSQLND_SZ_T_SPEC" bytes to the network", payload_size + MYSQLND_HEADER_SIZE + COMPRESSED_HEADER_SIZE);
+                       bytes_sent = vio->data->m.network_write(vio, compress_buf, payload_size + MYSQLND_HEADER_SIZE + COMPRESSED_HEADER_SIZE, conn_stats, error_info);
+                       net->compressed_envelope_packet_no++;
+  #if WHEN_WE_NEED_TO_CHECK_WHETHER_COMPRESSION_WORKS_CORRECTLY
+                       if (res == Z_OK) {
+                               size_t decompressed_size = left + MYSQLND_HEADER_SIZE;
+                               zend_uchar * decompressed_data = mnd_malloc(decompressed_size);
+                               int error = net->data->m.decode(decompressed_data, decompressed_size,
+                                                                                               compress_buf + MYSQLND_HEADER_SIZE + COMPRESSED_HEADER_SIZE, payload_size);
+                               if (error == Z_OK) {
+                                       int i;
+                                       DBG_INF("success decompressing");
+                                       for (i = 0 ; i < decompressed_size; i++) {
+                                               if (i && (i % 30 == 0)) {
+                                                       printf("\n\t\t");
+                                               }
+                                               printf("%.2X ", (int)*((char*)&(decompressed_data[i])));
+                                               DBG_INF_FMT("%.2X ", (int)*((char*)&(decompressed_data[i])));
+                                       }
+                               } else {
+                                       DBG_INF("error decompressing");
+                               }
+                               mnd_free(decompressed_data);
+                       }
+  #endif /* WHEN_WE_NEED_TO_CHECK_WHETHER_COMPRESSION_WORKS_CORRECTLY */
+               } else
+#endif /* MYSQLND_COMPRESSION_ENABLED */
+               {
+                       DBG_INF("no compression");
+                       STORE_HEADER_SIZE(safe_storage, p);
+                       int3store(p, to_be_sent);
+                       int1store(p + 3, net->packet_no);
+                       bytes_sent = vio->data->m.network_write(vio, p, to_be_sent + MYSQLND_HEADER_SIZE, conn_stats, error_info);
+                       RESTORE_HEADER_SIZE(p, safe_storage);
+                       net->compressed_envelope_packet_no++;
+               }
+               net->packet_no++;
+
+               p += to_be_sent;
+               left -= to_be_sent;
+               packets_sent++;
+               /*
+                 if left is 0 then there is nothing more to send, but if the last packet was exactly
+                 with the size MYSQLND_MAX_PACKET_SIZE we need to send additional packet, which has
+                 empty payload. Thus if left == 0 we check for to_be_sent being the max size. If it is
+                 indeed it then loop once more, then to_be_sent will become 0, left will stay 0. Empty
+                 packet will be sent and this loop will end.
+               */
+       } while (bytes_sent && (left > 0 || to_be_sent == MYSQLND_MAX_PACKET_SIZE));
+
+       DBG_INF_FMT("packet_size="MYSQLND_SZ_T_SPEC" packet_no=%u", left, net->packet_no);
+
+       MYSQLND_INC_CONN_STATISTIC_W_VALUE3(conn_stats,
+                       STAT_BYTES_SENT, count + packets_sent * MYSQLND_HEADER_SIZE,
+                       STAT_PROTOCOL_OVERHEAD_OUT, packets_sent * MYSQLND_HEADER_SIZE,
+                       STAT_PACKETS_SENT, packets_sent);
+
+       if (compress_buf) {
+               mnd_efree(compress_buf);
+       }
+
+       /* Even for zero size payload we have to send a packet */
+       if (!bytes_sent) {
+               DBG_ERR_FMT("Can't %u send bytes", count);
+               SET_CLIENT_ERROR(error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);
+       }
+       DBG_RETURN(bytes_sent);
+}
+/* }}} */
+
+
+#ifdef MYSQLND_COMPRESSION_ENABLED
+/* {{{ php_mysqlnd_read_buffer_is_empty */
+static zend_bool
+php_mysqlnd_read_buffer_is_empty(MYSQLND_READ_BUFFER * buffer)
+{
+       return buffer->len? FALSE:TRUE;
+}
+/* }}} */
+
+
+/* {{{ php_mysqlnd_read_buffer_read */
+static void
+php_mysqlnd_read_buffer_read(MYSQLND_READ_BUFFER * buffer, size_t count, zend_uchar * dest)
+{
+       if (buffer->len >= count) {
+               memcpy(dest, buffer->data + buffer->offset, count);
+               buffer->offset += count;
+               buffer->len -= count;
+       }
+}
+/* }}} */
+
+
+/* {{{ php_mysqlnd_read_buffer_bytes_left */
+static size_t
+php_mysqlnd_read_buffer_bytes_left(MYSQLND_READ_BUFFER * buffer)
+{
+       return buffer->len;
+}
+/* }}} */
+
+
+/* {{{ php_mysqlnd_read_buffer_free */
+static void
+php_mysqlnd_read_buffer_free(MYSQLND_READ_BUFFER ** buffer)
+{
+       DBG_ENTER("php_mysqlnd_read_buffer_free");
+       if (*buffer) {
+               mnd_efree((*buffer)->data);
+               mnd_efree(*buffer);
+               *buffer = NULL;
+       }
+       DBG_VOID_RETURN;
+}
+/* }}} */
+
+
+/* {{{ php_mysqlnd_create_read_buffer */
+static MYSQLND_READ_BUFFER *
+mysqlnd_create_read_buffer(size_t count)
+{
+       MYSQLND_READ_BUFFER * ret = mnd_emalloc(sizeof(MYSQLND_READ_BUFFER));
+       DBG_ENTER("mysqlnd_create_read_buffer");
+       ret->is_empty = php_mysqlnd_read_buffer_is_empty;
+       ret->read = php_mysqlnd_read_buffer_read;
+       ret->bytes_left = php_mysqlnd_read_buffer_bytes_left;
+       ret->free_buffer = php_mysqlnd_read_buffer_free;
+       ret->data = mnd_emalloc(count);
+       ret->size = ret->len = count;
+       ret->offset = 0;
+       DBG_RETURN(ret);
+}
+/* }}} */
+
+
+/* {{{ mysqlnd_net::read_compressed_packet_from_stream_and_fill_read_buffer */
+static enum_func_status
+MYSQLND_METHOD(mysqlnd_net, read_compressed_packet_from_stream_and_fill_read_buffer)
+               (MYSQLND_NET * net, MYSQLND_VIO * vio, size_t net_payload_size, MYSQLND_STATS * conn_stats, MYSQLND_ERROR_INFO * error_info)
+{
+       size_t decompressed_size;
+       enum_func_status retval = PASS;
+       zend_uchar * compressed_data = NULL;
+       zend_uchar comp_header[COMPRESSED_HEADER_SIZE];
+       DBG_ENTER("mysqlnd_net::read_compressed_packet_from_stream_and_fill_read_buffer");
+
+       /* Read the compressed header */
+       if (FAIL == vio->data->m.network_read(vio, comp_header, COMPRESSED_HEADER_SIZE, conn_stats, error_info)) {
+               DBG_RETURN(FAIL);
+       }
+       decompressed_size = uint3korr(comp_header);
+
+       /* When decompressed_size is 0, then the data is not compressed, and we have wasted 3 bytes */
+       /* we need to decompress the data */
+
+       if (decompressed_size) {
+               compressed_data = mnd_emalloc(net_payload_size);
+               if (FAIL == vio->data->m.network_read(vio, compressed_data, net_payload_size, conn_stats, error_info)) {
+                       retval = FAIL;
+                       goto end;
+               }
+               net->uncompressed_data = mysqlnd_create_read_buffer(decompressed_size);
+               retval = net->data->m.decode(net->uncompressed_data->data, decompressed_size, compressed_data, net_payload_size);
+               if (FAIL == retval) {
+                       goto end;
+               }
+       } else {
+               DBG_INF_FMT("The server decided not to compress the data. Our job is easy. Copying %u bytes", net_payload_size);
+               net->uncompressed_data = mysqlnd_create_read_buffer(net_payload_size);
+               if (FAIL == vio->data->m.network_read(vio, net->uncompressed_data->data, net_payload_size, conn_stats, error_info)) {
+                       retval = FAIL;
+                       goto end;
+               }
+       }
+end:
+       if (compressed_data) {
+               mnd_efree(compressed_data);
+       }
+       DBG_RETURN(retval);
+}
+/* }}} */
+#endif /* MYSQLND_COMPRESSION_ENABLED */
+
+
+/* {{{ mysqlnd_net::decode */
+static enum_func_status
+MYSQLND_METHOD(mysqlnd_net, decode)(zend_uchar * uncompressed_data, const size_t uncompressed_data_len,
+                                                                       const zend_uchar * const compressed_data, const size_t compressed_data_len)
+{
+#ifdef MYSQLND_COMPRESSION_ENABLED
+       int error;
+       uLongf tmp_complen = uncompressed_data_len;
+       DBG_ENTER("mysqlnd_net::decode");
+       error = uncompress(uncompressed_data, &tmp_complen, compressed_data, compressed_data_len);
+
+       DBG_INF_FMT("compressed data: decomp_len=%lu compressed_size="MYSQLND_SZ_T_SPEC, tmp_complen, compressed_data_len);
+       if (error != Z_OK) {
+               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);
+       }
+       DBG_RETURN(error == Z_OK? PASS:FAIL);
+#else
+       DBG_ENTER("mysqlnd_net::decode");
+       DBG_RETURN(FAIL);
+#endif
+}
+/* }}} */
+
+
+/* {{{ mysqlnd_net::encode */
+static enum_func_status
+MYSQLND_METHOD(mysqlnd_net, encode)(zend_uchar * compress_buffer, size_t * compress_buffer_len,
+                                                                       const zend_uchar * const uncompressed_data, const size_t uncompressed_data_len)
+{
+#ifdef MYSQLND_COMPRESSION_ENABLED
+       int error;
+       uLongf tmp_complen = *compress_buffer_len;
+       DBG_ENTER("mysqlnd_net::encode");
+       error = compress(compress_buffer, &tmp_complen, uncompressed_data, uncompressed_data_len);
+
+       if (error != Z_OK) {
+               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);
+       } else {
+               *compress_buffer_len = tmp_complen;
+               DBG_INF_FMT("compression successful. compressed size=%lu", tmp_complen);
+       }
+
+       DBG_RETURN(error == Z_OK? PASS:FAIL);
+#else
+       DBG_ENTER("mysqlnd_net::encode");
+       DBG_RETURN(FAIL);
+#endif
+}
+/* }}} */
+
+
+/* {{{ mysqlnd_net::receive */
+static enum_func_status
+MYSQLND_METHOD(mysqlnd_net, receive)(MYSQLND_NET * const net, MYSQLND_VIO * const vio, zend_uchar * const buffer, const size_t count,
+                                                                        MYSQLND_STATS * const conn_stats, MYSQLND_ERROR_INFO * const error_info)
+{
+       size_t to_read = count;
+       zend_uchar * p = buffer;
+
+       DBG_ENTER("mysqlnd_net::receive");
+#ifdef MYSQLND_COMPRESSION_ENABLED
+       if (net->data->compressed) {
+               if (net->uncompressed_data) {
+                       size_t to_read_from_buffer = MIN(net->uncompressed_data->bytes_left(net->uncompressed_data), to_read);
+                       DBG_INF_FMT("reading "MYSQLND_SZ_T_SPEC" from uncompressed_data buffer", to_read_from_buffer);
+                       if (to_read_from_buffer) {
+                               net->uncompressed_data->read(net->uncompressed_data, to_read_from_buffer, (zend_uchar *) p);
+                               p += to_read_from_buffer;
+                               to_read -= to_read_from_buffer;
+                       }
+                       DBG_INF_FMT("left "MYSQLND_SZ_T_SPEC" to read", to_read);
+                       if (TRUE == net->uncompressed_data->is_empty(net->uncompressed_data)) {
+                               /* Everything was consumed. This should never happen here, but for security */
+                               net->uncompressed_data->free_buffer(&net->uncompressed_data);
+                       }
+               }
+               if (to_read) {
+                       zend_uchar net_header[MYSQLND_HEADER_SIZE];
+                       size_t net_payload_size;
+                       zend_uchar packet_no;
+
+                       if (FAIL == vio->data->m.network_read(vio, net_header, MYSQLND_HEADER_SIZE, conn_stats, error_info)) {
+                               DBG_RETURN(FAIL);
+                       }
+                       net_payload_size = uint3korr(net_header);
+                       packet_no = uint1korr(net_header + 3);
+                       if (net->compressed_envelope_packet_no != packet_no) {
+                               DBG_ERR_FMT("Transport level: packets out of order. Expected %u received %u. Packet size="MYSQLND_SZ_T_SPEC,
+                                                       net->compressed_envelope_packet_no, packet_no, net_payload_size);
+
+                               php_error(E_WARNING, "Packets out of order. Expected %u received %u. Packet size="MYSQLND_SZ_T_SPEC,
+                                                 net->compressed_envelope_packet_no, packet_no, net_payload_size);
+                               DBG_RETURN(FAIL);
+                       }
+                       net->compressed_envelope_packet_no++;
+#ifdef MYSQLND_DUMP_HEADER_N_BODY
+                       DBG_INF_FMT("HEADER: hwd_packet_no=%u size=%3u", packet_no, (zend_ulong) net_payload_size);
+#endif
+                       /* Now let's read from the wire, decompress it and fill the read buffer */
+                       net->data->m.read_compressed_packet_from_stream_and_fill_read_buffer(net, vio, net_payload_size, conn_stats, error_info);
+
+                       /*
+                         Now a bit of recursion - read from the read buffer,
+                         if the data which we have just read from the wire
+                         is not enough, then the recursive call will try to
+                         satisfy it until it is satisfied.
+                       */
+                       DBG_RETURN(net->data->m.receive(net, vio, p, to_read, conn_stats, error_info));
+               }
+               DBG_RETURN(PASS);
+       }
+#endif /* MYSQLND_COMPRESSION_ENABLED */
+       DBG_RETURN(vio->data->m.network_read(vio, p, to_read, conn_stats, error_info));
+}
+/* }}} */
+
+
+/* {{{ mysqlnd_net::set_client_option */
+static enum_func_status
+MYSQLND_METHOD(mysqlnd_net, set_client_option)(MYSQLND_NET * const net, enum_mysqlnd_client_option option, const char * const value)
+{
+       DBG_ENTER("mysqlnd_net::set_client_option");
+       DBG_INF_FMT("option=%u", option);
+       switch (option) {
+               case MYSQL_OPT_COMPRESS:
+                       net->data->options.flags |= MYSQLND_NET_FLAG_USE_COMPRESSION;
+                       break;
+               case MYSQL_SERVER_PUBLIC_KEY:
+                       {
+                               zend_bool pers = net->persistent;
+                               if (net->data->options.sha256_server_public_key) {
+                                       mnd_pefree(net->data->options.sha256_server_public_key, pers);
+                               }
+                               net->data->options.sha256_server_public_key = value? mnd_pestrdup(value, pers) : NULL;
+                               break;
+                       }
+               default:
+                       DBG_RETURN(FAIL);
+       }
+       DBG_RETURN(PASS);
+}
+/* }}} */
+
+
+/* {{{ mysqlnd_net::free_contents */
+static void
+MYSQLND_METHOD(mysqlnd_net, free_contents)(MYSQLND_NET * net)
+{
+       zend_bool pers = net->persistent;
+       DBG_ENTER("mysqlnd_net::free_contents");
+
+#ifdef MYSQLND_COMPRESSION_ENABLED
+       if (net->uncompressed_data) {
+               net->uncompressed_data->free_buffer(&net->uncompressed_data);
+       }
+#endif
+       if (net->data->options.sha256_server_public_key) {
+               mnd_pefree(net->data->options.sha256_server_public_key, pers);
+               net->data->options.sha256_server_public_key = NULL;
+       }
+
+       DBG_VOID_RETURN;
+}
+/* }}} */
+
+
+/* {{{ mysqlnd_net::init */
+static enum_func_status
+MYSQLND_METHOD(mysqlnd_net, init)(MYSQLND_NET * const net, MYSQLND_STATS * const stats, MYSQLND_ERROR_INFO * const error_info)
+{
+       return PASS;
+}
+/* }}} */
+
+
+/* {{{ mysqlnd_net::dtor */
+static void
+MYSQLND_METHOD(mysqlnd_net, dtor)(MYSQLND_NET * const net, MYSQLND_STATS * const stats, MYSQLND_ERROR_INFO * const error_info)
+{
+       DBG_ENTER("mysqlnd_net::dtor");
+       if (net) {
+               net->data->m.free_contents(net);
+
+               mnd_pefree(net->data, net->data->persistent);
+               mnd_pefree(net, net->persistent);
+       }
+       DBG_VOID_RETURN;
+}
+/* }}} */
+
+
+MYSQLND_CLASS_METHODS_START(mysqlnd_net)
+       MYSQLND_METHOD(mysqlnd_net, init),
+       MYSQLND_METHOD(mysqlnd_net, dtor),
+       MYSQLND_METHOD(mysqlnd_net, connect),
+
+       MYSQLND_METHOD(mysqlnd_net, set_client_option),
+
+       MYSQLND_METHOD(mysqlnd_net, decode),
+       MYSQLND_METHOD(mysqlnd_net, encode),
+
+       MYSQLND_METHOD(mysqlnd_net, send),
+       MYSQLND_METHOD(mysqlnd_net, receive),
+
+#ifdef MYSQLND_COMPRESSION_ENABLED
+       MYSQLND_METHOD(mysqlnd_net, read_compressed_packet_from_stream_and_fill_read_buffer),
+#else
+       NULL,
+#endif
+
+       MYSQLND_METHOD(mysqlnd_net, free_contents),
+MYSQLND_CLASS_METHODS_END;
+
+
+/* {{{ mysqlnd_net_init */
+PHPAPI MYSQLND_NET *
+mysqlnd_net_init(zend_bool persistent, MYSQLND_STATS * stats, MYSQLND_ERROR_INFO * error_info)
+{
+       MYSQLND_NET * net;
+       DBG_ENTER("mysqlnd_net_init");
+       net = MYSQLND_CLASS_METHOD_TABLE_NAME(mysqlnd_object_factory).get_net(persistent, stats, error_info);
+       DBG_RETURN(net);
+}
+/* }}} */
+
+
+/* {{{ mysqlnd_net_free */
+PHPAPI void
+mysqlnd_net_free(MYSQLND_NET * const net, MYSQLND_STATS * stats, MYSQLND_ERROR_INFO * error_info)
+{
+       DBG_ENTER("mysqlnd_net_free");
+       if (net) {
+               net->data->m.dtor(net, stats, error_info);
+       }
+       DBG_VOID_RETURN;
+}
+/* }}} */
+
+
+
 MYSQLND_CLASS_METHODS_START(mysqlnd_protocol_payload_decoder_factory)
        MYSQLND_METHOD(mysqlnd_protocol, get_greet_packet),
        MYSQLND_METHOD(mysqlnd_protocol, get_auth_packet),