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

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

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