diff options
Diffstat (limited to 'ext/mysqlnd/mysqlnd_net.c')
-rw-r--r-- | ext/mysqlnd/mysqlnd_net.c | 403 |
1 files changed, 259 insertions, 144 deletions
diff --git a/ext/mysqlnd/mysqlnd_net.c b/ext/mysqlnd/mysqlnd_net.c index b558ce3af4..405919339c 100644 --- a/ext/mysqlnd/mysqlnd_net.c +++ b/ext/mysqlnd/mysqlnd_net.c @@ -59,48 +59,88 @@ mysqlnd_set_sock_no_delay(php_stream * stream TSRMLS_DC) /* }}} */ -/* {{{ mysqlnd_net::network_read */ +/* {{{ mysqlnd_net::network_read_ex */ static enum_func_status -MYSQLND_METHOD(mysqlnd_net, network_read)(MYSQLND * conn, zend_uchar * buffer, size_t count TSRMLS_DC) +MYSQLND_METHOD(mysqlnd_net, network_read_ex)(MYSQLND_NET * const net, zend_uchar * const buffer, const size_t count, + MYSQLND_STATS * const stats, MYSQLND_ERROR_INFO * const error_info TSRMLS_DC) { enum_func_status return_value = PASS; size_t to_read = count, ret; - size_t old_chunk_size = conn->net->stream->chunk_size; - DBG_ENTER("mysqlnd_net::network_read"); + size_t old_chunk_size = net->stream->chunk_size; + zend_uchar * p = buffer; + + DBG_ENTER("mysqlnd_net::network_read_ex"); DBG_INF_FMT("count="MYSQLND_SZ_T_SPEC, count); - conn->net->stream->chunk_size = MIN(to_read, conn->net->options.net_read_buffer_size); + + net->stream->chunk_size = MIN(to_read, net->options.net_read_buffer_size); while (to_read) { - if (!(ret = php_stream_read(conn->net->stream, (char *) buffer, to_read))) { + if (!(ret = php_stream_read(net->stream, (char *) p, to_read))) { DBG_ERR_FMT("Error while reading header from socket"); return_value = FAIL; break; } - buffer += ret; + p += ret; to_read -= ret; } - MYSQLND_INC_CONN_STATISTIC_W_VALUE(conn->stats, STAT_BYTES_RECEIVED, count - to_read); - conn->net->stream->chunk_size = old_chunk_size; + MYSQLND_INC_CONN_STATISTIC_W_VALUE(stats, STAT_BYTES_RECEIVED, count - to_read); + net->stream->chunk_size = old_chunk_size; DBG_RETURN(return_value); } /* }}} */ -/* {{{ mysqlnd_net::network_write */ +/* {{{ mysqlnd_net::network_write_ex */ static size_t -MYSQLND_METHOD(mysqlnd_net, network_write)(MYSQLND * const conn, const zend_uchar * const buf, size_t count TSRMLS_DC) +MYSQLND_METHOD(mysqlnd_net, network_write_ex)(MYSQLND_NET * const net, const zend_uchar * const buffer, const size_t count, + MYSQLND_STATS * const stats, MYSQLND_ERROR_INFO * const error_info TSRMLS_DC) { size_t ret; - DBG_ENTER("mysqlnd_net::network_write"); - ret = php_stream_write(conn->net->stream, (char *)buf, count); + DBG_ENTER("mysqlnd_net::network_write_ex"); + ret = php_stream_write(net->stream, (char *)buffer, count); DBG_RETURN(ret); } /* }}} */ +/* {{{ mysqlnd_net::open_pipe */ +static enum_func_status +MYSQLND_METHOD(mysqlnd_net, open_pipe)(MYSQLND_NET * const net, const char * const scheme, const size_t scheme_len, + const zend_bool persistent, + MYSQLND_STATS * const conn_stats, MYSQLND_ERROR_INFO * const error_info TSRMLS_DC) +{ +#if PHP_API_VERSION < 20100412 + unsigned int streams_options = ENFORCE_SAFE_MODE; +#else + unsigned int streams_options = 0; +#endif + DBG_ENTER("mysqlnd_net::open_pipe"); + if (persistent) { + streams_options |= STREAM_OPEN_PERSISTENT; + } + streams_options |= IGNORE_URL; + net->stream = php_stream_open_wrapper((char*) scheme + sizeof("pipe://") - 1, "r+", streams_options, NULL); + if (!net->stream) { + SET_CLIENT_ERROR(*error_info, CR_CONNECTION_ERROR, UNKNOWN_SQLSTATE, "Unknown errror while connecting"); + DBG_RETURN(FAIL); + } + /* + Streams are not meant for C extensions! Thus we need a hack. Every connected stream will + be registered as resource (in EG(regular_list). So far, so good. However, it won't be + unregistered yntil the script ends. So, we need to take care of that. + */ + net->stream->in_free = 1; + zend_hash_index_del(&EG(regular_list), net->stream->rsrc_id); + net->stream->in_free = 0; + + DBG_RETURN(PASS); +} +/* }}} */ -/* {{{ mysqlnd_net::connect */ +/* {{{ mysqlnd_net::open_tcp_or_unix */ static enum_func_status -MYSQLND_METHOD(mysqlnd_net, connect)(MYSQLND_NET * net, const char * const scheme, size_t scheme_len, zend_bool persistent, char **errstr, int * errcode TSRMLS_DC) +MYSQLND_METHOD(mysqlnd_net, open_tcp_or_unix)(MYSQLND_NET * const net, const char * const scheme, const size_t scheme_len, + const zend_bool persistent, + MYSQLND_STATS * const conn_stats, MYSQLND_ERROR_INFO * const error_info TSRMLS_DC) { #if PHP_API_VERSION < 20100412 unsigned int streams_options = ENFORCE_SAFE_MODE; @@ -110,52 +150,39 @@ MYSQLND_METHOD(mysqlnd_net, connect)(MYSQLND_NET * net, const char * const schem unsigned int streams_flags = STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT; char * hashed_details = NULL; int hashed_details_len = 0; + char * errstr = NULL; + int errcode = 0; struct timeval tv; - DBG_ENTER("mysqlnd_net::connect"); - net->packet_no = net->compressed_envelope_packet_no = 0; + DBG_ENTER("mysqlnd_net::open_tcp_or_unix"); - if (net->stream) { - /* close before opening a new one */ - DBG_INF_FMT("Freeing stream. abstract=%p", net->stream->abstract); - if (net->persistent) { - php_stream_free(net->stream, PHP_STREAM_FREE_CLOSE_PERSISTENT | PHP_STREAM_FREE_RSRC_DTOR); - } else { - php_stream_free(net->stream, PHP_STREAM_FREE_CLOSE); - } - net->stream = NULL; + if (persistent) { + hashed_details_len = mnd_sprintf(&hashed_details, 0, "%p", net); + DBG_INF_FMT("hashed_details=%s", hashed_details); } - if (scheme_len > (sizeof("pipe://") - 1) && !memcmp(scheme, "pipe://", sizeof("pipe://") - 1)) { - if (persistent) { - streams_options |= STREAM_OPEN_PERSISTENT; - } - streams_options |= IGNORE_URL; - net->stream = php_stream_open_wrapper((char*) scheme + sizeof("pipe://") - 1, "r+", streams_options, NULL); - } else { - if (persistent) { - hashed_details_len = mnd_sprintf(&hashed_details, 0, "%p", net); - DBG_INF_FMT("hashed_details=%s", hashed_details); - } - - if (net->options.timeout_connect) { - tv.tv_sec = net->options.timeout_connect; - tv.tv_usec = 0; - } - - DBG_INF_FMT("calling php_stream_xport_create"); - net->stream = php_stream_xport_create(scheme, scheme_len, streams_options, streams_flags, - hashed_details, (net->options.timeout_connect) ? &tv : NULL, - NULL /*ctx*/, errstr, errcode); + if (net->options.timeout_connect) { + tv.tv_sec = net->options.timeout_connect; + tv.tv_usec = 0; } - if (*errstr || !net->stream) { + + DBG_INF_FMT("calling php_stream_xport_create"); + net->stream = php_stream_xport_create(scheme, scheme_len, streams_options, streams_flags, + hashed_details, (net->options.timeout_connect) ? &tv : NULL, + NULL /*ctx*/, &errstr, &errcode); + if (errstr || !net->stream) { + DBG_ERR("Error"); if (hashed_details) { mnd_sprintf_free(hashed_details); } - *errcode = CR_CONNECTION_ERROR; + errcode = CR_CONNECTION_ERROR; + SET_CLIENT_ERROR(*error_info, errcode? errcode:CR_CONNECTION_ERROR, UNKNOWN_SQLSTATE, errstr); + if (errstr) { + /* no mnd_ since we don't allocate it */ + efree(errstr); + } DBG_RETURN(FAIL); } - if (hashed_details) { /* If persistent, the streams register it in EG(persistent_list). @@ -180,20 +207,30 @@ MYSQLND_METHOD(mysqlnd_net, connect)(MYSQLND_NET * net, const char * const schem #endif mnd_sprintf_free(hashed_details); } + /* Streams are not meant for C extensions! Thus we need a hack. Every connected stream will be registered as resource (in EG(regular_list). So far, so good. However, it won't be - unregistered till the script ends. So, we need to take care of that. + unregistered yntil the script ends. So, we need to take care of that. */ net->stream->in_free = 1; zend_hash_index_del(&EG(regular_list), net->stream->rsrc_id); net->stream->in_free = 0; - if (!net->options.timeout_read) { - /* should always happen because read_timeout cannot be set via API */ - net->options.timeout_read = (unsigned int) MYSQLND_G(net_read_timeout); - } + DBG_RETURN(PASS); +} +/* }}} */ + + +/* {{{ mysqlnd_net::connect_ex */ +static void +MYSQLND_METHOD(mysqlnd_net, post_connect_set_opt)(MYSQLND_NET * const net, + const char * const scheme, const size_t scheme_len, + MYSQLND_STATS * const conn_stats, MYSQLND_ERROR_INFO * const error_info TSRMLS_DC) +{ + DBG_ENTER("mysqlnd_net::post_connect_set_opt"); if (net->options.timeout_read) { + struct timeval tv; DBG_INF_FMT("setting %u as PHP_STREAM_OPTION_READ_TIMEOUT", net->options.timeout_read); tv.tv_sec = net->options.timeout_read; tv.tv_usec = 0; @@ -205,13 +242,33 @@ MYSQLND_METHOD(mysqlnd_net, connect)(MYSQLND_NET * net, const char * const schem mysqlnd_set_sock_no_delay(net->stream TSRMLS_CC); } - { - unsigned int buf_size = MYSQLND_G(net_read_buffer_size); /* this is long, cast to unsigned int*/ - net->m.set_client_option(net, MYSQLND_OPT_NET_READ_BUFFER_SIZE, (char *)&buf_size TSRMLS_CC); - } + DBG_VOID_RETURN; +} +/* }}} */ - DBG_RETURN(PASS); +/* {{{ mysqlnd_net::connect_ex */ +static enum_func_status +MYSQLND_METHOD(mysqlnd_net, connect_ex)(MYSQLND_NET * const net, const char * const scheme, const size_t scheme_len, + const zend_bool persistent, + MYSQLND_STATS * const conn_stats, MYSQLND_ERROR_INFO * const error_info TSRMLS_DC) +{ + enum_func_status ret = FAIL; + func_mysqlnd_net__open_stream open_stream = NULL; + DBG_ENTER("mysqlnd_net::connect_ex"); + + net->packet_no = net->compressed_envelope_packet_no = 0; + + net->m.close_stream(net, conn_stats, error_info TSRMLS_CC); + + open_stream = (scheme_len > (sizeof("pipe://") - 1) && !memcmp(scheme, "pipe://", sizeof("pipe://") - 1))? net->m.open_pipe: + net->m.open_tcp_or_unix; + + if (PASS == (ret = open_stream(net, scheme, scheme_len, persistent, conn_stats, error_info TSRMLS_CC))) { + net->m.post_connect_set_opt(net, scheme, scheme_len, conn_stats, error_info TSRMLS_CC); + } + + DBG_RETURN(ret); } /* }}} */ @@ -225,34 +282,32 @@ MYSQLND_METHOD(mysqlnd_net, connect)(MYSQLND_NET * net, const char * const schem #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 */ + +/* {{{ mysqlnd_net::send_ex */ /* - IMPORTANT : It's expected that buf has place in the beginning for MYSQLND_HEADER_SIZE !!!! + 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(buf) (not the pointer but the actual buffer) + count + MYSQLND_HEADER_SIZE = sizeof(buffer) (not the pointer but the actual buffer) */ -size_t -MYSQLND_METHOD(mysqlnd_net, send)(MYSQLND * const conn, zend_uchar * const buf, size_t count TSRMLS_DC) +static size_t +MYSQLND_METHOD(mysqlnd_net, send_ex)(MYSQLND_NET * const net, zend_uchar * const buffer, const size_t count, + MYSQLND_STATS * const conn_stats, MYSQLND_ERROR_INFO * const error_info TSRMLS_DC) { zend_uchar safe_buf[((MYSQLND_HEADER_SIZE) + (sizeof(zend_uchar)) - 1) / (sizeof(zend_uchar))]; - zend_uchar *safe_storage = safe_buf; - MYSQLND_NET *net = conn->net; - size_t old_chunk_size = net->stream->chunk_size; - size_t ret, packets_sent = 1; + zend_uchar * safe_storage = safe_buf; + size_t bytes_sent, packets_sent = 1; size_t left = count; - zend_uchar *p = (zend_uchar *) buf; + zend_uchar * p = (zend_uchar *) buffer; zend_uchar * compress_buf = NULL; size_t to_be_sent; - DBG_ENTER("mysqlnd_net::send"); - DBG_INF_FMT("conn=%llu count=" MYSQLND_SZ_T_SPEC " compression=%u", conn->thread_id, count, net->compressed); - - net->stream->chunk_size = MYSQLND_MAX_PACKET_SIZE; + DBG_ENTER("mysqlnd_net::send_ex"); + DBG_INF_FMT("count=" MYSQLND_SZ_T_SPEC " compression=%u", count, net->compressed); if (net->compressed == TRUE) { size_t comp_buf_size = MYSQLND_HEADER_SIZE + COMPRESSED_HEADER_SIZE + MYSQLND_HEADER_SIZE + MIN(left, MYSQLND_MAX_PACKET_SIZE); @@ -287,7 +342,8 @@ MYSQLND_METHOD(mysqlnd_net, send)(MYSQLND * const conn, zend_uchar * const buf, 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); - ret = conn->net->m.network_write(conn, compress_buf, payload_size + MYSQLND_HEADER_SIZE + COMPRESSED_HEADER_SIZE TSRMLS_CC); + bytes_sent = net->m.network_write_ex(net, compress_buf, payload_size + MYSQLND_HEADER_SIZE + COMPRESSED_HEADER_SIZE, + conn_stats, error_info TSRMLS_CC); net->compressed_envelope_packet_no++; #if WHEN_WE_NEED_TO_CHECK_WHETHER_COMPRESSION_WORKS_CORRECTLY if (res == Z_OK) { @@ -318,7 +374,7 @@ MYSQLND_METHOD(mysqlnd_net, send)(MYSQLND * const conn, zend_uchar * const buf, STORE_HEADER_SIZE(safe_storage, p); int3store(p, to_be_sent); int1store(p + 3, net->packet_no); - ret = conn->net->m.network_write(conn, p, to_be_sent + MYSQLND_HEADER_SIZE TSRMLS_CC); + bytes_sent = net->m.network_write_ex(net, p, to_be_sent + MYSQLND_HEADER_SIZE, conn_stats, error_info TSRMLS_CC); RESTORE_HEADER_SIZE(p, safe_storage); net->compressed_envelope_packet_no++; } @@ -334,26 +390,25 @@ MYSQLND_METHOD(mysqlnd_net, send)(MYSQLND * const conn, zend_uchar * const buf, 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 (ret && (left > 0 || to_be_sent == MYSQLND_MAX_PACKET_SIZE)); + } 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); - /* Even for zero size payload we have to send a packet */ - if (!ret) { - DBG_ERR_FMT("Can't %u send bytes", count); - conn->state = CONN_QUIT_SENT; - SET_CLIENT_ERROR(conn->error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone); - } - MYSQLND_INC_CONN_STATISTIC_W_VALUE3(conn->stats, + 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); - net->stream->chunk_size = old_chunk_size; if (compress_buf) { mnd_efree(compress_buf); } - DBG_RETURN(ret); + + /* 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); } /* }}} */ @@ -423,19 +478,19 @@ mysqlnd_create_read_buffer(size_t count TSRMLS_DC) /* }}} */ -/* {{{ mysqlnd_read_compressed_packet_from_stream_and_fill_read_buffer */ +/* {{{ mysqlnd_net::read_compressed_packet_from_stream_and_fill_read_buffer */ static enum_func_status -mysqlnd_read_compressed_packet_from_stream_and_fill_read_buffer(MYSQLND * conn, size_t net_payload_size TSRMLS_DC) +MYSQLND_METHOD(mysqlnd_net, read_compressed_packet_from_stream_and_fill_read_buffer) + (MYSQLND_NET * net, size_t net_payload_size, MYSQLND_STATS * conn_stats, MYSQLND_ERROR_INFO * error_info TSRMLS_DC) { - MYSQLND_NET * net = conn->net; size_t decompressed_size; enum_func_status ret = PASS; zend_uchar * compressed_data = NULL; zend_uchar comp_header[COMPRESSED_HEADER_SIZE]; - DBG_ENTER("mysqlnd_read_compressed_packet_from_stream_and_fill_read_buffer"); + DBG_ENTER("mysqlnd_net::read_compressed_packet_from_stream_and_fill_read_buffe"); /* Read the compressed header */ - if (FAIL == conn->net->m.network_read(conn, comp_header, COMPRESSED_HEADER_SIZE TSRMLS_CC)) { + if (FAIL == net->m.network_read_ex(net, comp_header, COMPRESSED_HEADER_SIZE, conn_stats, error_info TSRMLS_CC)) { DBG_RETURN(FAIL); } decompressed_size = uint3korr(comp_header); @@ -445,7 +500,7 @@ mysqlnd_read_compressed_packet_from_stream_and_fill_read_buffer(MYSQLND * conn, if (decompressed_size) { compressed_data = mnd_emalloc(net_payload_size); - if (FAIL == conn->net->m.network_read(conn, compressed_data, net_payload_size TSRMLS_CC)) { + if (FAIL == net->m.network_read_ex(net, compressed_data, net_payload_size, conn_stats, error_info TSRMLS_CC)) { ret = FAIL; goto end; } @@ -457,7 +512,7 @@ mysqlnd_read_compressed_packet_from_stream_and_fill_read_buffer(MYSQLND * conn, } 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 TSRMLS_CC); - if (FAIL == conn->net->m.network_read(conn, net->uncompressed_data->data, net_payload_size TSRMLS_CC)) { + if (FAIL == net->m.network_read_ex(net, net->uncompressed_data->data, net_payload_size, conn_stats, error_info TSRMLS_CC)) { ret = FAIL; goto end; } @@ -474,8 +529,8 @@ end: /* {{{ mysqlnd_net::decode */ static enum_func_status -MYSQLND_METHOD(mysqlnd_net, decode)(zend_uchar * uncompressed_data, size_t uncompressed_data_len, - const zend_uchar * const compressed_data, size_t compressed_data_len TSRMLS_DC) +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 TSRMLS_DC) { #ifdef MYSQLND_COMPRESSION_ENABLED int error; @@ -499,7 +554,7 @@ MYSQLND_METHOD(mysqlnd_net, decode)(zend_uchar * uncompressed_data, size_t uncom /* {{{ 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, size_t uncompressed_data_len TSRMLS_DC) + const zend_uchar * const uncompressed_data, const size_t uncompressed_data_len TSRMLS_DC) { #ifdef MYSQLND_COMPRESSION_ENABLED int error; @@ -523,15 +578,15 @@ MYSQLND_METHOD(mysqlnd_net, encode)(zend_uchar * compress_buffer, size_t * compr /* }}} */ -/* {{{ mysqlnd_net::receive */ +/* {{{ mysqlnd_net::receive_ex */ static enum_func_status -MYSQLND_METHOD(mysqlnd_net, receive)(MYSQLND * conn, zend_uchar * buffer, size_t count TSRMLS_DC) +MYSQLND_METHOD(mysqlnd_net, receive_ex)(MYSQLND_NET * const net, zend_uchar * const buffer, const size_t count, + MYSQLND_STATS * const conn_stats, MYSQLND_ERROR_INFO * const error_info TSRMLS_DC) { size_t to_read = count; zend_uchar * p = buffer; - MYSQLND_NET * net = conn->net; - DBG_ENTER("mysqlnd_net::receive"); + DBG_ENTER("mysqlnd_net::receive_ex"); #ifdef MYSQLND_COMPRESSION_ENABLED if (net->compressed) { if (net->uncompressed_data) { @@ -553,7 +608,7 @@ MYSQLND_METHOD(mysqlnd_net, receive)(MYSQLND * conn, zend_uchar * buffer, size_t size_t net_payload_size; zend_uchar packet_no; - if (FAIL == net->m.network_read(conn, net_header, MYSQLND_HEADER_SIZE TSRMLS_CC)) { + if (FAIL == net->m.network_read_ex(net, net_header, MYSQLND_HEADER_SIZE, conn_stats, error_info TSRMLS_CC)) { DBG_RETURN(FAIL); } net_payload_size = uint3korr(net_header); @@ -571,7 +626,7 @@ MYSQLND_METHOD(mysqlnd_net, receive)(MYSQLND * conn, zend_uchar * buffer, size_t DBG_INF_FMT("HEADER: hwd_packet_no=%u size=%3u", packet_no, (unsigned long) net_payload_size); #endif /* Now let's read from the wire, decompress it and fill the read buffer */ - mysqlnd_read_compressed_packet_from_stream_and_fill_read_buffer(conn, net_payload_size TSRMLS_CC); + net->m.read_compressed_packet_from_stream_and_fill_read_buffer(net, net_payload_size, conn_stats, error_info TSRMLS_CC); /* Now a bit of recursion - read from the read buffer, @@ -579,12 +634,12 @@ MYSQLND_METHOD(mysqlnd_net, receive)(MYSQLND * conn, zend_uchar * buffer, size_t is not enough, then the recursive call will try to satisfy it until it is satisfied. */ - DBG_RETURN(net->m.receive(conn, p, to_read TSRMLS_CC)); + DBG_RETURN(net->m.receive_ex(net, p, to_read, conn_stats, error_info TSRMLS_CC)); } DBG_RETURN(PASS); } #endif /* MYSQLND_COMPRESSION_ENABLED */ - DBG_RETURN(net->m.network_read(conn, p, to_read TSRMLS_CC)); + DBG_RETURN(net->m.network_read_ex(net, p, to_read, conn_stats, error_info TSRMLS_CC)); } /* }}} */ @@ -675,10 +730,10 @@ MYSQLND_METHOD(mysqlnd_net, set_client_option)(MYSQLND_NET * const net, enum mys case MYSQL_OPT_SSL_VERIFY_SERVER_CERT: net->options.ssl_verify_peer = value? ((*(zend_bool *)value)? TRUE:FALSE): FALSE; break; -#ifdef WHEN_SUPPORTED_BY_MYSQLI case MYSQL_OPT_READ_TIMEOUT: net->options.timeout_read = *(unsigned int*) value; break; +#ifdef WHEN_SUPPORTED_BY_MYSQLI case MYSQL_OPT_WRITE_TIMEOUT: net->options.timeout_write = *(unsigned int*) value; break; @@ -837,7 +892,7 @@ MYSQLND_METHOD(mysqlnd_net, disable_ssl)(MYSQLND_NET * const net TSRMLS_DC) /* }}} */ -/* {{{ mysqlnd_net::set_client_option */ +/* {{{ mysqlnd_net::free_contents */ static void MYSQLND_METHOD(mysqlnd_net, free_contents)(MYSQLND_NET * net TSRMLS_DC) { @@ -874,26 +929,112 @@ MYSQLND_METHOD(mysqlnd_net, free_contents)(MYSQLND_NET * net TSRMLS_DC) } /* }}} */ + +/* {{{ mysqlnd_net::close_stream */ +static void +MYSQLND_METHOD(mysqlnd_net, close_stream)(MYSQLND_NET * const net, MYSQLND_STATS * const stats, MYSQLND_ERROR_INFO * const error_info TSRMLS_DC) +{ + DBG_ENTER("mysqlnd_net::close_stream"); + if (net && net->stream) { + zend_bool pers = net->persistent; + DBG_INF_FMT("Freeing stream. abstract=%p", net->stream->abstract); + if (pers) { + if (EG(active)) { + php_stream_free(net->stream, PHP_STREAM_FREE_CLOSE_PERSISTENT | PHP_STREAM_FREE_RSRC_DTOR); + } else { + /* + otherwise we will crash because the EG(persistent_list) has been freed already, + before the modules are shut down + */ + php_stream_free(net->stream, PHP_STREAM_FREE_CLOSE | PHP_STREAM_FREE_RSRC_DTOR); + } + } else { + php_stream_free(net->stream, PHP_STREAM_FREE_CLOSE); + } + net->stream = 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 TSRMLS_DC) +{ + unsigned int buf_size; + DBG_ENTER("mysqlnd_net::init"); + + buf_size = MYSQLND_G(net_cmd_buffer_size); /* this is long, cast to unsigned int*/ + net->m.set_client_option(net, MYSQLND_OPT_NET_CMD_BUFFER_SIZE, (char *) &buf_size TSRMLS_CC); + + buf_size = MYSQLND_G(net_read_buffer_size); /* this is long, cast to unsigned int*/ + net->m.set_client_option(net, MYSQLND_OPT_NET_READ_BUFFER_SIZE, (char *)&buf_size TSRMLS_CC); + + buf_size = MYSQLND_G(net_read_timeout); /* this is long, cast to unsigned int*/ + net->m.set_client_option(net, MYSQL_OPT_READ_TIMEOUT, (char *)&buf_size TSRMLS_CC); + + DBG_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 TSRMLS_DC) +{ + DBG_ENTER("mysqlnd_net::dtor"); + if (net) { + zend_bool pers = net->persistent; + + net->m.free_contents(net TSRMLS_CC); + net->m.close_stream(net, stats, error_info TSRMLS_CC); + if (net->cmd_buffer.buffer) { + DBG_INF("Freeing cmd buffer"); + mnd_pefree(net->cmd_buffer.buffer, pers); + net->cmd_buffer.buffer = NULL; + } + mnd_pefree(net, pers); + } + DBG_VOID_RETURN; +} +/* }}} */ + + static MYSQLND_CLASS_METHODS_START(mysqlnd_net) - MYSQLND_METHOD(mysqlnd_net, connect), - MYSQLND_METHOD(mysqlnd_net, send), - MYSQLND_METHOD(mysqlnd_net, receive), + MYSQLND_METHOD(mysqlnd_net, init), + MYSQLND_METHOD(mysqlnd_net, dtor), + MYSQLND_METHOD(mysqlnd_net, connect_ex), + MYSQLND_METHOD(mysqlnd_net, close_stream), + MYSQLND_METHOD(mysqlnd_net, open_pipe), + MYSQLND_METHOD(mysqlnd_net, open_tcp_or_unix), + NULL, /* unused 1 */ + NULL, /* unused 2 */ + MYSQLND_METHOD(mysqlnd_net, post_connect_set_opt), MYSQLND_METHOD(mysqlnd_net, set_client_option), - MYSQLND_METHOD(mysqlnd_net, network_read), - MYSQLND_METHOD(mysqlnd_net, network_write), MYSQLND_METHOD(mysqlnd_net, decode), MYSQLND_METHOD(mysqlnd_net, encode), MYSQLND_METHOD(mysqlnd_net, consume_uneaten_data), MYSQLND_METHOD(mysqlnd_net, free_contents), MYSQLND_METHOD(mysqlnd_net, enable_ssl), - MYSQLND_METHOD(mysqlnd_net, disable_ssl) + MYSQLND_METHOD(mysqlnd_net, disable_ssl), + MYSQLND_METHOD(mysqlnd_net, network_read_ex), + MYSQLND_METHOD(mysqlnd_net, network_write_ex), + MYSQLND_METHOD(mysqlnd_net, send_ex), + MYSQLND_METHOD(mysqlnd_net, receive_ex), +#ifdef MYSQLND_COMPRESSION_ENABLED + MYSQLND_METHOD(mysqlnd_net, read_compressed_packet_from_stream_and_fill_read_buffer) +#else + NULL +#endif MYSQLND_CLASS_METHODS_END; /* {{{ mysqlnd_net_init */ PHPAPI MYSQLND_NET * -mysqlnd_net_init(zend_bool persistent TSRMLS_DC) +mysqlnd_net_init(zend_bool persistent, MYSQLND_STATS * stats, MYSQLND_ERROR_INFO * error_info TSRMLS_DC) { size_t alloc_size = sizeof(MYSQLND_NET) + mysqlnd_plugin_count() * sizeof(void *); MYSQLND_NET * net = mnd_pecalloc(1, alloc_size, persistent); @@ -904,9 +1045,9 @@ mysqlnd_net_init(zend_bool persistent TSRMLS_DC) net->persistent = persistent; net->m = mysqlnd_mysqlnd_net_methods; - { - unsigned int buf_size = MYSQLND_G(net_cmd_buffer_size); /* this is long, cast to unsigned int*/ - net->m.set_client_option(net, MYSQLND_OPT_NET_CMD_BUFFER_SIZE, (char *) &buf_size TSRMLS_CC); + if (PASS != net->m.init(net, stats, error_info TSRMLS_CC)) { + net->m.dtor(net, stats, error_info TSRMLS_CC); + net = NULL; } } DBG_RETURN(net); @@ -916,37 +1057,11 @@ mysqlnd_net_init(zend_bool persistent TSRMLS_DC) /* {{{ mysqlnd_net_free */ PHPAPI void -mysqlnd_net_free(MYSQLND_NET * const net TSRMLS_DC) +mysqlnd_net_free(MYSQLND_NET * const net, MYSQLND_STATS * stats, MYSQLND_ERROR_INFO * error_info TSRMLS_DC) { DBG_ENTER("mysqlnd_net_free"); - if (net) { - zend_bool pers = net->persistent; - - net->m.free_contents(net TSRMLS_CC); - if (net->cmd_buffer.buffer) { - DBG_INF("Freeing cmd buffer"); - mnd_pefree(net->cmd_buffer.buffer, pers); - net->cmd_buffer.buffer = NULL; - } - if (net->stream) { - DBG_INF_FMT("Freeing stream. abstract=%p", net->stream->abstract); - if (pers) { - if (EG(active)) { - php_stream_free(net->stream, PHP_STREAM_FREE_CLOSE_PERSISTENT | PHP_STREAM_FREE_RSRC_DTOR); - } else { - /* - otherwise we will crash because the EG(persistent_list) has been freed already, - before the modules are shut down - */ - php_stream_free(net->stream, PHP_STREAM_FREE_CLOSE | PHP_STREAM_FREE_RSRC_DTOR); - } - } else { - php_stream_free(net->stream, PHP_STREAM_FREE_CLOSE); - } - net->stream = NULL; - } - mnd_pefree(net, pers); + net->m.dtor(net, stats, error_info TSRMLS_CC); } DBG_VOID_RETURN; } |