Annotation of embedaddon/php/ext/mysqlnd/mysqlnd_net.c, revision 1.1.1.5

1.1       misho       1: /*
                      2:   +----------------------------------------------------------------------+
                      3:   | PHP Version 5                                                        |
                      4:   +----------------------------------------------------------------------+
1.1.1.5 ! misho       5:   | Copyright (c) 2006-2014 The PHP Group                                |
1.1       misho       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:   +----------------------------------------------------------------------+
1.1.1.2   misho      15:   | Authors: Andrey Hristov <andrey@mysql.com>                           |
1.1       misho      16:   |          Ulf Wendel <uwendel@mysql.com>                              |
1.1.1.2   misho      17:   |          Georg Richter <georg@mysql.com>                             |
1.1       misho      18:   +----------------------------------------------------------------------+
                     19: */
1.1.1.2   misho      20: 
                     21: /* $Id: mysqlnd_ps.c 316906 2011-09-17 10:24:18Z pajoye $ */
1.1       misho      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"
1.1.1.2   misho      29: #include "mysqlnd_ext_plugin.h"
1.1       misho      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: mysqlnd_set_sock_no_delay(php_stream * stream TSRMLS_DC)
                     46: {
                     47: 
                     48:        int socketd = ((php_netstream_data_t*)stream->abstract)->socket;
                     49:        int ret = SUCCESS;
                     50:        int flag = 1;
                     51:        int result = setsockopt(socketd, IPPROTO_TCP,  TCP_NODELAY, (char *) &flag, sizeof(int));
                     52: 
                     53:        DBG_ENTER("mysqlnd_set_sock_no_delay");
                     54: 
                     55:        if (result == -1) {
                     56:                ret = FAILURE;
                     57:        }
                     58: 
                     59:        DBG_RETURN(ret);
                     60: }
                     61: /* }}} */
                     62: 
                     63: 
1.1.1.2   misho      64: /* {{{ mysqlnd_net::network_read_ex */
1.1       misho      65: static enum_func_status
1.1.1.2   misho      66: 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)
1.1       misho      68: {
                     69:        enum_func_status return_value = PASS;
                     70:        size_t to_read = count, ret;
1.1.1.2   misho      71:        size_t old_chunk_size = net->stream->chunk_size;
                     72:        zend_uchar * p = buffer;
                     73: 
                     74:        DBG_ENTER("mysqlnd_net::network_read_ex");
                     75:        DBG_INF_FMT("count="MYSQLND_SZ_T_SPEC, count);
                     76: 
                     77:        net->stream->chunk_size = MIN(to_read, net->options.net_read_buffer_size);
1.1       misho      78:        while (to_read) {
1.1.1.2   misho      79:                if (!(ret = php_stream_read(net->stream, (char *) p, to_read))) {
1.1       misho      80:                        DBG_ERR_FMT("Error while reading header from socket");
                     81:                        return_value = FAIL;
                     82:                        break;
                     83:                }
1.1.1.2   misho      84:                p += ret;
1.1       misho      85:                to_read -= ret;
                     86:        }
1.1.1.2   misho      87:        MYSQLND_INC_CONN_STATISTIC_W_VALUE(stats, STAT_BYTES_RECEIVED, count - to_read);
                     88:        net->stream->chunk_size = old_chunk_size;
1.1       misho      89:        DBG_RETURN(return_value);
                     90: }
                     91: /* }}} */
                     92: 
                     93: 
1.1.1.2   misho      94: /* {{{ mysqlnd_net::network_write_ex */
1.1       misho      95: static size_t
1.1.1.2   misho      96: 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)
1.1       misho      98: {
                     99:        size_t ret;
1.1.1.2   misho     100:        DBG_ENTER("mysqlnd_net::network_write_ex");
                    101:        ret = php_stream_write(net->stream, (char *)buffer, count);
1.1       misho     102:        DBG_RETURN(ret);
                    103: }
                    104: /* }}} */
                    105: 
1.1.1.2   misho     106: /* {{{ mysqlnd_net::open_pipe */
                    107: static enum_func_status
                    108: 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:        unsigned int streams_options = 0;
                    116: #endif
                    117:        DBG_ENTER("mysqlnd_net::open_pipe");
                    118:        if (persistent) {
                    119:                streams_options |= STREAM_OPEN_PERSISTENT;
                    120:        }
                    121:        streams_options |= IGNORE_URL;
                    122:        net->stream = php_stream_open_wrapper((char*) scheme + sizeof("pipe://") - 1, "r+", streams_options, NULL);
                    123:        if (!net->stream) {
                    124:                SET_CLIENT_ERROR(*error_info, CR_CONNECTION_ERROR, UNKNOWN_SQLSTATE, "Unknown errror while connecting");
                    125:                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:        net->stream->in_free = 1;
                    133:        zend_hash_index_del(&EG(regular_list), net->stream->rsrc_id);
                    134:        net->stream->in_free = 0;
                    135: 
                    136:        DBG_RETURN(PASS);
                    137: }
                    138: /* }}} */
1.1       misho     139: 
                    140: 
1.1.1.2   misho     141: /* {{{ mysqlnd_net::open_tcp_or_unix */
1.1       misho     142: static enum_func_status
1.1.1.2   misho     143: 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)
1.1       misho     146: {
                    147: #if PHP_API_VERSION < 20100412
                    148:        unsigned int streams_options = ENFORCE_SAFE_MODE;
                    149: #else
                    150:        unsigned int streams_options = 0;
                    151: #endif
                    152:        unsigned int streams_flags = STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT;
                    153:        char * hashed_details = NULL;
                    154:        int hashed_details_len = 0;
1.1.1.2   misho     155:        char * errstr = NULL;
                    156:        int errcode = 0;
1.1       misho     157:        struct timeval tv;
1.1.1.2   misho     158: 
                    159:        DBG_ENTER("mysqlnd_net::open_tcp_or_unix");
1.1       misho     160: 
                    161:        if (persistent) {
1.1.1.2   misho     162:                hashed_details_len = mnd_sprintf(&hashed_details, 0, "%p", net);
1.1       misho     163:                DBG_INF_FMT("hashed_details=%s", hashed_details);
                    164:        }
                    165: 
                    166:        if (net->options.timeout_connect) {
                    167:                tv.tv_sec = net->options.timeout_connect;
                    168:                tv.tv_usec = 0;
                    169:        }
                    170: 
                    171:        DBG_INF_FMT("calling php_stream_xport_create");
                    172:        net->stream = php_stream_xport_create(scheme, scheme_len, streams_options, streams_flags,
                    173:                                                                                  hashed_details, (net->options.timeout_connect) ? &tv : NULL,
1.1.1.2   misho     174:                                                                                  NULL /*ctx*/, &errstr, &errcode);
                    175:        if (errstr || !net->stream) {
                    176:                DBG_ERR("Error");
1.1       misho     177:                if (hashed_details) {
1.1.1.2   misho     178:                        mnd_sprintf_free(hashed_details);
                    179:                }
                    180:                errcode = CR_CONNECTION_ERROR;
                    181:                SET_CLIENT_ERROR(*error_info, errcode? errcode:CR_CONNECTION_ERROR, UNKNOWN_SQLSTATE, errstr);
                    182:                if (errstr) {
                    183:                        /* no mnd_ since we don't allocate it */
                    184:                        efree(errstr);
1.1       misho     185:                }
                    186:                DBG_RETURN(FAIL);
                    187:        }
                    188:        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:                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:                        net->stream->in_free = 1;
                    203:                        zend_hash_del(&EG(persistent_list), hashed_details, hashed_details_len + 1);
                    204:                        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
1.1.1.2   misho     210:                mnd_sprintf_free(hashed_details);
1.1       misho     211:        }
1.1.1.2   misho     212: 
1.1       misho     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
1.1.1.2   misho     216:          unregistered yntil the script ends. So, we need to take care of that.
1.1       misho     217:        */
                    218:        net->stream->in_free = 1;
                    219:        zend_hash_index_del(&EG(regular_list), net->stream->rsrc_id);
                    220:        net->stream->in_free = 0;
                    221: 
1.1.1.2   misho     222:        DBG_RETURN(PASS);
                    223: }
                    224: /* }}} */
                    225: 
                    226: 
                    227: /* {{{ mysqlnd_net::connect_ex */
                    228: static void
                    229: 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:        DBG_ENTER("mysqlnd_net::post_connect_set_opt");
1.1       misho     234:        if (net->options.timeout_read) {
1.1.1.2   misho     235:                struct timeval tv;
1.1       misho     236:                DBG_INF_FMT("setting %u as PHP_STREAM_OPTION_READ_TIMEOUT", net->options.timeout_read);
                    237:                tv.tv_sec = net->options.timeout_read;
                    238:                tv.tv_usec = 0;
                    239:                php_stream_set_option(net->stream, PHP_STREAM_OPTION_READ_TIMEOUT, 0, &tv);
                    240:        }
                    241: 
                    242:        if (!memcmp(scheme, "tcp://", sizeof("tcp://") - 1)) {
                    243:                /* TCP -> Set TCP_NODELAY */
                    244:                mysqlnd_set_sock_no_delay(net->stream TSRMLS_CC);
                    245:        }
                    246: 
1.1.1.2   misho     247:        DBG_VOID_RETURN;
                    248: }
                    249: /* }}} */
1.1       misho     250: 
                    251: 
1.1.1.2   misho     252: /* {{{ mysqlnd_net::connect_ex */
                    253: static enum_func_status
                    254: 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:        enum_func_status ret = FAIL;
                    259:        func_mysqlnd_net__open_stream open_stream = NULL;
                    260:        DBG_ENTER("mysqlnd_net::connect_ex");
                    261: 
                    262:        net->packet_no = net->compressed_envelope_packet_no = 0;
                    263: 
                    264:        net->m.close_stream(net, conn_stats, error_info TSRMLS_CC);
                    265: 
                    266:        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:        if (PASS == (ret = open_stream(net, scheme, scheme_len, persistent, conn_stats, error_info TSRMLS_CC))) {
                    270:                net->m.post_connect_set_opt(net, scheme, scheme_len, conn_stats, error_info TSRMLS_CC);
                    271:        }
                    272: 
                    273:        DBG_RETURN(ret);
1.1       misho     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: 
1.1.1.2   misho     287: 
                    288: /* {{{ mysqlnd_net::send_ex */
1.1       misho     289: /*
1.1.1.2   misho     290:   IMPORTANT : It's expected that buffer has place in the beginning for MYSQLND_HEADER_SIZE !!!!
1.1       misho     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 :
1.1.1.2   misho     297:   count + MYSQLND_HEADER_SIZE = sizeof(buffer) (not the pointer but the actual buffer)
1.1       misho     298: */
1.1.1.2   misho     299: static size_t
                    300: 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)
1.1       misho     302: {
                    303:        zend_uchar safe_buf[((MYSQLND_HEADER_SIZE) + (sizeof(zend_uchar)) - 1) / (sizeof(zend_uchar))];
1.1.1.2   misho     304:        zend_uchar * safe_storage = safe_buf;
                    305:        size_t bytes_sent, packets_sent = 1;
1.1       misho     306:        size_t left = count;
1.1.1.2   misho     307:        zend_uchar * p = (zend_uchar *) buffer;
1.1       misho     308:        zend_uchar * compress_buf = NULL;
                    309:        size_t to_be_sent;
                    310: 
1.1.1.2   misho     311:        DBG_ENTER("mysqlnd_net::send_ex");
                    312:        DBG_INF_FMT("count=" MYSQLND_SZ_T_SPEC " compression=%u", count, net->compressed);
1.1       misho     313: 
                    314:        if (net->compressed == TRUE) {
                    315:                size_t comp_buf_size = MYSQLND_HEADER_SIZE + COMPRESSED_HEADER_SIZE + MYSQLND_HEADER_SIZE + MIN(left, MYSQLND_MAX_PACKET_SIZE);
                    316:                DBG_INF_FMT("compress_buf_size="MYSQLND_SZ_T_SPEC, comp_buf_size);
                    317:                compress_buf = mnd_emalloc(comp_buf_size);
                    318:        }
                    319: 
                    320:        do {
                    321:                to_be_sent = MIN(left, MYSQLND_MAX_PACKET_SIZE);
                    322: #ifdef MYSQLND_COMPRESSION_ENABLED
                    323:                if (net->compressed == TRUE) {
                    324:                        /* here we need to compress the data and then write it, first comes the compressed header */
                    325:                        size_t tmp_complen = to_be_sent;
                    326:                        size_t payload_size;
                    327:                        zend_uchar * uncompressed_payload = p; /* should include the header */
                    328: 
                    329:                        STORE_HEADER_SIZE(safe_storage, uncompressed_payload);
                    330:                        int3store(uncompressed_payload, to_be_sent);
                    331:                        int1store(uncompressed_payload + 3, net->packet_no);
                    332:                        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:                                int3store(compress_buf + MYSQLND_HEADER_SIZE, to_be_sent + MYSQLND_HEADER_SIZE);
                    336:                                payload_size = tmp_complen;
                    337:                        } else {
                    338:                                int3store(compress_buf + MYSQLND_HEADER_SIZE, 0);
                    339:                                memcpy(compress_buf + MYSQLND_HEADER_SIZE + COMPRESSED_HEADER_SIZE, uncompressed_payload, to_be_sent + MYSQLND_HEADER_SIZE);
                    340:                                payload_size = to_be_sent + MYSQLND_HEADER_SIZE;
                    341:                        }
                    342:                        RESTORE_HEADER_SIZE(uncompressed_payload, safe_storage);
                    343: 
                    344:                        int3store(compress_buf, payload_size);
                    345:                        int1store(compress_buf + 3, net->packet_no);
                    346:                        DBG_INF_FMT("writing "MYSQLND_SZ_T_SPEC" bytes to the network", payload_size + MYSQLND_HEADER_SIZE + COMPRESSED_HEADER_SIZE);
1.1.1.2   misho     347:                        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);
1.1       misho     349:                        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:                        DBG_INF("no compression");
                    376:                        STORE_HEADER_SIZE(safe_storage, p);
                    377:                        int3store(p, to_be_sent);
                    378:                        int1store(p + 3, net->packet_no);
1.1.1.2   misho     379:                        bytes_sent = net->m.network_write_ex(net, p, to_be_sent + MYSQLND_HEADER_SIZE, conn_stats, error_info TSRMLS_CC);
1.1       misho     380:                        RESTORE_HEADER_SIZE(p, safe_storage);
                    381:                        net->compressed_envelope_packet_no++;
                    382:                }
                    383:                net->packet_no++;
                    384: 
                    385:                p += to_be_sent;
                    386:                left -= to_be_sent;
                    387:                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:                */
1.1.1.2   misho     395:        } while (bytes_sent && (left > 0 || to_be_sent == MYSQLND_MAX_PACKET_SIZE));
1.1       misho     396: 
                    397:        DBG_INF_FMT("packet_size="MYSQLND_SZ_T_SPEC" packet_no=%u", left, net->packet_no);
                    398: 
1.1.1.2   misho     399:        MYSQLND_INC_CONN_STATISTIC_W_VALUE3(conn_stats,
1.1       misho     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:        if (compress_buf) {
                    405:                mnd_efree(compress_buf);
                    406:        }
1.1.1.2   misho     407: 
                    408:        /* Even for zero size payload we have to send a packet */
                    409:        if (!bytes_sent) {
                    410:                DBG_ERR_FMT("Can't %u send bytes", count);
                    411:                SET_CLIENT_ERROR(*error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);
                    412:        }
                    413:        DBG_RETURN(bytes_sent);
1.1       misho     414: }
                    415: /* }}} */
                    416: 
                    417: 
                    418: #ifdef MYSQLND_COMPRESSION_ENABLED
                    419: /* {{{ php_mysqlnd_read_buffer_is_empty */
                    420: static zend_bool
                    421: php_mysqlnd_read_buffer_is_empty(MYSQLND_READ_BUFFER * buffer)
                    422: {
                    423:        return buffer->len? FALSE:TRUE;
                    424: }
                    425: /* }}} */
                    426: 
                    427: 
                    428: /* {{{ php_mysqlnd_read_buffer_read */
                    429: static void
                    430: php_mysqlnd_read_buffer_read(MYSQLND_READ_BUFFER * buffer, size_t count, zend_uchar * dest)
                    431: {
                    432:        if (buffer->len >= count) {
                    433:                memcpy(dest, buffer->data + buffer->offset, count);
                    434:                buffer->offset += count;
                    435:                buffer->len -= count;
                    436:        }
                    437: }
                    438: /* }}} */
                    439: 
                    440: 
                    441: /* {{{ php_mysqlnd_read_buffer_bytes_left */
                    442: static size_t
                    443: php_mysqlnd_read_buffer_bytes_left(MYSQLND_READ_BUFFER * buffer)
                    444: {
                    445:        return buffer->len;
                    446: }
                    447: /* }}} */
                    448: 
                    449: 
                    450: /* {{{ php_mysqlnd_read_buffer_free */
                    451: static void
                    452: php_mysqlnd_read_buffer_free(MYSQLND_READ_BUFFER ** buffer TSRMLS_DC)
                    453: {
                    454:        DBG_ENTER("php_mysqlnd_read_buffer_free");
                    455:        if (*buffer) {
                    456:                mnd_efree((*buffer)->data);
                    457:                mnd_efree(*buffer);
                    458:                *buffer = NULL;
                    459:        }
                    460:        DBG_VOID_RETURN;
                    461: }
                    462: /* }}} */
                    463: 
                    464: 
                    465: /* {{{ php_mysqlnd_create_read_buffer */
                    466: static MYSQLND_READ_BUFFER *
                    467: mysqlnd_create_read_buffer(size_t count TSRMLS_DC)
                    468: {
                    469:        MYSQLND_READ_BUFFER * ret = mnd_emalloc(sizeof(MYSQLND_READ_BUFFER));
                    470:        DBG_ENTER("mysqlnd_create_read_buffer");
                    471:        ret->is_empty = php_mysqlnd_read_buffer_is_empty;
                    472:        ret->read = php_mysqlnd_read_buffer_read;
                    473:        ret->bytes_left = php_mysqlnd_read_buffer_bytes_left;
                    474:        ret->free_buffer = php_mysqlnd_read_buffer_free;
                    475:        ret->data = mnd_emalloc(count);
                    476:        ret->size = ret->len = count;
                    477:        ret->offset = 0;
                    478:        DBG_RETURN(ret);
                    479: }
                    480: /* }}} */
                    481: 
                    482: 
1.1.1.2   misho     483: /* {{{ mysqlnd_net::read_compressed_packet_from_stream_and_fill_read_buffer */
1.1       misho     484: static enum_func_status
1.1.1.2   misho     485: 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)
1.1       misho     487: {
                    488:        size_t decompressed_size;
                    489:        enum_func_status ret = PASS;
                    490:        zend_uchar * compressed_data = NULL;
                    491:        zend_uchar comp_header[COMPRESSED_HEADER_SIZE];
1.1.1.2   misho     492:        DBG_ENTER("mysqlnd_net::read_compressed_packet_from_stream_and_fill_read_buffe");
1.1       misho     493: 
                    494:        /* Read the compressed header */
1.1.1.2   misho     495:        if (FAIL == net->m.network_read_ex(net, comp_header, COMPRESSED_HEADER_SIZE, conn_stats, error_info TSRMLS_CC)) {
1.1       misho     496:                DBG_RETURN(FAIL);
                    497:        }
                    498:        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:        if (decompressed_size) {
                    504:                compressed_data = mnd_emalloc(net_payload_size);
1.1.1.2   misho     505:                if (FAIL == net->m.network_read_ex(net, compressed_data, net_payload_size, conn_stats, error_info TSRMLS_CC)) {
1.1       misho     506:                        ret = FAIL;
                    507:                        goto end;
                    508:                }
                    509:                net->uncompressed_data = mysqlnd_create_read_buffer(decompressed_size TSRMLS_CC);
                    510:                ret = net->m.decode(net->uncompressed_data->data, decompressed_size, compressed_data, net_payload_size TSRMLS_CC);
                    511:                if (ret == FAIL) {
                    512:                        goto end;
                    513:                }
                    514:        } else {
                    515:                DBG_INF_FMT("The server decided not to compress the data. Our job is easy. Copying %u bytes", net_payload_size);
                    516:                net->uncompressed_data = mysqlnd_create_read_buffer(net_payload_size TSRMLS_CC);
1.1.1.2   misho     517:                if (FAIL == net->m.network_read_ex(net, net->uncompressed_data->data, net_payload_size, conn_stats, error_info TSRMLS_CC)) {
1.1       misho     518:                        ret = FAIL;
                    519:                        goto end;
                    520:                }
                    521:        }
                    522: end:
                    523:        if (compressed_data) {
                    524:                mnd_efree(compressed_data);
                    525:        }
                    526:        DBG_RETURN(ret);
                    527: }
                    528: /* }}} */
                    529: #endif /* MYSQLND_COMPRESSION_ENABLED */
                    530: 
                    531: 
                    532: /* {{{ mysqlnd_net::decode */
                    533: static enum_func_status
1.1.1.2   misho     534: 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)
1.1       misho     536: {
                    537: #ifdef MYSQLND_COMPRESSION_ENABLED
                    538:        int error;
                    539:        uLongf tmp_complen = uncompressed_data_len;
                    540:        DBG_ENTER("mysqlnd_net::decode");
                    541:        error = uncompress(uncompressed_data, &tmp_complen, compressed_data, compressed_data_len);
                    542: 
                    543:        DBG_INF_FMT("compressed data: decomp_len=%lu compressed_size="MYSQLND_SZ_T_SPEC, tmp_complen, compressed_data_len);
                    544:        if (error != Z_OK) {
                    545:                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:        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: MYSQLND_METHOD(mysqlnd_net, encode)(zend_uchar * compress_buffer, size_t * compress_buffer_len,
1.1.1.2   misho     559:                                                                        const zend_uchar * const uncompressed_data, const size_t uncompressed_data_len TSRMLS_DC)
1.1       misho     560: {
                    561: #ifdef MYSQLND_COMPRESSION_ENABLED
                    562:        int error;
                    563:        uLongf tmp_complen = *compress_buffer_len;
                    564:        DBG_ENTER("mysqlnd_net::encode");
                    565:        error = compress(compress_buffer, &tmp_complen, uncompressed_data, uncompressed_data_len);
                    566: 
                    567:        if (error != Z_OK) {
                    568:                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:                *compress_buffer_len = tmp_complen;
                    571:                DBG_INF_FMT("compression successful. compressed size=%lu", tmp_complen);
                    572:        }
                    573:        
                    574:        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: 
1.1.1.2   misho     583: /* {{{ mysqlnd_net::receive_ex */
1.1       misho     584: static enum_func_status
1.1.1.2   misho     585: 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)
1.1       misho     587: {
                    588:        size_t to_read = count;
                    589:        zend_uchar * p = buffer;
                    590: 
1.1.1.2   misho     591:        DBG_ENTER("mysqlnd_net::receive_ex");
1.1       misho     592: #ifdef MYSQLND_COMPRESSION_ENABLED
                    593:        if (net->compressed) {
                    594:                if (net->uncompressed_data) {
                    595:                        size_t to_read_from_buffer = MIN(net->uncompressed_data->bytes_left(net->uncompressed_data), to_read);
                    596:                        DBG_INF_FMT("reading %u from uncompressed_data buffer", to_read_from_buffer);
                    597:                        if (to_read_from_buffer) {
                    598:                                net->uncompressed_data->read(net->uncompressed_data, to_read_from_buffer, (zend_uchar *) p);
                    599:                                p += to_read_from_buffer;
                    600:                                to_read -= to_read_from_buffer;
                    601:                        }
                    602:                        DBG_INF_FMT("left %u to read", to_read);
                    603:                        if (TRUE == net->uncompressed_data->is_empty(net->uncompressed_data)) {
                    604:                                /* Everything was consumed. This should never happen here, but for security */
                    605:                                net->uncompressed_data->free_buffer(&net->uncompressed_data TSRMLS_CC);
                    606:                        }
                    607:                }
                    608:                if (to_read) {
                    609:                        zend_uchar net_header[MYSQLND_HEADER_SIZE];
                    610:                        size_t net_payload_size;
                    611:                        zend_uchar packet_no;
                    612: 
1.1.1.2   misho     613:                        if (FAIL == net->m.network_read_ex(net, net_header, MYSQLND_HEADER_SIZE, conn_stats, error_info TSRMLS_CC)) {
1.1       misho     614:                                DBG_RETURN(FAIL);
                    615:                        }
                    616:                        net_payload_size = uint3korr(net_header);
                    617:                        packet_no = uint1korr(net_header + 3);
                    618:                        if (net->compressed_envelope_packet_no != packet_no) {
                    619:                                DBG_ERR_FMT("Transport level: packets out of order. Expected %u received %u. Packet size="MYSQLND_SZ_T_SPEC,
                    620:                                                        net->compressed_envelope_packet_no, packet_no, net_payload_size);
                    621: 
                    622:                                php_error(E_WARNING, "Packets out of order. Expected %u received %u. Packet size="MYSQLND_SZ_T_SPEC,
                    623:                                                  net->compressed_envelope_packet_no, packet_no, net_payload_size);
                    624:                                DBG_RETURN(FAIL);
                    625:                        }
                    626:                        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 */
1.1.1.2   misho     631:                        net->m.read_compressed_packet_from_stream_and_fill_read_buffer(net, net_payload_size, conn_stats, error_info TSRMLS_CC);
1.1       misho     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:                        */
1.1.1.2   misho     639:                        DBG_RETURN(net->m.receive_ex(net, p, to_read, conn_stats, error_info TSRMLS_CC));
1.1       misho     640:                }
                    641:                DBG_RETURN(PASS);
                    642:        }
                    643: #endif /* MYSQLND_COMPRESSION_ENABLED */
1.1.1.2   misho     644:        DBG_RETURN(net->m.network_read_ex(net, p, to_read, conn_stats, error_info TSRMLS_CC));
1.1       misho     645: }
                    646: /* }}} */
                    647: 
                    648: 
                    649: /* {{{ mysqlnd_net::set_client_option */
                    650: static enum_func_status
                    651: MYSQLND_METHOD(mysqlnd_net, set_client_option)(MYSQLND_NET * const net, enum mysqlnd_option option, const char * const value TSRMLS_DC)
                    652: {
                    653:        DBG_ENTER("mysqlnd_net::set_client_option");
                    654:        DBG_INF_FMT("option=%u", option);
                    655:        switch (option) {
                    656:                case MYSQLND_OPT_NET_CMD_BUFFER_SIZE:
                    657:                        DBG_INF("MYSQLND_OPT_NET_CMD_BUFFER_SIZE");
                    658:                        if (*(unsigned int*) value < MYSQLND_NET_CMD_BUFFER_MIN_SIZE) {
                    659:                                DBG_RETURN(FAIL);
                    660:                        }
                    661:                        net->cmd_buffer.length = *(unsigned int*) value;
                    662:                        DBG_INF_FMT("new_length=%u", net->cmd_buffer.length);
                    663:                        if (!net->cmd_buffer.buffer) {
                    664:                                net->cmd_buffer.buffer = mnd_pemalloc(net->cmd_buffer.length, net->persistent);
                    665:                        } else {
                    666:                                net->cmd_buffer.buffer = mnd_perealloc(net->cmd_buffer.buffer, net->cmd_buffer.length, net->persistent);
                    667:                        }
                    668:                        break;
                    669:                case MYSQLND_OPT_NET_READ_BUFFER_SIZE:
                    670:                        DBG_INF("MYSQLND_OPT_NET_READ_BUFFER_SIZE");
                    671:                        net->options.net_read_buffer_size = *(unsigned int*) value;
                    672:                        DBG_INF_FMT("new_length=%u", net->options.net_read_buffer_size);
                    673:                        break;
                    674:                case MYSQL_OPT_CONNECT_TIMEOUT:
                    675:                        DBG_INF("MYSQL_OPT_CONNECT_TIMEOUT");
                    676:                        net->options.timeout_connect = *(unsigned int*) value;
                    677:                        break;
                    678:                case MYSQLND_OPT_SSL_KEY:
                    679:                        {
                    680:                                zend_bool pers = net->persistent;
                    681:                                if (net->options.ssl_key) {
                    682:                                        mnd_pefree(net->options.ssl_key, pers);
                    683:                                }
                    684:                                net->options.ssl_key = value? mnd_pestrdup(value, pers) : NULL;
                    685:                                break;
                    686:                        }
                    687:                case MYSQLND_OPT_SSL_CERT:
                    688:                        {
                    689:                                zend_bool pers = net->persistent;
                    690:                                if (net->options.ssl_cert) {
                    691:                                        mnd_pefree(net->options.ssl_cert, pers);
                    692:                                }
                    693:                                net->options.ssl_cert = value? mnd_pestrdup(value, pers) : NULL;
                    694:                                break;
                    695:                        }
                    696:                case MYSQLND_OPT_SSL_CA:
                    697:                        {
                    698:                                zend_bool pers = net->persistent;
                    699:                                if (net->options.ssl_ca) {
                    700:                                        mnd_pefree(net->options.ssl_ca, pers);
                    701:                                }
                    702:                                net->options.ssl_ca = value? mnd_pestrdup(value, pers) : NULL;
                    703:                                break;
                    704:                        }
                    705:                case MYSQLND_OPT_SSL_CAPATH:
                    706:                        {
                    707:                                zend_bool pers = net->persistent;
                    708:                                if (net->options.ssl_capath) {
                    709:                                        mnd_pefree(net->options.ssl_capath, pers);
                    710:                                }
                    711:                                net->options.ssl_capath = value? mnd_pestrdup(value, pers) : NULL;
                    712:                                break;
                    713:                        }
                    714:                case MYSQLND_OPT_SSL_CIPHER:
                    715:                        {
                    716:                                zend_bool pers = net->persistent;
                    717:                                if (net->options.ssl_cipher) {
                    718:                                        mnd_pefree(net->options.ssl_cipher, pers);
                    719:                                }
                    720:                                net->options.ssl_cipher = value? mnd_pestrdup(value, pers) : NULL;
                    721:                                break;
                    722:                        }
                    723:                case MYSQLND_OPT_SSL_PASSPHRASE:
                    724:                        {
                    725:                                zend_bool pers = net->persistent;
                    726:                                if (net->options.ssl_passphrase) {
                    727:                                        mnd_pefree(net->options.ssl_passphrase, pers);
                    728:                                }
                    729:                                net->options.ssl_passphrase = value? mnd_pestrdup(value, pers) : NULL;
                    730:                                break;
                    731:                        }
                    732:                case MYSQL_OPT_SSL_VERIFY_SERVER_CERT:
                    733:                        net->options.ssl_verify_peer = value? ((*(zend_bool *)value)? TRUE:FALSE): FALSE;
                    734:                        break;
                    735:                case MYSQL_OPT_READ_TIMEOUT:
                    736:                        net->options.timeout_read = *(unsigned int*) value;
                    737:                        break;
1.1.1.2   misho     738: #ifdef WHEN_SUPPORTED_BY_MYSQLI
1.1       misho     739:                case MYSQL_OPT_WRITE_TIMEOUT:
                    740:                        net->options.timeout_write = *(unsigned int*) value;
                    741:                        break;
                    742: #endif
                    743:                case MYSQL_OPT_COMPRESS:
                    744:                        net->options.flags |= MYSQLND_NET_FLAG_USE_COMPRESSION;
                    745:                        break;
                    746:                default:
                    747:                        DBG_RETURN(FAIL);
                    748:        }
                    749:        DBG_RETURN(PASS);
                    750: }
                    751: /* }}} */
                    752: 
                    753: /* {{{ mysqlnd_net::consume_uneaten_data */
                    754: size_t 
                    755: 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
1.1.1.4   misho     761:          the actual place where out-of-order packets have been sent.
1.1       misho     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:        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: MYSQLND_METHOD(mysqlnd_net, enable_ssl)(MYSQLND_NET * const net TSRMLS_DC)
                    807: {
                    808: #ifdef MYSQLND_SSL_SUPPORTED
1.1.1.2   misho     809:        php_stream_context *context = php_stream_context_alloc(TSRMLS_C);
1.1       misho     810:        DBG_ENTER("mysqlnd_net::enable_ssl");
                    811:        if (!context) {
                    812:                DBG_RETURN(FAIL);
                    813:        }
                    814: 
                    815:        if (net->options.ssl_key) {
                    816:                zval key_zval;
                    817:                ZVAL_STRING(&key_zval, net->options.ssl_key, 0);
                    818:                php_stream_context_set_option(context, "ssl", "local_pk", &key_zval);
                    819:        }
                    820:        if (net->options.ssl_verify_peer) {
                    821:                zval verify_peer_zval;
                    822:                ZVAL_TRUE(&verify_peer_zval);
                    823:                php_stream_context_set_option(context, "ssl", "verify_peer", &verify_peer_zval);
                    824:        }
                    825:        if (net->options.ssl_cert) {
                    826:                zval cert_zval;
                    827:                ZVAL_STRING(&cert_zval, net->options.ssl_cert, 0);
                    828:                php_stream_context_set_option(context, "ssl", "local_cert", &cert_zval);
                    829:                if (!net->options.ssl_key) {
                    830:                        php_stream_context_set_option(context, "ssl", "local_pk", &cert_zval);
                    831:                }
                    832:        }
                    833:        if (net->options.ssl_ca) {
                    834:                zval cafile_zval;
                    835:                ZVAL_STRING(&cafile_zval, net->options.ssl_ca, 0);
                    836:                php_stream_context_set_option(context, "ssl", "cafile", &cafile_zval);
                    837:        }
                    838:        if (net->options.ssl_capath) {
                    839:                zval capath_zval;
                    840:                ZVAL_STRING(&capath_zval, net->options.ssl_capath, 0);
                    841:                php_stream_context_set_option(context, "ssl", "cafile", &capath_zval);
                    842:        }
                    843:        if (net->options.ssl_passphrase) {
                    844:                zval passphrase_zval;
                    845:                ZVAL_STRING(&passphrase_zval, net->options.ssl_passphrase, 0);
                    846:                php_stream_context_set_option(context, "ssl", "passphrase", &passphrase_zval);
                    847:        }
                    848:        if (net->options.ssl_cipher) {
                    849:                zval cipher_zval;
                    850:                ZVAL_STRING(&cipher_zval, net->options.ssl_cipher, 0);
                    851:                php_stream_context_set_option(context, "ssl", "ciphers", &cipher_zval);
                    852:        }
                    853:        php_stream_context_set(net->stream, context);
                    854:        if (php_stream_xport_crypto_setup(net->stream, STREAM_CRYPTO_METHOD_TLS_CLIENT, NULL TSRMLS_CC) < 0 ||
                    855:            php_stream_xport_crypto_enable(net->stream, 1 TSRMLS_CC) < 0)
                    856:        {
                    857:                DBG_ERR("Cannot connect to MySQL by using SSL");
                    858:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot connect to MySQL by using SSL");
                    859:                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:        php_stream_context_set(net->stream, NULL);
                    869: 
                    870:        if (net->options.timeout_read) {
                    871:                struct timeval tv;
                    872:                DBG_INF_FMT("setting %u as PHP_STREAM_OPTION_READ_TIMEOUT", net->options.timeout_read);
                    873:                tv.tv_sec = net->options.timeout_read;
                    874:                tv.tv_usec = 0;
                    875:                php_stream_set_option(net->stream, PHP_STREAM_OPTION_READ_TIMEOUT, 0, &tv);
                    876:        }
                    877: 
                    878:        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: MYSQLND_METHOD(mysqlnd_net, disable_ssl)(MYSQLND_NET * const net TSRMLS_DC)
                    890: {
                    891:        DBG_ENTER("mysqlnd_net::disable_ssl");
                    892:        DBG_RETURN(PASS);
                    893: }
                    894: /* }}} */
                    895: 
                    896: 
1.1.1.2   misho     897: /* {{{ mysqlnd_net::free_contents */
1.1       misho     898: static void
                    899: MYSQLND_METHOD(mysqlnd_net, free_contents)(MYSQLND_NET * net TSRMLS_DC)
                    900: {
                    901:        zend_bool pers = net->persistent;
                    902:        DBG_ENTER("mysqlnd_net::free_contents");
                    903: 
                    904: #ifdef MYSQLND_COMPRESSION_ENABLED
                    905:        if (net->uncompressed_data) {
                    906:                net->uncompressed_data->free_buffer(&net->uncompressed_data TSRMLS_CC);
                    907:        }
                    908: #endif
                    909:        if (net->options.ssl_key) {
                    910:                mnd_pefree(net->options.ssl_key, pers);
                    911:                net->options.ssl_key = NULL;
                    912:        }
                    913:        if (net->options.ssl_cert) {
                    914:                mnd_pefree(net->options.ssl_cert, pers);
                    915:                net->options.ssl_cert = NULL;
                    916:        }
                    917:        if (net->options.ssl_ca) {
                    918:                mnd_pefree(net->options.ssl_ca, pers);
                    919:                net->options.ssl_ca = NULL;
                    920:        }
                    921:        if (net->options.ssl_capath) {
                    922:                mnd_pefree(net->options.ssl_capath, pers);
                    923:                net->options.ssl_capath = NULL;
                    924:        }
                    925:        if (net->options.ssl_cipher) {
                    926:                mnd_pefree(net->options.ssl_cipher, pers);
                    927:                net->options.ssl_cipher = NULL;
                    928:        }
                    929: 
                    930:        DBG_VOID_RETURN;
                    931: }
                    932: /* }}} */
                    933: 
                    934: 
1.1.1.2   misho     935: /* {{{ mysqlnd_net::close_stream */
                    936: static void
                    937: MYSQLND_METHOD(mysqlnd_net, close_stream)(MYSQLND_NET * const net, MYSQLND_STATS * const stats, MYSQLND_ERROR_INFO * const error_info TSRMLS_DC)
1.1       misho     938: {
1.1.1.2   misho     939:        DBG_ENTER("mysqlnd_net::close_stream");
                    940:        if (net && net->stream) {
                    941:                zend_bool pers = net->persistent;
                    942:                DBG_INF_FMT("Freeing stream. abstract=%p", net->stream->abstract);
                    943:                if (pers) {
                    944:                        if (EG(active)) {
                    945:                                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:                                php_stream_free(net->stream, PHP_STREAM_FREE_CLOSE | PHP_STREAM_FREE_RSRC_DTOR);
                    952:                        }
                    953:                } else {
                    954:                        php_stream_free(net->stream, PHP_STREAM_FREE_CLOSE);
1.1       misho     955:                }
1.1.1.2   misho     956:                net->stream = NULL;
1.1       misho     957:        }
1.1.1.2   misho     958: 
                    959:        DBG_VOID_RETURN;
1.1       misho     960: }
                    961: /* }}} */
                    962: 
                    963: 
1.1.1.2   misho     964: /* {{{ mysqlnd_net::init */
                    965: static enum_func_status
                    966: MYSQLND_METHOD(mysqlnd_net, init)(MYSQLND_NET * const net, MYSQLND_STATS * const stats, MYSQLND_ERROR_INFO * const error_info TSRMLS_DC)
1.1       misho     967: {
1.1.1.2   misho     968:        unsigned int buf_size;
                    969:        DBG_ENTER("mysqlnd_net::init");
                    970: 
                    971:        buf_size = MYSQLND_G(net_cmd_buffer_size); /* this is long, cast to unsigned int*/
                    972:        net->m.set_client_option(net, MYSQLND_OPT_NET_CMD_BUFFER_SIZE, (char *) &buf_size TSRMLS_CC);
                    973: 
                    974:        buf_size = MYSQLND_G(net_read_buffer_size); /* this is long, cast to unsigned int*/
                    975:        net->m.set_client_option(net, MYSQLND_OPT_NET_READ_BUFFER_SIZE, (char *)&buf_size TSRMLS_CC);
                    976: 
                    977:        buf_size = MYSQLND_G(net_read_timeout); /* this is long, cast to unsigned int*/
                    978:        net->m.set_client_option(net, MYSQL_OPT_READ_TIMEOUT, (char *)&buf_size TSRMLS_CC);
1.1       misho     979: 
1.1.1.2   misho     980:        DBG_RETURN(PASS);
                    981: }
                    982: /* }}} */
                    983: 
                    984: 
                    985: /* {{{ mysqlnd_net::dtor */
                    986: static void
                    987: MYSQLND_METHOD(mysqlnd_net, dtor)(MYSQLND_NET * const net, MYSQLND_STATS * const stats, MYSQLND_ERROR_INFO * const error_info TSRMLS_DC)
                    988: {
                    989:        DBG_ENTER("mysqlnd_net::dtor");
1.1       misho     990:        if (net) {
                    991:                zend_bool pers = net->persistent;
1.1.1.2   misho     992:        
1.1       misho     993:                net->m.free_contents(net TSRMLS_CC);
1.1.1.2   misho     994:                net->m.close_stream(net, stats, error_info TSRMLS_CC);
1.1       misho     995:                if (net->cmd_buffer.buffer) {
                    996:                        DBG_INF("Freeing cmd buffer");
                    997:                        mnd_pefree(net->cmd_buffer.buffer, pers);
                    998:                        net->cmd_buffer.buffer = NULL;
                    999:                }
                   1000:                mnd_pefree(net, pers);
                   1001:        }
                   1002:        DBG_VOID_RETURN;
                   1003: }
                   1004: /* }}} */
                   1005: 
                   1006: 
1.1.1.2   misho    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: mysqlnd_net_init(zend_bool persistent, MYSQLND_STATS * stats, MYSQLND_ERROR_INFO * error_info TSRMLS_DC)
1.1       misho    1039: {
1.1.1.2   misho    1040:        MYSQLND_NET * net;
                   1041:        DBG_ENTER("mysqlnd_net_init");
                   1042:        net = MYSQLND_CLASS_METHOD_TABLE_NAME(mysqlnd_object_factory).get_io_channel(persistent, stats, error_info TSRMLS_CC);
                   1043:        DBG_RETURN(net);
1.1       misho    1044: }
                   1045: /* }}} */
                   1046: 
                   1047: 
1.1.1.2   misho    1048: /* {{{ mysqlnd_net_free */
                   1049: PHPAPI void
                   1050: mysqlnd_net_free(MYSQLND_NET * const net, MYSQLND_STATS * stats, MYSQLND_ERROR_INFO * error_info TSRMLS_DC)
1.1       misho    1051: {
1.1.1.2   misho    1052:        DBG_ENTER("mysqlnd_net_free");
                   1053:        if (net) {
                   1054:                net->m.dtor(net, stats, error_info TSRMLS_CC);
                   1055:        }
                   1056:        DBG_VOID_RETURN;
1.1       misho    1057: }
                   1058: /* }}} */
                   1059: 
                   1060: 
1.1.1.2   misho    1061: 
1.1       misho    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:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>