source: src/router/php7/ext/mysqlnd/mysqlnd_vio.c @ 31874

Last change on this file since 31874 was 31874, checked in by brainslayer, 3 months ago

update php

File size: 24.8 KB
Line 
1/*
2  +----------------------------------------------------------------------+
3  | PHP Version 7                                                        |
4  +----------------------------------------------------------------------+
5  | Copyright (c) 2006-2017 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: Andrey Hristov <andrey@php.net>                             |
16  |          Ulf Wendel <uw@php.net>                                     |
17  +----------------------------------------------------------------------+
18*/
19
20#include "php.h"
21#include "mysqlnd.h"
22#include "mysqlnd_priv.h"
23#include "mysqlnd_statistics.h"
24#include "mysqlnd_debug.h"
25#include "mysqlnd_ext_plugin.h"
26#include "php_network.h"
27
28#ifndef PHP_WIN32
29#include <netinet/tcp.h>
30#else
31#include <winsock.h>
32#endif
33
34
35/* {{{ mysqlnd_set_sock_no_delay */
36static int
37mysqlnd_set_sock_no_delay(php_stream * stream)
38{
39        int socketd = ((php_netstream_data_t*)stream->abstract)->socket;
40        int ret = SUCCESS;
41        int flag = 1;
42        int result = setsockopt(socketd, IPPROTO_TCP,  TCP_NODELAY, (char *) &flag, sizeof(int));
43
44        DBG_ENTER("mysqlnd_set_sock_no_delay");
45
46        if (result == -1) {
47                ret = FAILURE;
48        }
49
50        DBG_RETURN(ret);
51}
52/* }}} */
53
54
55/* {{{ mysqlnd_set_sock_keepalive */
56static int
57mysqlnd_set_sock_keepalive(php_stream * stream)
58{
59        int socketd = ((php_netstream_data_t*)stream->abstract)->socket;
60        int ret = SUCCESS;
61        int flag = 1;
62        int result = setsockopt(socketd, SOL_SOCKET, SO_KEEPALIVE, (char *) &flag, sizeof(int));
63
64        DBG_ENTER("mysqlnd_set_sock_keepalive");
65
66        if (result == -1) {
67                ret = FAILURE;
68        }
69
70        DBG_RETURN(ret);
71}
72/* }}} */
73
74
75/* {{{ mysqlnd_vio::network_read */
76static enum_func_status
77MYSQLND_METHOD(mysqlnd_vio, network_read)(MYSQLND_VIO * const vio, zend_uchar * const buffer, const size_t count,
78                                                                                  MYSQLND_STATS * const stats, MYSQLND_ERROR_INFO * const error_info)
79{
80        enum_func_status return_value = PASS;
81        php_stream * net_stream = vio->data->m.get_stream(vio);
82        size_t old_chunk_size = net_stream->chunk_size;
83        size_t to_read = count, ret;
84        zend_uchar * p = buffer;
85
86        DBG_ENTER("mysqlnd_vio::network_read");
87        DBG_INF_FMT("count="MYSQLND_SZ_T_SPEC, count);
88
89        net_stream->chunk_size = MIN(to_read, vio->data->options.net_read_buffer_size);
90        while (to_read) {
91                if (!(ret = php_stream_read(net_stream, (char *) p, to_read))) {
92                        DBG_ERR_FMT("Error while reading header from socket");
93                        return_value = FAIL;
94                        break;
95                }
96                p += ret;
97                to_read -= ret;
98        }
99        MYSQLND_INC_CONN_STATISTIC_W_VALUE(stats, STAT_BYTES_RECEIVED, count - to_read);
100        net_stream->chunk_size = old_chunk_size;
101        DBG_RETURN(return_value);
102}
103/* }}} */
104
105
106/* {{{ mysqlnd_vio::network_write */
107static size_t
108MYSQLND_METHOD(mysqlnd_vio, network_write)(MYSQLND_VIO * const vio, const zend_uchar * const buffer, const size_t count,
109                                                                                   MYSQLND_STATS * const stats, MYSQLND_ERROR_INFO * const error_info)
110{
111        size_t ret;
112        DBG_ENTER("mysqlnd_vio::network_write");
113        DBG_INF_FMT("sending %u bytes", count);
114        ret = php_stream_write(vio->data->m.get_stream(vio), (char *)buffer, count);
115        DBG_RETURN(ret);
116}
117/* }}} */
118
119
120/* {{{ mysqlnd_vio::open_pipe */
121static php_stream *
122MYSQLND_METHOD(mysqlnd_vio, open_pipe)(MYSQLND_VIO * const vio, const MYSQLND_CSTRING scheme, const zend_bool persistent,
123                                                                           MYSQLND_STATS * const conn_stats, MYSQLND_ERROR_INFO * const error_info)
124{
125        unsigned int streams_options = 0;
126        dtor_func_t origin_dtor;
127        php_stream * net_stream = NULL;
128
129        DBG_ENTER("mysqlnd_vio::open_pipe");
130        if (persistent) {
131                streams_options |= STREAM_OPEN_PERSISTENT;
132        }
133        streams_options |= IGNORE_URL;
134        net_stream = php_stream_open_wrapper(scheme.s + sizeof("pipe://") - 1, "r+", streams_options, NULL);
135        if (!net_stream) {
136                SET_CLIENT_ERROR(error_info, CR_CONNECTION_ERROR, UNKNOWN_SQLSTATE, "Unknown errror while connecting");
137                DBG_RETURN(NULL);
138        }
139        /*
140          Streams are not meant for C extensions! Thus we need a hack. Every connected stream will
141          be registered as resource (in EG(regular_list). So far, so good. However, it won't be
142          unregistered until the script ends. So, we need to take care of that.
143        */
144        origin_dtor = EG(regular_list).pDestructor;
145        EG(regular_list).pDestructor = NULL;
146        zend_hash_index_del(&EG(regular_list), net_stream->res->handle); /* ToDO: should it be res->handle, do streams register with addref ?*/
147        EG(regular_list).pDestructor = origin_dtor;
148        net_stream->res = NULL;
149
150        DBG_RETURN(net_stream);
151}
152/* }}} */
153
154
155/* {{{ mysqlnd_vio::open_tcp_or_unix */
156static php_stream *
157MYSQLND_METHOD(mysqlnd_vio, open_tcp_or_unix)(MYSQLND_VIO * const vio, const MYSQLND_CSTRING scheme, const zend_bool persistent,
158                                                                                          MYSQLND_STATS * const conn_stats, MYSQLND_ERROR_INFO * const error_info)
159{
160        unsigned int streams_options = 0;
161        unsigned int streams_flags = STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT;
162        char * hashed_details = NULL;
163        int hashed_details_len = 0;
164        zend_string *errstr = NULL;
165        int errcode = 0;
166        struct timeval tv;
167        dtor_func_t origin_dtor;
168        php_stream * net_stream = NULL;
169
170        DBG_ENTER("mysqlnd_vio::open_tcp_or_unix");
171
172        vio->data->stream = NULL;
173
174        if (persistent) {
175                hashed_details_len = mnd_sprintf(&hashed_details, 0, "%p", vio);
176                DBG_INF_FMT("hashed_details=%s", hashed_details);
177        }
178
179        if (vio->data->options.timeout_connect) {
180                tv.tv_sec = vio->data->options.timeout_connect;
181                tv.tv_usec = 0;
182        }
183
184        DBG_INF_FMT("calling php_stream_xport_create");
185        net_stream = php_stream_xport_create(scheme.s, scheme.l, streams_options, streams_flags,
186                                                                                  hashed_details, (vio->data->options.timeout_connect) ? &tv : NULL,
187                                                                                  NULL /*ctx*/, &errstr, &errcode);
188        if (errstr || !net_stream) {
189                DBG_ERR("Error");
190                if (hashed_details) {
191                        mnd_sprintf_free(hashed_details);
192                }
193                errcode = CR_CONNECTION_ERROR;
194                SET_CLIENT_ERROR(error_info,
195                                                 CR_CONNECTION_ERROR,
196                                                 UNKNOWN_SQLSTATE,
197                                                 errstr? ZSTR_VAL(errstr):"Unknown error while connecting");
198                if (errstr) {
199                        zend_string_release(errstr);
200                }
201                DBG_RETURN(NULL);
202        }
203        if (hashed_details) {
204                /*
205                  If persistent, the streams register it in EG(persistent_list).
206                  This is unwanted. ext/mysql or ext/mysqli are responsible to clean,
207                  whatever they have to.
208                */
209                zend_resource *le;
210
211                if ((le = zend_hash_str_find_ptr(&EG(persistent_list), hashed_details, hashed_details_len))) {
212                        origin_dtor = EG(persistent_list).pDestructor;
213                        /*
214                          in_free will let streams code skip destructing - big HACK,
215                          but STREAMS suck big time regarding persistent streams.
216                          Just not compatible for extensions that need persistency.
217                        */
218                        EG(persistent_list).pDestructor = NULL;
219                        zend_hash_str_del(&EG(persistent_list), hashed_details, hashed_details_len);
220                        EG(persistent_list).pDestructor = origin_dtor;
221                        pefree(le, 1);
222                }
223#if ZEND_DEBUG
224                /* Shut-up the streams, they don't know what they are doing */
225                net_stream->__exposed = 1;
226#endif
227                mnd_sprintf_free(hashed_details);
228        }
229
230        /*
231          Streams are not meant for C extensions! Thus we need a hack. Every connected stream will
232          be registered as resource (in EG(regular_list). So far, so good. However, it won't be
233          unregistered until the script ends. So, we need to take care of that.
234        */
235        origin_dtor = EG(regular_list).pDestructor;
236        EG(regular_list).pDestructor = NULL;
237        zend_hash_index_del(&EG(regular_list), net_stream->res->handle); /* ToDO: should it be res->handle, do streams register with addref ?*/
238        efree(net_stream->res);
239        net_stream->res = NULL;
240        EG(regular_list).pDestructor = origin_dtor;
241        DBG_RETURN(net_stream);
242}
243/* }}} */
244
245
246/* {{{ mysqlnd_vio::post_connect_set_opt */
247static void
248MYSQLND_METHOD(mysqlnd_vio, post_connect_set_opt)(MYSQLND_VIO * const vio, const MYSQLND_CSTRING scheme,
249                                                                                                  MYSQLND_STATS * const conn_stats, MYSQLND_ERROR_INFO * const error_info)
250{
251        php_stream * net_stream = vio->data->m.get_stream(vio);
252        DBG_ENTER("mysqlnd_vio::post_connect_set_opt");
253        if (net_stream) {
254                if (vio->data->options.timeout_read) {
255                        struct timeval tv;
256                        DBG_INF_FMT("setting %u as PHP_STREAM_OPTION_READ_TIMEOUT", vio->data->options.timeout_read);
257                        tv.tv_sec = vio->data->options.timeout_read;
258                        tv.tv_usec = 0;
259                        php_stream_set_option(net_stream, PHP_STREAM_OPTION_READ_TIMEOUT, 0, &tv);
260                }
261
262                if (!memcmp(scheme.s, "tcp://", sizeof("tcp://") - 1)) {
263                        /* TCP -> Set TCP_NODELAY */
264                        mysqlnd_set_sock_no_delay(net_stream);
265                        /* TCP -> Set SO_KEEPALIVE */
266                        mysqlnd_set_sock_keepalive(net_stream);
267                }
268        }
269
270        DBG_VOID_RETURN;
271}
272/* }}} */
273
274
275/* {{{ mysqlnd_vio::get_open_stream */
276static func_mysqlnd_vio__open_stream
277MYSQLND_METHOD(mysqlnd_vio, get_open_stream)(MYSQLND_VIO * const vio, const MYSQLND_CSTRING scheme,
278                                                                                         MYSQLND_ERROR_INFO * const error_info)
279{
280        func_mysqlnd_vio__open_stream ret = NULL;
281        DBG_ENTER("mysqlnd_vio::get_open_stream");
282        if (scheme.l > (sizeof("pipe://") - 1) && !memcmp(scheme.s, "pipe://", sizeof("pipe://") - 1)) {
283                ret = vio->data->m.open_pipe;
284        } else if ((scheme.l > (sizeof("tcp://") - 1) && !memcmp(scheme.s, "tcp://", sizeof("tcp://") - 1))
285                                ||
286                                (scheme.l > (sizeof("unix://") - 1) && !memcmp(scheme.s, "unix://", sizeof("unix://") - 1)))
287        {
288                ret = vio->data->m.open_tcp_or_unix;
289        }
290
291        if (!ret) {
292                SET_CLIENT_ERROR(error_info, CR_CONNECTION_ERROR, UNKNOWN_SQLSTATE, "No handler for this scheme");
293        }
294
295        DBG_RETURN(ret);
296}
297/* }}} */
298
299
300/* {{{ mysqlnd_vio::connect */
301static enum_func_status
302MYSQLND_METHOD(mysqlnd_vio, connect)(MYSQLND_VIO * const vio, const MYSQLND_CSTRING scheme, const zend_bool persistent,
303                                                                         MYSQLND_STATS * const conn_stats, MYSQLND_ERROR_INFO * const error_info)
304{
305        enum_func_status ret = FAIL;
306        func_mysqlnd_vio__open_stream open_stream = NULL;
307        DBG_ENTER("mysqlnd_vio::connect");
308
309        vio->data->m.close_stream(vio, conn_stats, error_info);
310
311        open_stream = vio->data->m.get_open_stream(vio, scheme, error_info);
312        if (open_stream) {
313                php_stream * net_stream = open_stream(vio, scheme, persistent, conn_stats, error_info);
314                if (net_stream && PASS == vio->data->m.set_stream(vio, net_stream)) {
315                        vio->data->m.post_connect_set_opt(vio, scheme, conn_stats, error_info);
316                        ret = PASS;
317                }
318        }
319
320        DBG_RETURN(ret);
321}
322/* }}} */
323
324
325/* {{{ mysqlnd_vio::set_client_option */
326static enum_func_status
327MYSQLND_METHOD(mysqlnd_vio, set_client_option)(MYSQLND_VIO * const net, enum_mysqlnd_client_option option, const char * const value)
328{
329        DBG_ENTER("mysqlnd_vio::set_client_option");
330        DBG_INF_FMT("option=%u", option);
331        switch (option) {
332                case MYSQLND_OPT_NET_READ_BUFFER_SIZE:
333                        DBG_INF("MYSQLND_OPT_NET_READ_BUFFER_SIZE");
334                        net->data->options.net_read_buffer_size = *(unsigned int*) value;
335                        DBG_INF_FMT("new_length="MYSQLND_SZ_T_SPEC, net->data->options.net_read_buffer_size);
336                        break;
337                case MYSQL_OPT_CONNECT_TIMEOUT:
338                        DBG_INF("MYSQL_OPT_CONNECT_TIMEOUT");
339                        net->data->options.timeout_connect = *(unsigned int*) value;
340                        break;
341                case MYSQLND_OPT_SSL_KEY:
342                        {
343                                zend_bool pers = net->persistent;
344                                if (net->data->options.ssl_key) {
345                                        mnd_pefree(net->data->options.ssl_key, pers);
346                                }
347                                net->data->options.ssl_key = value? mnd_pestrdup(value, pers) : NULL;
348                                break;
349                        }
350                case MYSQLND_OPT_SSL_CERT:
351                        {
352                                zend_bool pers = net->persistent;
353                                if (net->data->options.ssl_cert) {
354                                        mnd_pefree(net->data->options.ssl_cert, pers);
355                                }
356                                net->data->options.ssl_cert = value? mnd_pestrdup(value, pers) : NULL;
357                                break;
358                        }
359                case MYSQLND_OPT_SSL_CA:
360                        {
361                                zend_bool pers = net->persistent;
362                                if (net->data->options.ssl_ca) {
363                                        mnd_pefree(net->data->options.ssl_ca, pers);
364                                }
365                                net->data->options.ssl_ca = value? mnd_pestrdup(value, pers) : NULL;
366                                break;
367                        }
368                case MYSQLND_OPT_SSL_CAPATH:
369                        {
370                                zend_bool pers = net->persistent;
371                                if (net->data->options.ssl_capath) {
372                                        mnd_pefree(net->data->options.ssl_capath, pers);
373                                }
374                                net->data->options.ssl_capath = value? mnd_pestrdup(value, pers) : NULL;
375                                break;
376                        }
377                case MYSQLND_OPT_SSL_CIPHER:
378                        {
379                                zend_bool pers = net->persistent;
380                                if (net->data->options.ssl_cipher) {
381                                        mnd_pefree(net->data->options.ssl_cipher, pers);
382                                }
383                                net->data->options.ssl_cipher = value? mnd_pestrdup(value, pers) : NULL;
384                                break;
385                        }
386                case MYSQLND_OPT_SSL_PASSPHRASE:
387                        {
388                                zend_bool pers = net->persistent;
389                                if (net->data->options.ssl_passphrase) {
390                                        mnd_pefree(net->data->options.ssl_passphrase, pers);
391                                }
392                                net->data->options.ssl_passphrase = value? mnd_pestrdup(value, pers) : NULL;
393                                break;
394                        }
395                case MYSQL_OPT_SSL_VERIFY_SERVER_CERT:
396                {
397                        enum mysqlnd_ssl_peer val = *((enum mysqlnd_ssl_peer *)value);
398                        switch (val) {
399                                case MYSQLND_SSL_PEER_VERIFY:
400                                        DBG_INF("MYSQLND_SSL_PEER_VERIFY");
401                                        break;
402                                case MYSQLND_SSL_PEER_DONT_VERIFY:
403                                        DBG_INF("MYSQLND_SSL_PEER_DONT_VERIFY");
404                                        break;
405                                case MYSQLND_SSL_PEER_DEFAULT:
406                                        DBG_INF("MYSQLND_SSL_PEER_DEFAULT");
407                                        val = MYSQLND_SSL_PEER_DEFAULT;
408                                        break;
409                                default:
410                                        DBG_INF("default = MYSQLND_SSL_PEER_DEFAULT_ACTION");
411                                        val = MYSQLND_SSL_PEER_DEFAULT;
412                                        break;
413                        }
414                        net->data->options.ssl_verify_peer = val;
415                        break;
416                }
417                case MYSQL_OPT_READ_TIMEOUT:
418                        net->data->options.timeout_read = *(unsigned int*) value;
419                        break;
420#ifdef WHEN_SUPPORTED_BY_MYSQLI
421                case MYSQL_OPT_WRITE_TIMEOUT:
422                        net->data->options.timeout_write = *(unsigned int*) value;
423                        break;
424#endif
425                default:
426                        DBG_RETURN(FAIL);
427        }
428        DBG_RETURN(PASS);
429}
430/* }}} */
431
432
433/* {{{ mysqlnd_vio::consume_uneaten_data */
434size_t
435MYSQLND_METHOD(mysqlnd_vio, consume_uneaten_data)(MYSQLND_VIO * const net, enum php_mysqlnd_server_command cmd)
436{
437#ifdef MYSQLND_DO_WIRE_CHECK_BEFORE_COMMAND
438        /*
439          Switch to non-blocking mode and try to consume something from
440          the line, if possible, then continue. This saves us from looking for
441          the actual place where out-of-order packets have been sent.
442          If someone is completely sure that everything is fine, he can switch it
443          off.
444        */
445        char tmp_buf[256];
446        size_t skipped_bytes = 0;
447        int opt = PHP_STREAM_OPTION_BLOCKING;
448        php_stream * net_stream = net->data->get_stream(net);
449        int was_blocked = net_stream->ops->set_option(net_stream, opt, 0, NULL);
450
451        DBG_ENTER("mysqlnd_vio::consume_uneaten_data");
452
453        if (PHP_STREAM_OPTION_RETURN_ERR != was_blocked) {
454                /* Do a read of 1 byte */
455                int bytes_consumed;
456
457                do {
458                        skipped_bytes += (bytes_consumed = php_stream_read(net_stream, tmp_buf, sizeof(tmp_buf)));
459                } while (bytes_consumed == sizeof(tmp_buf));
460
461                if (was_blocked) {
462                        net_stream->ops->set_option(net_stream, opt, 1, NULL);
463                }
464
465                if (bytes_consumed) {
466                        DBG_ERR_FMT("Skipped %u bytes. Last command hasn't consumed all the output from the server",
467                                                bytes_consumed, mysqlnd_command_to_text[net->last_command]);
468                        php_error_docref(NULL, E_WARNING, "Skipped %u bytes. Last command %s hasn't "
469                                                         "consumed all the output from the server",
470                                                         bytes_consumed, mysqlnd_command_to_text[net->last_command]);
471                }
472        }
473        net->last_command = cmd;
474
475        DBG_RETURN(skipped_bytes);
476#else
477        return 0;
478#endif
479}
480/* }}} */
481
482/*
483  in libmyusql, if cert and !key then key=cert
484*/
485/* {{{ mysqlnd_vio::enable_ssl */
486static enum_func_status
487MYSQLND_METHOD(mysqlnd_vio, enable_ssl)(MYSQLND_VIO * const net)
488{
489#ifdef MYSQLND_SSL_SUPPORTED
490        php_stream_context * context = php_stream_context_alloc();
491        php_stream * net_stream = net->data->m.get_stream(net);
492        zend_bool any_flag = FALSE;
493
494        DBG_ENTER("mysqlnd_vio::enable_ssl");
495        if (!context) {
496                DBG_RETURN(FAIL);
497        }
498
499        if (net->data->options.ssl_key) {
500                zval key_zval;
501                ZVAL_STRING(&key_zval, net->data->options.ssl_key);
502                php_stream_context_set_option(context, "ssl", "local_pk", &key_zval);
503                zval_ptr_dtor(&key_zval);
504                any_flag = TRUE;
505        }
506        if (net->data->options.ssl_cert) {
507                zval cert_zval;
508                ZVAL_STRING(&cert_zval, net->data->options.ssl_cert);
509                php_stream_context_set_option(context, "ssl", "local_cert", &cert_zval);
510                if (!net->data->options.ssl_key) {
511                        php_stream_context_set_option(context, "ssl", "local_pk", &cert_zval);
512                }
513                zval_ptr_dtor(&cert_zval);
514                any_flag = TRUE;
515        }
516        if (net->data->options.ssl_ca) {
517                zval cafile_zval;
518                ZVAL_STRING(&cafile_zval, net->data->options.ssl_ca);
519                php_stream_context_set_option(context, "ssl", "cafile", &cafile_zval);
520                any_flag = TRUE;
521        }
522        if (net->data->options.ssl_capath) {
523                zval capath_zval;
524                ZVAL_STRING(&capath_zval, net->data->options.ssl_capath);
525                php_stream_context_set_option(context, "ssl", "capath", &capath_zval);
526                zval_ptr_dtor(&capath_zval);
527                any_flag = TRUE;
528        }
529        if (net->data->options.ssl_passphrase) {
530                zval passphrase_zval;
531                ZVAL_STRING(&passphrase_zval, net->data->options.ssl_passphrase);
532                php_stream_context_set_option(context, "ssl", "passphrase", &passphrase_zval);
533                zval_ptr_dtor(&passphrase_zval);
534                any_flag = TRUE;
535        }
536        if (net->data->options.ssl_cipher) {
537                zval cipher_zval;
538                ZVAL_STRING(&cipher_zval, net->data->options.ssl_cipher);
539                php_stream_context_set_option(context, "ssl", "ciphers", &cipher_zval);
540                zval_ptr_dtor(&cipher_zval);
541                any_flag = TRUE;
542        }
543        {
544                zval verify_peer_zval;
545                zend_bool verify;
546
547                if (net->data->options.ssl_verify_peer == MYSQLND_SSL_PEER_DEFAULT) {
548                        net->data->options.ssl_verify_peer = any_flag? MYSQLND_SSL_PEER_DEFAULT_ACTION:MYSQLND_SSL_PEER_DONT_VERIFY;
549                }
550
551                verify = net->data->options.ssl_verify_peer == MYSQLND_SSL_PEER_VERIFY? TRUE:FALSE;
552
553                DBG_INF_FMT("VERIFY=%d", verify);
554                ZVAL_BOOL(&verify_peer_zval, verify);
555                php_stream_context_set_option(context, "ssl", "verify_peer", &verify_peer_zval);
556                php_stream_context_set_option(context, "ssl", "verify_peer_name", &verify_peer_zval);
557                if (net->data->options.ssl_verify_peer == MYSQLND_SSL_PEER_DONT_VERIFY) {
558                        ZVAL_TRUE(&verify_peer_zval);
559                        php_stream_context_set_option(context, "ssl", "allow_self_signed", &verify_peer_zval);
560                }
561        }
562        php_stream_context_set(net_stream, context);
563        if (php_stream_xport_crypto_setup(net_stream, STREAM_CRYPTO_METHOD_TLS_CLIENT, NULL) < 0 ||
564            php_stream_xport_crypto_enable(net_stream, 1) < 0)
565        {
566                DBG_ERR("Cannot connect to MySQL by using SSL");
567                php_error_docref(NULL, E_WARNING, "Cannot connect to MySQL by using SSL");
568                DBG_RETURN(FAIL);
569        }
570        net->data->ssl = TRUE;
571        /*
572          get rid of the context. we are persistent and if this is a real pconn used by mysql/mysqli,
573          then the context would not survive cleaning of EG(regular_list), where it is registered, as a
574          resource. What happens is that after this destruction any use of the network will mean usage
575          of the context, which means usage of already freed memory, bad. Actually we don't need this
576          context anymore after we have enabled SSL on the connection. Thus it is very simple, we remove it.
577        */
578        php_stream_context_set(net_stream, NULL);
579
580        if (net->data->options.timeout_read) {
581                struct timeval tv;
582                DBG_INF_FMT("setting %u as PHP_STREAM_OPTION_READ_TIMEOUT", net->data->options.timeout_read);
583                tv.tv_sec = net->data->options.timeout_read;
584                tv.tv_usec = 0;
585                php_stream_set_option(net_stream, PHP_STREAM_OPTION_READ_TIMEOUT, 0, &tv);
586        }
587
588        DBG_RETURN(PASS);
589#else
590        DBG_ENTER("mysqlnd_vio::enable_ssl");
591        DBG_INF("MYSQLND_SSL_SUPPORTED is not defined");
592        DBG_RETURN(PASS);
593#endif
594}
595/* }}} */
596
597
598/* {{{ mysqlnd_vio::disable_ssl */
599static enum_func_status
600MYSQLND_METHOD(mysqlnd_vio, disable_ssl)(MYSQLND_VIO * const vio)
601{
602        DBG_ENTER("mysqlnd_vio::disable_ssl");
603        DBG_RETURN(PASS);
604}
605/* }}} */
606
607
608/* {{{ mysqlnd_vio::free_contents */
609static void
610MYSQLND_METHOD(mysqlnd_vio, free_contents)(MYSQLND_VIO * net)
611{
612        zend_bool pers = net->persistent;
613        DBG_ENTER("mysqlnd_vio::free_contents");
614
615        if (net->data->options.ssl_key) {
616                mnd_pefree(net->data->options.ssl_key, pers);
617                net->data->options.ssl_key = NULL;
618        }
619        if (net->data->options.ssl_cert) {
620                mnd_pefree(net->data->options.ssl_cert, pers);
621                net->data->options.ssl_cert = NULL;
622        }
623        if (net->data->options.ssl_ca) {
624                mnd_pefree(net->data->options.ssl_ca, pers);
625                net->data->options.ssl_ca = NULL;
626        }
627        if (net->data->options.ssl_capath) {
628                mnd_pefree(net->data->options.ssl_capath, pers);
629                net->data->options.ssl_capath = NULL;
630        }
631        if (net->data->options.ssl_cipher) {
632                mnd_pefree(net->data->options.ssl_cipher, pers);
633                net->data->options.ssl_cipher = NULL;
634        }
635
636        DBG_VOID_RETURN;
637}
638/* }}} */
639
640
641/* {{{ mysqlnd_vio::close_stream */
642static void
643MYSQLND_METHOD(mysqlnd_vio, close_stream)(MYSQLND_VIO * const net, MYSQLND_STATS * const stats, MYSQLND_ERROR_INFO * const error_info)
644{
645        php_stream * net_stream;
646        DBG_ENTER("mysqlnd_vio::close_stream");
647        if (net && (net_stream = net->data->m.get_stream(net))) {
648                zend_bool pers = net->persistent;
649                DBG_INF_FMT("Freeing stream. abstract=%p", net_stream->abstract);
650                if (pers) {
651                        if (EG(active)) {
652                                php_stream_free(net_stream, PHP_STREAM_FREE_CLOSE_PERSISTENT | PHP_STREAM_FREE_RSRC_DTOR);
653                        } else {
654                                /*
655                                  otherwise we will crash because the EG(persistent_list) has been freed already,
656                                  before the modules are shut down
657                                */
658                                php_stream_free(net_stream, PHP_STREAM_FREE_CLOSE | PHP_STREAM_FREE_RSRC_DTOR);
659                        }
660                } else {
661                        php_stream_free(net_stream, PHP_STREAM_FREE_CLOSE);
662                }
663                net->data->m.set_stream(net, NULL);
664        }
665
666        DBG_VOID_RETURN;
667}
668/* }}} */
669
670
671/* {{{ mysqlnd_vio::init */
672static enum_func_status
673MYSQLND_METHOD(mysqlnd_vio, init)(MYSQLND_VIO * const net, MYSQLND_STATS * const stats, MYSQLND_ERROR_INFO * const error_info)
674{
675        unsigned int buf_size;
676        DBG_ENTER("mysqlnd_vio::init");
677
678        buf_size = MYSQLND_G(net_read_buffer_size); /* this is long, cast to unsigned int*/
679        net->data->m.set_client_option(net, MYSQLND_OPT_NET_READ_BUFFER_SIZE, (char *)&buf_size);
680
681        buf_size = MYSQLND_G(net_read_timeout); /* this is long, cast to unsigned int*/
682        net->data->m.set_client_option(net, MYSQL_OPT_READ_TIMEOUT, (char *)&buf_size);
683
684        DBG_RETURN(PASS);
685}
686/* }}} */
687
688
689/* {{{ mysqlnd_vio::dtor */
690static void
691MYSQLND_METHOD(mysqlnd_vio, dtor)(MYSQLND_VIO * const vio, MYSQLND_STATS * const stats, MYSQLND_ERROR_INFO * const error_info)
692{
693        DBG_ENTER("mysqlnd_vio::dtor");
694        if (vio) {
695                vio->data->m.free_contents(vio);
696                vio->data->m.close_stream(vio, stats, error_info);
697
698                mnd_pefree(vio->data, vio->data->persistent);
699                mnd_pefree(vio, vio->persistent);
700        }
701        DBG_VOID_RETURN;
702}
703/* }}} */
704
705
706/* {{{ mysqlnd_vio::get_stream */
707static php_stream *
708MYSQLND_METHOD(mysqlnd_vio, get_stream)(const MYSQLND_VIO * const net)
709{
710        DBG_ENTER("mysqlnd_vio::get_stream");
711        DBG_INF_FMT("%p", net? net->data->stream:NULL);
712        DBG_RETURN(net? net->data->stream:NULL);
713}
714/* }}} */
715
716
717/* {{{ mysqlnd_vio::set_stream */
718static enum_func_status
719MYSQLND_METHOD(mysqlnd_vio, set_stream)(MYSQLND_VIO * const vio, php_stream * net_stream)
720{
721        DBG_ENTER("mysqlnd_vio::set_stream");
722        if (vio) {
723                vio->data->stream = net_stream;
724                DBG_RETURN(PASS);
725        }
726        DBG_RETURN(FAIL);
727}
728/* }}} */
729
730
731/* {{{ mysqlnd_vio::has_valid_stream */
732static zend_bool
733MYSQLND_METHOD(mysqlnd_vio, has_valid_stream)(const MYSQLND_VIO * const vio)
734{
735        DBG_ENTER("mysqlnd_vio::has_valid_stream");
736        DBG_INF_FMT("%p %p", vio, vio? vio->data->stream:NULL);
737        DBG_RETURN((vio && vio->data->stream)? TRUE: FALSE);
738}
739/* }}} */
740
741
742MYSQLND_CLASS_METHODS_START(mysqlnd_vio)
743        MYSQLND_METHOD(mysqlnd_vio, init),
744        MYSQLND_METHOD(mysqlnd_vio, dtor),
745
746        MYSQLND_METHOD(mysqlnd_vio, connect),
747
748        MYSQLND_METHOD(mysqlnd_vio, close_stream),
749        MYSQLND_METHOD(mysqlnd_vio, open_pipe),
750        MYSQLND_METHOD(mysqlnd_vio, open_tcp_or_unix),
751
752        MYSQLND_METHOD(mysqlnd_vio, get_stream),
753        MYSQLND_METHOD(mysqlnd_vio, set_stream),
754        MYSQLND_METHOD(mysqlnd_vio, has_valid_stream),
755        MYSQLND_METHOD(mysqlnd_vio, get_open_stream),
756
757        MYSQLND_METHOD(mysqlnd_vio, set_client_option),
758        MYSQLND_METHOD(mysqlnd_vio, post_connect_set_opt),
759
760        MYSQLND_METHOD(mysqlnd_vio, enable_ssl),
761        MYSQLND_METHOD(mysqlnd_vio, disable_ssl),
762
763        MYSQLND_METHOD(mysqlnd_vio, network_read),
764        MYSQLND_METHOD(mysqlnd_vio, network_write),
765
766        MYSQLND_METHOD(mysqlnd_vio, consume_uneaten_data),
767
768        MYSQLND_METHOD(mysqlnd_vio, free_contents),
769MYSQLND_CLASS_METHODS_END;
770
771
772/* {{{ mysqlnd_vio_init */
773PHPAPI MYSQLND_VIO *
774mysqlnd_vio_init(zend_bool persistent, MYSQLND_CLASS_METHODS_TYPE(mysqlnd_object_factory) *object_factory, MYSQLND_STATS * stats, MYSQLND_ERROR_INFO * error_info)
775{
776        MYSQLND_CLASS_METHODS_TYPE(mysqlnd_object_factory) *factory = object_factory? object_factory : &MYSQLND_CLASS_METHOD_TABLE_NAME(mysqlnd_object_factory);
777        MYSQLND_VIO * vio;
778        DBG_ENTER("mysqlnd_vio_init");
779        vio = factory->get_vio(persistent, stats, error_info);
780        DBG_RETURN(vio);
781}
782/* }}} */
783
784
785/* {{{ mysqlnd_vio_free */
786PHPAPI void
787mysqlnd_vio_free(MYSQLND_VIO * const vio, MYSQLND_STATS * stats, MYSQLND_ERROR_INFO * error_info)
788{
789        DBG_ENTER("mysqlnd_vio_free");
790        if (vio) {
791                vio->data->m.dtor(vio, stats, error_info);
792        }
793        DBG_VOID_RETURN;
794}
795/* }}} */
796
797
798/*
799 * Local variables:
800 * tab-width: 4
801 * c-basic-offset: 4
802 * End:
803 * vim600: noet sw=4 ts=4 fdm=marker
804 * vim<600: noet sw=4 ts=4
805 */
Note: See TracBrowser for help on using the repository browser.