123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794 |
- /*
- +----------------------------------------------------------------------+
- | Copyright (c) The PHP Group |
- +----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | https://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
- +----------------------------------------------------------------------+
- | Authors: Andrey Hristov <andrey@php.net> |
- | Ulf Wendel <uw@php.net> |
- +----------------------------------------------------------------------+
- */
- #include "php.h"
- #include "mysqlnd.h"
- #include "mysqlnd_priv.h"
- #include "mysqlnd_statistics.h"
- #include "mysqlnd_debug.h"
- #include "mysqlnd_ext_plugin.h"
- #include "php_network.h"
- #ifndef PHP_WIN32
- #include <netinet/tcp.h>
- #else
- #include <winsock.h>
- #endif
- /* {{{ mysqlnd_set_sock_no_delay */
- static int
- mysqlnd_set_sock_no_delay(php_stream * stream)
- {
- int socketd = ((php_netstream_data_t*)stream->abstract)->socket;
- int ret = SUCCESS;
- int flag = 1;
- int result = setsockopt(socketd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int));
- DBG_ENTER("mysqlnd_set_sock_no_delay");
- if (result == -1) {
- ret = FAILURE;
- }
- DBG_RETURN(ret);
- }
- /* }}} */
- /* {{{ mysqlnd_set_sock_keepalive */
- static int
- mysqlnd_set_sock_keepalive(php_stream * stream)
- {
- int socketd = ((php_netstream_data_t*)stream->abstract)->socket;
- int ret = SUCCESS;
- int flag = 1;
- int result = setsockopt(socketd, SOL_SOCKET, SO_KEEPALIVE, (char *) &flag, sizeof(int));
- DBG_ENTER("mysqlnd_set_sock_keepalive");
- if (result == -1) {
- ret = FAILURE;
- }
- DBG_RETURN(ret);
- }
- /* }}} */
- /* {{{ mysqlnd_vio::network_read */
- static enum_func_status
- MYSQLND_METHOD(mysqlnd_vio, network_read)(MYSQLND_VIO * const vio, zend_uchar * const buffer, const size_t count,
- MYSQLND_STATS * const stats, MYSQLND_ERROR_INFO * const error_info)
- {
- enum_func_status return_value = PASS;
- php_stream * net_stream = vio->data->m.get_stream(vio);
- size_t to_read = count;
- zend_uchar * p = buffer;
- DBG_ENTER("mysqlnd_vio::network_read");
- DBG_INF_FMT("count=%zu", count);
- while (to_read) {
- ssize_t ret = php_stream_read(net_stream, (char *) p, to_read);
- if (ret <= 0) {
- DBG_ERR_FMT("Error while reading header from socket");
- return_value = FAIL;
- break;
- }
- p += ret;
- to_read -= ret;
- }
- MYSQLND_INC_CONN_STATISTIC_W_VALUE(stats, STAT_BYTES_RECEIVED, count - to_read);
- DBG_RETURN(return_value);
- }
- /* }}} */
- /* {{{ mysqlnd_vio::network_write */
- static ssize_t
- MYSQLND_METHOD(mysqlnd_vio, network_write)(MYSQLND_VIO * const vio, const zend_uchar * const buffer, const size_t count,
- MYSQLND_STATS * const stats, MYSQLND_ERROR_INFO * const error_info)
- {
- ssize_t ret;
- DBG_ENTER("mysqlnd_vio::network_write");
- DBG_INF_FMT("sending %zu bytes", count);
- ret = php_stream_write(vio->data->m.get_stream(vio), (char *)buffer, count);
- DBG_RETURN(ret);
- }
- /* }}} */
- /* {{{ mysqlnd_vio::open_pipe */
- static php_stream *
- MYSQLND_METHOD(mysqlnd_vio, open_pipe)(MYSQLND_VIO * const vio, const MYSQLND_CSTRING scheme, const bool persistent,
- MYSQLND_STATS * const conn_stats, MYSQLND_ERROR_INFO * const error_info)
- {
- unsigned int streams_options = 0;
- dtor_func_t origin_dtor;
- php_stream * net_stream = NULL;
- DBG_ENTER("mysqlnd_vio::open_pipe");
- if (persistent) {
- streams_options |= STREAM_OPEN_PERSISTENT;
- }
- streams_options |= IGNORE_URL;
- net_stream = php_stream_open_wrapper(scheme.s + sizeof("pipe://") - 1, "r+", streams_options, NULL);
- if (!net_stream) {
- SET_CLIENT_ERROR(error_info, CR_CONNECTION_ERROR, UNKNOWN_SQLSTATE, "Unknown error while connecting");
- DBG_RETURN(NULL);
- }
- /*
- Streams are not meant for C extensions! Thus we need a hack. Every connected stream will
- be registered as resource (in EG(regular_list). So far, so good. However, it won't be
- unregistered until the script ends. So, we need to take care of that.
- */
- origin_dtor = EG(regular_list).pDestructor;
- EG(regular_list).pDestructor = NULL;
- zend_hash_index_del(&EG(regular_list), net_stream->res->handle); /* ToDO: should it be res->handle, do streams register with addref ?*/
- EG(regular_list).pDestructor = origin_dtor;
- net_stream->res = NULL;
- DBG_RETURN(net_stream);
- }
- /* }}} */
- /* {{{ mysqlnd_vio::open_tcp_or_unix */
- static php_stream *
- MYSQLND_METHOD(mysqlnd_vio, open_tcp_or_unix)(MYSQLND_VIO * const vio, const MYSQLND_CSTRING scheme, const bool persistent,
- MYSQLND_STATS * const conn_stats, MYSQLND_ERROR_INFO * const error_info)
- {
- unsigned int streams_options = 0;
- unsigned int streams_flags = STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT;
- char * hashed_details = NULL;
- int hashed_details_len = 0;
- zend_string *errstr = NULL;
- int errcode = 0;
- struct timeval tv;
- dtor_func_t origin_dtor;
- php_stream * net_stream = NULL;
- DBG_ENTER("mysqlnd_vio::open_tcp_or_unix");
- vio->data->stream = NULL;
- if (persistent) {
- hashed_details_len = mnd_sprintf(&hashed_details, 0, "%p", vio);
- DBG_INF_FMT("hashed_details=%s", hashed_details);
- }
- if (vio->data->options.timeout_connect) {
- tv.tv_sec = vio->data->options.timeout_connect;
- tv.tv_usec = 0;
- }
- DBG_INF_FMT("calling php_stream_xport_create");
- net_stream = php_stream_xport_create(scheme.s, scheme.l, streams_options, streams_flags,
- hashed_details, (vio->data->options.timeout_connect) ? &tv : NULL,
- NULL /*ctx*/, &errstr, &errcode);
- if (errstr || !net_stream) {
- DBG_ERR("Error");
- if (hashed_details) {
- mnd_sprintf_free(hashed_details);
- }
- errcode = CR_CONNECTION_ERROR;
- SET_CLIENT_ERROR(error_info,
- CR_CONNECTION_ERROR,
- UNKNOWN_SQLSTATE,
- errstr? ZSTR_VAL(errstr):"Unknown error while connecting");
- if (errstr) {
- zend_string_release_ex(errstr, 0);
- }
- DBG_RETURN(NULL);
- }
- if (hashed_details) {
- /*
- If persistent, the streams register it in EG(persistent_list).
- This is unwanted. ext/mysql or ext/mysqli are responsible to clean,
- whatever they have to.
- */
- zend_resource *le;
- if ((le = zend_hash_str_find_ptr(&EG(persistent_list), hashed_details, hashed_details_len))) {
- origin_dtor = EG(persistent_list).pDestructor;
- /*
- in_free will let streams code skip destructing - big HACK,
- but STREAMS suck big time regarding persistent streams.
- Just not compatible for extensions that need persistency.
- */
- EG(persistent_list).pDestructor = NULL;
- zend_hash_str_del(&EG(persistent_list), hashed_details, hashed_details_len);
- EG(persistent_list).pDestructor = origin_dtor;
- pefree(le, 1);
- }
- #if ZEND_DEBUG
- /* Shut-up the streams, they don't know what they are doing */
- net_stream->__exposed = 1;
- #endif
- mnd_sprintf_free(hashed_details);
- }
- /*
- Streams are not meant for C extensions! Thus we need a hack. Every connected stream will
- be registered as resource (in EG(regular_list). So far, so good. However, it won't be
- unregistered until the script ends. So, we need to take care of that.
- */
- origin_dtor = EG(regular_list).pDestructor;
- EG(regular_list).pDestructor = NULL;
- zend_hash_index_del(&EG(regular_list), net_stream->res->handle); /* ToDO: should it be res->handle, do streams register with addref ?*/
- efree(net_stream->res);
- net_stream->res = NULL;
- EG(regular_list).pDestructor = origin_dtor;
- DBG_RETURN(net_stream);
- }
- /* }}} */
- /* {{{ mysqlnd_vio::post_connect_set_opt */
- static void
- MYSQLND_METHOD(mysqlnd_vio, post_connect_set_opt)(MYSQLND_VIO * const vio, const MYSQLND_CSTRING scheme,
- MYSQLND_STATS * const conn_stats, MYSQLND_ERROR_INFO * const error_info)
- {
- php_stream * net_stream = vio->data->m.get_stream(vio);
- DBG_ENTER("mysqlnd_vio::post_connect_set_opt");
- if (net_stream) {
- if (vio->data->options.timeout_read) {
- struct timeval tv;
- DBG_INF_FMT("setting %u as PHP_STREAM_OPTION_READ_TIMEOUT", vio->data->options.timeout_read);
- tv.tv_sec = vio->data->options.timeout_read;
- tv.tv_usec = 0;
- php_stream_set_option(net_stream, PHP_STREAM_OPTION_READ_TIMEOUT, 0, &tv);
- }
- if (!memcmp(scheme.s, "tcp://", sizeof("tcp://") - 1)) {
- /* TCP -> Set TCP_NODELAY */
- mysqlnd_set_sock_no_delay(net_stream);
- /* TCP -> Set SO_KEEPALIVE */
- mysqlnd_set_sock_keepalive(net_stream);
- }
- net_stream->chunk_size = vio->data->options.net_read_buffer_size;
- net_stream->flags |= PHP_STREAM_FLAG_SUPPRESS_ERRORS;
- }
- DBG_VOID_RETURN;
- }
- /* }}} */
- /* {{{ mysqlnd_vio::get_open_stream */
- static func_mysqlnd_vio__open_stream
- MYSQLND_METHOD(mysqlnd_vio, get_open_stream)(MYSQLND_VIO * const vio, const MYSQLND_CSTRING scheme,
- MYSQLND_ERROR_INFO * const error_info)
- {
- func_mysqlnd_vio__open_stream ret = NULL;
- DBG_ENTER("mysqlnd_vio::get_open_stream");
- if (scheme.l > (sizeof("pipe://") - 1) && !memcmp(scheme.s, "pipe://", sizeof("pipe://") - 1)) {
- ret = vio->data->m.open_pipe;
- } else if ((scheme.l > (sizeof("tcp://") - 1) && !memcmp(scheme.s, "tcp://", sizeof("tcp://") - 1))
- ||
- (scheme.l > (sizeof("unix://") - 1) && !memcmp(scheme.s, "unix://", sizeof("unix://") - 1)))
- {
- ret = vio->data->m.open_tcp_or_unix;
- }
- if (!ret) {
- SET_CLIENT_ERROR(error_info, CR_CONNECTION_ERROR, UNKNOWN_SQLSTATE, "No handler for this scheme");
- }
- DBG_RETURN(ret);
- }
- /* }}} */
- /* {{{ mysqlnd_vio::connect */
- static enum_func_status
- MYSQLND_METHOD(mysqlnd_vio, connect)(MYSQLND_VIO * const vio, const MYSQLND_CSTRING scheme, const bool persistent,
- MYSQLND_STATS * const conn_stats, MYSQLND_ERROR_INFO * const error_info)
- {
- enum_func_status ret = FAIL;
- func_mysqlnd_vio__open_stream open_stream = NULL;
- DBG_ENTER("mysqlnd_vio::connect");
- vio->data->m.close_stream(vio, conn_stats, error_info);
- open_stream = vio->data->m.get_open_stream(vio, scheme, error_info);
- if (open_stream) {
- php_stream * net_stream = open_stream(vio, scheme, persistent, conn_stats, error_info);
- if (net_stream && PASS == vio->data->m.set_stream(vio, net_stream)) {
- vio->data->m.post_connect_set_opt(vio, scheme, conn_stats, error_info);
- ret = PASS;
- }
- }
- DBG_RETURN(ret);
- }
- /* }}} */
- /* {{{ mysqlnd_vio::set_client_option */
- static enum_func_status
- MYSQLND_METHOD(mysqlnd_vio, set_client_option)(MYSQLND_VIO * const net, enum_mysqlnd_client_option option, const char * const value)
- {
- DBG_ENTER("mysqlnd_vio::set_client_option");
- DBG_INF_FMT("option=%u", option);
- switch (option) {
- case MYSQLND_OPT_NET_READ_BUFFER_SIZE:
- DBG_INF("MYSQLND_OPT_NET_READ_BUFFER_SIZE");
- net->data->options.net_read_buffer_size = *(unsigned int*) value;
- DBG_INF_FMT("new_length=%zu", net->data->options.net_read_buffer_size);
- break;
- case MYSQL_OPT_CONNECT_TIMEOUT:
- DBG_INF("MYSQL_OPT_CONNECT_TIMEOUT");
- net->data->options.timeout_connect = *(unsigned int*) value;
- break;
- case MYSQLND_OPT_SSL_KEY:
- {
- bool pers = net->persistent;
- if (net->data->options.ssl_key) {
- mnd_pefree(net->data->options.ssl_key, pers);
- }
- net->data->options.ssl_key = value? mnd_pestrdup(value, pers) : NULL;
- break;
- }
- case MYSQLND_OPT_SSL_CERT:
- {
- bool pers = net->persistent;
- if (net->data->options.ssl_cert) {
- mnd_pefree(net->data->options.ssl_cert, pers);
- }
- net->data->options.ssl_cert = value? mnd_pestrdup(value, pers) : NULL;
- break;
- }
- case MYSQLND_OPT_SSL_CA:
- {
- bool pers = net->persistent;
- if (net->data->options.ssl_ca) {
- mnd_pefree(net->data->options.ssl_ca, pers);
- }
- net->data->options.ssl_ca = value? mnd_pestrdup(value, pers) : NULL;
- break;
- }
- case MYSQLND_OPT_SSL_CAPATH:
- {
- bool pers = net->persistent;
- if (net->data->options.ssl_capath) {
- mnd_pefree(net->data->options.ssl_capath, pers);
- }
- net->data->options.ssl_capath = value? mnd_pestrdup(value, pers) : NULL;
- break;
- }
- case MYSQLND_OPT_SSL_CIPHER:
- {
- bool pers = net->persistent;
- if (net->data->options.ssl_cipher) {
- mnd_pefree(net->data->options.ssl_cipher, pers);
- }
- net->data->options.ssl_cipher = value? mnd_pestrdup(value, pers) : NULL;
- break;
- }
- case MYSQLND_OPT_SSL_PASSPHRASE:
- {
- bool pers = net->persistent;
- if (net->data->options.ssl_passphrase) {
- mnd_pefree(net->data->options.ssl_passphrase, pers);
- }
- net->data->options.ssl_passphrase = value? mnd_pestrdup(value, pers) : NULL;
- break;
- }
- case MYSQL_OPT_SSL_VERIFY_SERVER_CERT:
- {
- enum mysqlnd_ssl_peer val = *((enum mysqlnd_ssl_peer *)value);
- switch (val) {
- case MYSQLND_SSL_PEER_VERIFY:
- DBG_INF("MYSQLND_SSL_PEER_VERIFY");
- break;
- case MYSQLND_SSL_PEER_DONT_VERIFY:
- DBG_INF("MYSQLND_SSL_PEER_DONT_VERIFY");
- break;
- case MYSQLND_SSL_PEER_DEFAULT:
- DBG_INF("MYSQLND_SSL_PEER_DEFAULT");
- val = MYSQLND_SSL_PEER_DEFAULT;
- break;
- default:
- DBG_INF("default = MYSQLND_SSL_PEER_DEFAULT_ACTION");
- val = MYSQLND_SSL_PEER_DEFAULT;
- break;
- }
- net->data->options.ssl_verify_peer = val;
- break;
- }
- case MYSQL_OPT_READ_TIMEOUT:
- net->data->options.timeout_read = *(unsigned int*) value;
- break;
- #ifdef WHEN_SUPPORTED_BY_MYSQLI
- case MYSQL_OPT_WRITE_TIMEOUT:
- net->data->options.timeout_write = *(unsigned int*) value;
- break;
- #endif
- default:
- DBG_RETURN(FAIL);
- }
- DBG_RETURN(PASS);
- }
- /* }}} */
- /* {{{ mysqlnd_vio::consume_uneaten_data */
- size_t
- MYSQLND_METHOD(mysqlnd_vio, consume_uneaten_data)(MYSQLND_VIO * const net, enum php_mysqlnd_server_command cmd)
- {
- #ifdef MYSQLND_DO_WIRE_CHECK_BEFORE_COMMAND
- /*
- Switch to non-blocking mode and try to consume something from
- the line, if possible, then continue. This saves us from looking for
- the actual place where out-of-order packets have been sent.
- If someone is completely sure that everything is fine, he can switch it
- off.
- */
- char tmp_buf[256];
- size_t skipped_bytes = 0;
- int opt = PHP_STREAM_OPTION_BLOCKING;
- php_stream * net_stream = net->data->get_stream(net);
- int was_blocked = net_stream->ops->set_option(net_stream, opt, 0, NULL);
- DBG_ENTER("mysqlnd_vio::consume_uneaten_data");
- if (PHP_STREAM_OPTION_RETURN_ERR != was_blocked) {
- /* Do a read of 1 byte */
- ssize_t bytes_consumed;
- do {
- bytes_consumed = php_stream_read(net_stream, tmp_buf, sizeof(tmp_buf));
- if (bytes_consumed <= 0) {
- break;
- }
- skipped_bytes += bytes_consumed;
- } while (bytes_consumed == sizeof(tmp_buf));
- if (was_blocked) {
- net_stream->ops->set_option(net_stream, opt, 1, NULL);
- }
- if (bytes_consumed) {
- DBG_ERR_FMT("Skipped %u bytes. Last command hasn't consumed all the output from the server",
- bytes_consumed, mysqlnd_command_to_text[net->last_command]);
- php_error_docref(NULL, E_WARNING, "Skipped %u bytes. Last command %s hasn't "
- "consumed all the output from the server",
- bytes_consumed, mysqlnd_command_to_text[net->last_command]);
- }
- }
- net->last_command = cmd;
- DBG_RETURN(skipped_bytes);
- #else
- return 0;
- #endif
- }
- /* }}} */
- /*
- in libmyusql, if cert and !key then key=cert
- */
- /* {{{ mysqlnd_vio::enable_ssl */
- static enum_func_status
- MYSQLND_METHOD(mysqlnd_vio, enable_ssl)(MYSQLND_VIO * const net)
- {
- #ifdef MYSQLND_SSL_SUPPORTED
- php_stream_context * context = php_stream_context_alloc();
- php_stream * net_stream = net->data->m.get_stream(net);
- bool any_flag = FALSE;
- DBG_ENTER("mysqlnd_vio::enable_ssl");
- if (net->data->options.ssl_key) {
- zval key_zval;
- ZVAL_STRING(&key_zval, net->data->options.ssl_key);
- php_stream_context_set_option(context, "ssl", "local_pk", &key_zval);
- zval_ptr_dtor(&key_zval);
- any_flag = TRUE;
- }
- if (net->data->options.ssl_cert) {
- zval cert_zval;
- ZVAL_STRING(&cert_zval, net->data->options.ssl_cert);
- php_stream_context_set_option(context, "ssl", "local_cert", &cert_zval);
- if (!net->data->options.ssl_key) {
- php_stream_context_set_option(context, "ssl", "local_pk", &cert_zval);
- }
- zval_ptr_dtor(&cert_zval);
- any_flag = TRUE;
- }
- if (net->data->options.ssl_ca) {
- zval cafile_zval;
- ZVAL_STRING(&cafile_zval, net->data->options.ssl_ca);
- php_stream_context_set_option(context, "ssl", "cafile", &cafile_zval);
- zval_ptr_dtor(&cafile_zval);
- any_flag = TRUE;
- }
- if (net->data->options.ssl_capath) {
- zval capath_zval;
- ZVAL_STRING(&capath_zval, net->data->options.ssl_capath);
- php_stream_context_set_option(context, "ssl", "capath", &capath_zval);
- zval_ptr_dtor(&capath_zval);
- any_flag = TRUE;
- }
- if (net->data->options.ssl_passphrase) {
- zval passphrase_zval;
- ZVAL_STRING(&passphrase_zval, net->data->options.ssl_passphrase);
- php_stream_context_set_option(context, "ssl", "passphrase", &passphrase_zval);
- zval_ptr_dtor(&passphrase_zval);
- any_flag = TRUE;
- }
- if (net->data->options.ssl_cipher) {
- zval cipher_zval;
- ZVAL_STRING(&cipher_zval, net->data->options.ssl_cipher);
- php_stream_context_set_option(context, "ssl", "ciphers", &cipher_zval);
- zval_ptr_dtor(&cipher_zval);
- any_flag = TRUE;
- }
- {
- zval verify_peer_zval;
- bool verify;
- if (net->data->options.ssl_verify_peer == MYSQLND_SSL_PEER_DEFAULT) {
- net->data->options.ssl_verify_peer = any_flag? MYSQLND_SSL_PEER_DEFAULT_ACTION:MYSQLND_SSL_PEER_DONT_VERIFY;
- }
- verify = net->data->options.ssl_verify_peer == MYSQLND_SSL_PEER_VERIFY? TRUE:FALSE;
- DBG_INF_FMT("VERIFY=%d", verify);
- ZVAL_BOOL(&verify_peer_zval, verify);
- php_stream_context_set_option(context, "ssl", "verify_peer", &verify_peer_zval);
- php_stream_context_set_option(context, "ssl", "verify_peer_name", &verify_peer_zval);
- if (net->data->options.ssl_verify_peer == MYSQLND_SSL_PEER_DONT_VERIFY) {
- ZVAL_TRUE(&verify_peer_zval);
- php_stream_context_set_option(context, "ssl", "allow_self_signed", &verify_peer_zval);
- }
- }
- php_stream_context_set(net_stream, context);
- if (php_stream_xport_crypto_setup(net_stream, STREAM_CRYPTO_METHOD_TLS_CLIENT, NULL) < 0 ||
- php_stream_xport_crypto_enable(net_stream, 1) < 0)
- {
- DBG_ERR("Cannot connect to MySQL by using SSL");
- php_error_docref(NULL, E_WARNING, "Cannot connect to MySQL by using SSL");
- DBG_RETURN(FAIL);
- }
- net->data->ssl = TRUE;
- /*
- get rid of the context. we are persistent and if this is a real pconn used by mysql/mysqli,
- then the context would not survive cleaning of EG(regular_list), where it is registered, as a
- resource. What happens is that after this destruction any use of the network will mean usage
- of the context, which means usage of already freed memory, bad. Actually we don't need this
- context anymore after we have enabled SSL on the connection. Thus it is very simple, we remove it.
- */
- php_stream_context_set(net_stream, NULL);
- if (net->data->options.timeout_read) {
- struct timeval tv;
- DBG_INF_FMT("setting %u as PHP_STREAM_OPTION_READ_TIMEOUT", net->data->options.timeout_read);
- tv.tv_sec = net->data->options.timeout_read;
- tv.tv_usec = 0;
- php_stream_set_option(net_stream, PHP_STREAM_OPTION_READ_TIMEOUT, 0, &tv);
- }
- DBG_RETURN(PASS);
- #else
- DBG_ENTER("mysqlnd_vio::enable_ssl");
- DBG_INF("MYSQLND_SSL_SUPPORTED is not defined");
- DBG_RETURN(PASS);
- #endif
- }
- /* }}} */
- /* {{{ mysqlnd_vio::disable_ssl */
- static enum_func_status
- MYSQLND_METHOD(mysqlnd_vio, disable_ssl)(MYSQLND_VIO * const vio)
- {
- DBG_ENTER("mysqlnd_vio::disable_ssl");
- DBG_RETURN(PASS);
- }
- /* }}} */
- /* {{{ mysqlnd_vio::free_contents */
- static void
- MYSQLND_METHOD(mysqlnd_vio, free_contents)(MYSQLND_VIO * net)
- {
- bool pers = net->persistent;
- DBG_ENTER("mysqlnd_vio::free_contents");
- if (net->data->options.ssl_key) {
- mnd_pefree(net->data->options.ssl_key, pers);
- net->data->options.ssl_key = NULL;
- }
- if (net->data->options.ssl_cert) {
- mnd_pefree(net->data->options.ssl_cert, pers);
- net->data->options.ssl_cert = NULL;
- }
- if (net->data->options.ssl_ca) {
- mnd_pefree(net->data->options.ssl_ca, pers);
- net->data->options.ssl_ca = NULL;
- }
- if (net->data->options.ssl_capath) {
- mnd_pefree(net->data->options.ssl_capath, pers);
- net->data->options.ssl_capath = NULL;
- }
- if (net->data->options.ssl_cipher) {
- mnd_pefree(net->data->options.ssl_cipher, pers);
- net->data->options.ssl_cipher = NULL;
- }
- DBG_VOID_RETURN;
- }
- /* }}} */
- /* {{{ mysqlnd_vio::close_stream */
- static void
- MYSQLND_METHOD(mysqlnd_vio, close_stream)(MYSQLND_VIO * const net, MYSQLND_STATS * const stats, MYSQLND_ERROR_INFO * const error_info)
- {
- php_stream * net_stream;
- DBG_ENTER("mysqlnd_vio::close_stream");
- if (net && (net_stream = net->data->m.get_stream(net))) {
- bool pers = net->persistent;
- DBG_INF_FMT("Freeing stream. abstract=%p", net_stream->abstract);
- /* We removed the resource from the stream, so pass FREE_RSRC_DTOR now to force
- * destruction to occur during shutdown, because it won't happen through the resource. */
- /* TODO: The EG(active) check here is dead -- check IN_SHUTDOWN? */
- if (pers && EG(active)) {
- php_stream_free(net_stream, PHP_STREAM_FREE_CLOSE_PERSISTENT | PHP_STREAM_FREE_RSRC_DTOR);
- } else {
- /*
- otherwise we will crash because the EG(persistent_list) has been freed already,
- before the modules are shut down
- */
- php_stream_free(net_stream, PHP_STREAM_FREE_CLOSE | PHP_STREAM_FREE_RSRC_DTOR);
- }
- net->data->m.set_stream(net, NULL);
- }
- DBG_VOID_RETURN;
- }
- /* }}} */
- /* {{{ mysqlnd_vio::init */
- static enum_func_status
- MYSQLND_METHOD(mysqlnd_vio, init)(MYSQLND_VIO * const net, MYSQLND_STATS * const stats, MYSQLND_ERROR_INFO * const error_info)
- {
- unsigned int buf_size;
- DBG_ENTER("mysqlnd_vio::init");
- buf_size = MYSQLND_G(net_read_buffer_size); /* this is long, cast to unsigned int*/
- net->data->m.set_client_option(net, MYSQLND_OPT_NET_READ_BUFFER_SIZE, (char *)&buf_size);
- buf_size = MYSQLND_G(net_read_timeout); /* this is long, cast to unsigned int*/
- net->data->m.set_client_option(net, MYSQL_OPT_READ_TIMEOUT, (char *)&buf_size);
- DBG_RETURN(PASS);
- }
- /* }}} */
- /* {{{ mysqlnd_vio::dtor */
- static void
- MYSQLND_METHOD(mysqlnd_vio, dtor)(MYSQLND_VIO * const vio, MYSQLND_STATS * const stats, MYSQLND_ERROR_INFO * const error_info)
- {
- DBG_ENTER("mysqlnd_vio::dtor");
- if (vio) {
- vio->data->m.free_contents(vio);
- vio->data->m.close_stream(vio, stats, error_info);
- mnd_pefree(vio, vio->persistent);
- }
- DBG_VOID_RETURN;
- }
- /* }}} */
- /* {{{ mysqlnd_vio::get_stream */
- static php_stream *
- MYSQLND_METHOD(mysqlnd_vio, get_stream)(const MYSQLND_VIO * const net)
- {
- DBG_ENTER("mysqlnd_vio::get_stream");
- DBG_INF_FMT("%p", net? net->data->stream:NULL);
- DBG_RETURN(net? net->data->stream:NULL);
- }
- /* }}} */
- /* {{{ mysqlnd_vio::set_stream */
- static enum_func_status
- MYSQLND_METHOD(mysqlnd_vio, set_stream)(MYSQLND_VIO * const vio, php_stream * net_stream)
- {
- DBG_ENTER("mysqlnd_vio::set_stream");
- if (vio) {
- vio->data->stream = net_stream;
- DBG_RETURN(PASS);
- }
- DBG_RETURN(FAIL);
- }
- /* }}} */
- /* {{{ mysqlnd_vio::has_valid_stream */
- static bool
- MYSQLND_METHOD(mysqlnd_vio, has_valid_stream)(const MYSQLND_VIO * const vio)
- {
- DBG_ENTER("mysqlnd_vio::has_valid_stream");
- DBG_INF_FMT("%p %p", vio, vio? vio->data->stream:NULL);
- DBG_RETURN((vio && vio->data->stream)? TRUE: FALSE);
- }
- /* }}} */
- MYSQLND_CLASS_METHODS_START(mysqlnd_vio)
- MYSQLND_METHOD(mysqlnd_vio, init),
- MYSQLND_METHOD(mysqlnd_vio, dtor),
- MYSQLND_METHOD(mysqlnd_vio, connect),
- MYSQLND_METHOD(mysqlnd_vio, close_stream),
- MYSQLND_METHOD(mysqlnd_vio, open_pipe),
- MYSQLND_METHOD(mysqlnd_vio, open_tcp_or_unix),
- MYSQLND_METHOD(mysqlnd_vio, get_stream),
- MYSQLND_METHOD(mysqlnd_vio, set_stream),
- MYSQLND_METHOD(mysqlnd_vio, has_valid_stream),
- MYSQLND_METHOD(mysqlnd_vio, get_open_stream),
- MYSQLND_METHOD(mysqlnd_vio, set_client_option),
- MYSQLND_METHOD(mysqlnd_vio, post_connect_set_opt),
- MYSQLND_METHOD(mysqlnd_vio, enable_ssl),
- MYSQLND_METHOD(mysqlnd_vio, disable_ssl),
- MYSQLND_METHOD(mysqlnd_vio, network_read),
- MYSQLND_METHOD(mysqlnd_vio, network_write),
- MYSQLND_METHOD(mysqlnd_vio, consume_uneaten_data),
- MYSQLND_METHOD(mysqlnd_vio, free_contents),
- MYSQLND_CLASS_METHODS_END;
- /* {{{ mysqlnd_vio_init */
- PHPAPI MYSQLND_VIO *
- mysqlnd_vio_init(bool persistent, MYSQLND_CLASS_METHODS_TYPE(mysqlnd_object_factory) *object_factory, MYSQLND_STATS * stats, MYSQLND_ERROR_INFO * error_info)
- {
- MYSQLND_CLASS_METHODS_TYPE(mysqlnd_object_factory) *factory = object_factory? object_factory : &MYSQLND_CLASS_METHOD_TABLE_NAME(mysqlnd_object_factory);
- MYSQLND_VIO * vio;
- DBG_ENTER("mysqlnd_vio_init");
- vio = factory->get_vio(persistent, stats, error_info);
- DBG_RETURN(vio);
- }
- /* }}} */
- /* {{{ mysqlnd_vio_free */
- PHPAPI void
- mysqlnd_vio_free(MYSQLND_VIO * const vio, MYSQLND_STATS * stats, MYSQLND_ERROR_INFO * error_info)
- {
- DBG_ENTER("mysqlnd_vio_free");
- if (vio) {
- vio->data->m.dtor(vio, stats, error_info);
- }
- DBG_VOID_RETURN;
- }
- /* }}} */
|