Annotation of embedaddon/php/ext/mysqlnd/mysqlnd_net.c, revision 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>