From fda5fbe2bcae69c35427ac9d7013b292398ab1d0 Mon Sep 17 00:00:00 2001 From: Qianqian Bu Date: Tue, 11 Feb 2020 11:20:34 +0800 Subject: [PATCH 01/10] tab to space for better format --- mysqlnd_azure.c | 840 ++++++++++++++++++++++++------------------------ 1 file changed, 420 insertions(+), 420 deletions(-) diff --git a/mysqlnd_azure.c b/mysqlnd_azure.c index c12625c..1c6aecd 100644 --- a/mysqlnd_azure.c +++ b/mysqlnd_azure.c @@ -39,121 +39,121 @@ struct st_mysqlnd_conn_methods* conn_m; static enum_func_status set_redirect_client_options(MYSQLND_CONN_DATA * const conn, MYSQLND_CONN_DATA * const redirectConn) { - //TODO: the fields copies here are from list that is handled in mysqlnd_conn_data::set_client_option, may not compelete, and may need update when mysqlnd_conn_data::set_client_option updates - DBG_ENTER("mysqlnd_azure_data::set_redirect_client_options Copy client options for redirection connection"); - enum_func_status ret = FAIL; + //TODO: the fields copies here are from list that is handled in mysqlnd_conn_data::set_client_option, may not compelete, and may need update when mysqlnd_conn_data::set_client_option updates + DBG_ENTER("mysqlnd_azure_data::set_redirect_client_options Copy client options for redirection connection"); + enum_func_status ret = FAIL; - redirectConn->client_api_capabilities = conn->client_api_capabilities; + redirectConn->client_api_capabilities = conn->client_api_capabilities; - redirectConn->vio->data->ssl = conn->vio->data->ssl; - redirectConn->vio->data->options.timeout_read = conn->vio->data->options.timeout_read; - redirectConn->vio->data->options.timeout_write = conn->vio->data->options.timeout_write; - redirectConn->vio->data->options.timeout_connect = conn->vio->data->options.timeout_connect; - redirectConn->vio->data->options.ssl_verify_peer = conn->vio->data->options.ssl_verify_peer; + redirectConn->vio->data->ssl = conn->vio->data->ssl; + redirectConn->vio->data->options.timeout_read = conn->vio->data->options.timeout_read; + redirectConn->vio->data->options.timeout_write = conn->vio->data->options.timeout_write; + redirectConn->vio->data->options.timeout_connect = conn->vio->data->options.timeout_connect; + redirectConn->vio->data->options.ssl_verify_peer = conn->vio->data->options.ssl_verify_peer; - ret = redirectConn->vio->data->m.set_client_option(redirectConn->vio, MYSQLND_OPT_SSL_KEY, conn->vio->data->options.ssl_key); - if (ret == FAIL) goto copyFailed; + ret = redirectConn->vio->data->m.set_client_option(redirectConn->vio, MYSQLND_OPT_SSL_KEY, conn->vio->data->options.ssl_key); + if (ret == FAIL) goto copyFailed; - ret = redirectConn->vio->data->m.set_client_option(redirectConn->vio, MYSQLND_OPT_SSL_CERT, conn->vio->data->options.ssl_cert); - if (ret == FAIL) goto copyFailed; + ret = redirectConn->vio->data->m.set_client_option(redirectConn->vio, MYSQLND_OPT_SSL_CERT, conn->vio->data->options.ssl_cert); + if (ret == FAIL) goto copyFailed; - ret = redirectConn->vio->data->m.set_client_option(redirectConn->vio, MYSQLND_OPT_SSL_CA, conn->vio->data->options.ssl_ca); - if (ret == FAIL) goto copyFailed; + ret = redirectConn->vio->data->m.set_client_option(redirectConn->vio, MYSQLND_OPT_SSL_CA, conn->vio->data->options.ssl_ca); + if (ret == FAIL) goto copyFailed; - ret = redirectConn->vio->data->m.set_client_option(redirectConn->vio, MYSQLND_OPT_SSL_CAPATH, conn->vio->data->options.ssl_capath); - if (ret == FAIL) goto copyFailed; + ret = redirectConn->vio->data->m.set_client_option(redirectConn->vio, MYSQLND_OPT_SSL_CAPATH, conn->vio->data->options.ssl_capath); + if (ret == FAIL) goto copyFailed; - ret = redirectConn->vio->data->m.set_client_option(redirectConn->vio, MYSQLND_OPT_SSL_CIPHER, conn->vio->data->options.ssl_cipher); - if (ret == FAIL) goto copyFailed; + ret = redirectConn->vio->data->m.set_client_option(redirectConn->vio, MYSQLND_OPT_SSL_CIPHER, conn->vio->data->options.ssl_cipher); + if (ret == FAIL) goto copyFailed; - ret = redirectConn->vio->data->m.set_client_option(redirectConn->vio, MYSQLND_OPT_NET_READ_BUFFER_SIZE, (const char *)&conn->vio->data->options.net_read_buffer_size); - if (ret == FAIL) goto copyFailed; + ret = redirectConn->vio->data->m.set_client_option(redirectConn->vio, MYSQLND_OPT_NET_READ_BUFFER_SIZE, (const char *)&conn->vio->data->options.net_read_buffer_size); + if (ret == FAIL) goto copyFailed; - ret = redirectConn->protocol_frame_codec->data->m.set_client_option(redirectConn->protocol_frame_codec, MYSQLND_OPT_NET_CMD_BUFFER_SIZE, (const char *)&conn->protocol_frame_codec->cmd_buffer.length); - if (ret == FAIL) goto copyFailed; + ret = redirectConn->protocol_frame_codec->data->m.set_client_option(redirectConn->protocol_frame_codec, MYSQLND_OPT_NET_CMD_BUFFER_SIZE, (const char *)&conn->protocol_frame_codec->cmd_buffer.length); + if (ret == FAIL) goto copyFailed; - //MYSQL_OPT_COMPRESS - if (conn->protocol_frame_codec->data->flags & MYSQLND_PROTOCOL_FLAG_USE_COMPRESSION) { - redirectConn->protocol_frame_codec->data->flags |= MYSQLND_PROTOCOL_FLAG_USE_COMPRESSION; - } - else { - redirectConn->protocol_frame_codec->data->flags &= ~MYSQLND_PROTOCOL_FLAG_USE_COMPRESSION; - } + //MYSQL_OPT_COMPRESS + if (conn->protocol_frame_codec->data->flags & MYSQLND_PROTOCOL_FLAG_USE_COMPRESSION) { + redirectConn->protocol_frame_codec->data->flags |= MYSQLND_PROTOCOL_FLAG_USE_COMPRESSION; + } + else { + redirectConn->protocol_frame_codec->data->flags &= ~MYSQLND_PROTOCOL_FLAG_USE_COMPRESSION; + } - ret = redirectConn->protocol_frame_codec->data->m.set_client_option(redirectConn->protocol_frame_codec, MYSQL_SERVER_PUBLIC_KEY, conn->protocol_frame_codec->data->sha256_server_public_key); - if (ret == FAIL) goto copyFailed; + ret = redirectConn->protocol_frame_codec->data->m.set_client_option(redirectConn->protocol_frame_codec, MYSQL_SERVER_PUBLIC_KEY, conn->protocol_frame_codec->data->sha256_server_public_key); + if (ret == FAIL) goto copyFailed; #ifdef MYSQLND_STRING_TO_INT_CONVERSION - redirectConn->options->int_and_float_native = conn->options->int_and_float_native; + redirectConn->options->int_and_float_native = conn->options->int_and_float_native; #endif - redirectConn->options->flags = conn->options->flags; + redirectConn->options->flags = conn->options->flags; - //MYSQL_INIT_COMMAND: - { - if (redirectConn->options->num_commands) { - unsigned int i; - for (i = 0; i < redirectConn->options->num_commands; i++) { - /* allocated with pestrdup */ - mnd_pefree(redirectConn->options->init_commands[i], redirectConn->persistent); - } - mnd_pefree(redirectConn->options->init_commands, redirectConn->persistent); - redirectConn->options->init_commands = NULL; - } + //MYSQL_INIT_COMMAND: + { + if (redirectConn->options->num_commands) { + unsigned int i; + for (i = 0; i < redirectConn->options->num_commands; i++) { + /* allocated with pestrdup */ + mnd_pefree(redirectConn->options->init_commands[i], redirectConn->persistent); + } + mnd_pefree(redirectConn->options->init_commands, redirectConn->persistent); + redirectConn->options->init_commands = NULL; + } - if (conn->options->num_commands) - { - char ** new_init_commands; - new_init_commands = mnd_perealloc(redirectConn->options->init_commands, sizeof(char *) * (conn->options->num_commands), conn->persistent); - if (!new_init_commands) { - SET_OOM_ERROR(redirectConn->error_info); - goto copyFailed; - } - redirectConn->options->init_commands = new_init_commands; - unsigned int i; - char * new_command; - for (i = 0; i < conn->options->num_commands; i++) { - new_command = mnd_pestrdup(conn->options->init_commands[i], conn->persistent); - if (!new_command) { - SET_OOM_ERROR(redirectConn->error_info); - goto copyFailed; - } - redirectConn->options->init_commands[i] = new_command; - ++redirectConn->options->num_commands; - } - } - } + if (conn->options->num_commands) + { + char ** new_init_commands; + new_init_commands = mnd_perealloc(redirectConn->options->init_commands, sizeof(char *) * (conn->options->num_commands), conn->persistent); + if (!new_init_commands) { + SET_OOM_ERROR(redirectConn->error_info); + goto copyFailed; + } + redirectConn->options->init_commands = new_init_commands; + unsigned int i; + char * new_command; + for (i = 0; i < conn->options->num_commands; i++) { + new_command = mnd_pestrdup(conn->options->init_commands[i], conn->persistent); + if (!new_command) { + SET_OOM_ERROR(redirectConn->error_info); + goto copyFailed; + } + redirectConn->options->init_commands[i] = new_command; + ++redirectConn->options->num_commands; + } + } + } - if (conn->options->charset_name != NULL) { - ret = redirectConn->m->set_client_option(redirectConn, MYSQL_SET_CHARSET_NAME, conn->options->charset_name); - if (ret == FAIL) goto copyFailed; - } + if (conn->options->charset_name != NULL) { + ret = redirectConn->m->set_client_option(redirectConn, MYSQL_SET_CHARSET_NAME, conn->options->charset_name); + if (ret == FAIL) goto copyFailed; + } - redirectConn->options->protocol = conn->options->protocol; - redirectConn->options->max_allowed_packet = conn->options->max_allowed_packet; + redirectConn->options->protocol = conn->options->protocol; + redirectConn->options->max_allowed_packet = conn->options->max_allowed_packet; - ret = redirectConn->m->set_client_option(redirectConn, MYSQLND_OPT_AUTH_PROTOCOL, conn->options->auth_protocol); - if (ret == FAIL) goto copyFailed; + ret = redirectConn->m->set_client_option(redirectConn, MYSQLND_OPT_AUTH_PROTOCOL, conn->options->auth_protocol); + if (ret == FAIL) goto copyFailed; - //MYSQL_OPT_CONNECT_ATTR_xx - { - if (redirectConn->options->connect_attr) { - zend_hash_destroy(redirectConn->options->connect_attr); - mnd_pefree(redirectConn->options->connect_attr, redirectConn->persistent); - redirectConn->options->connect_attr = NULL; - } - zend_string * key; - zval * entry_value; - ZEND_HASH_FOREACH_STR_KEY_VAL(conn->options->connect_attr, key, entry_value) { - ret = redirectConn->m->set_client_option_2d(redirectConn, MYSQL_OPT_CONNECT_ATTR_ADD, ZSTR_VAL(key), Z_STRVAL_P(entry_value)); - if (ret == FAIL) goto copyFailed; - } ZEND_HASH_FOREACH_END(); - } + //MYSQL_OPT_CONNECT_ATTR_xx + { + if (redirectConn->options->connect_attr) { + zend_hash_destroy(redirectConn->options->connect_attr); + mnd_pefree(redirectConn->options->connect_attr, redirectConn->persistent); + redirectConn->options->connect_attr = NULL; + } + zend_string * key; + zval * entry_value; + ZEND_HASH_FOREACH_STR_KEY_VAL(conn->options->connect_attr, key, entry_value) { + ret = redirectConn->m->set_client_option_2d(redirectConn, MYSQL_OPT_CONNECT_ATTR_ADD, ZSTR_VAL(key), Z_STRVAL_P(entry_value)); + if (ret == FAIL) goto copyFailed; + } ZEND_HASH_FOREACH_END(); + } - DBG_RETURN(ret); + DBG_RETURN(ret); copyFailed: - DBG_RETURN(FAIL); + DBG_RETURN(FAIL); } /* }}} */ @@ -161,12 +161,12 @@ copyFailed: static zend_bool get_redirect_info(const MYSQLND_CONN_DATA * const conn, char* redirect_host, char* redirect_user, unsigned int* p_ui_redirect_port) { - /** - * Get redirected server information contained in OK packet. - * Redirection string has following format: - * Location: mysql://redirectedHostName:redirectedPort/user=redirectedUser - * the minimal len is 28 bytes - */ + /** + * Get redirected server information contained in OK packet. + * Redirection string has following format: + * Location: mysql://redirectedHostName:redirectedPort/user=redirectedUser + * the minimal len is 28 bytes + */ const char * msg_header = "Location: mysql://"; int msg_header_len = strlen(msg_header); @@ -233,395 +233,395 @@ get_redirect_info(const MYSQLND_CONN_DATA * const conn, char* redirect_host, cha /* {{{ mysqlnd_azure_data::connect */ MYSQLND_METHOD(mysqlnd_azure_data, connect)(MYSQLND_CONN_DATA ** pconn, - MYSQLND_CSTRING hostname, - MYSQLND_CSTRING username, - MYSQLND_CSTRING password, - MYSQLND_CSTRING database, - unsigned int port, - MYSQLND_CSTRING socket_or_pipe, - unsigned int mysql_flags - ) + MYSQLND_CSTRING hostname, + MYSQLND_CSTRING username, + MYSQLND_CSTRING password, + MYSQLND_CSTRING database, + unsigned int port, + MYSQLND_CSTRING socket_or_pipe, + unsigned int mysql_flags + ) { - MYSQLND_CONN_DATA * conn = *pconn; + MYSQLND_CONN_DATA * conn = *pconn; - const size_t this_func = STRUCT_OFFSET(MYSQLND_CLASS_METHODS_TYPE(mysqlnd_conn_data), connect); - zend_bool unix_socket = FALSE; - zend_bool named_pipe = FALSE; - zend_bool reconnect = FALSE; - zend_bool saved_compression = FALSE; - zend_bool local_tx_started = FALSE; - MYSQLND_PFC * pfc = conn->protocol_frame_codec; - MYSQLND_STRING transport = { NULL, 0 }; + const size_t this_func = STRUCT_OFFSET(MYSQLND_CLASS_METHODS_TYPE(mysqlnd_conn_data), connect); + zend_bool unix_socket = FALSE; + zend_bool named_pipe = FALSE; + zend_bool reconnect = FALSE; + zend_bool saved_compression = FALSE; + zend_bool local_tx_started = FALSE; + MYSQLND_PFC * pfc = conn->protocol_frame_codec; + MYSQLND_STRING transport = { NULL, 0 }; - DBG_ENTER("mysqlnd_conn_data::connect"); - DBG_INF_FMT("conn=%p", conn); + DBG_ENTER("mysqlnd_conn_data::connect"); + DBG_INF_FMT("conn=%p", conn); - if (PASS != conn->m->local_tx_start(conn, this_func)) { - goto err; - } - local_tx_started = TRUE; + if (PASS != conn->m->local_tx_start(conn, this_func)) { + goto err; + } + local_tx_started = TRUE; - SET_EMPTY_ERROR(conn->error_info); - UPSERT_STATUS_SET_AFFECTED_ROWS_TO_ERROR(conn->upsert_status); + SET_EMPTY_ERROR(conn->error_info); + UPSERT_STATUS_SET_AFFECTED_ROWS_TO_ERROR(conn->upsert_status); - DBG_INF_FMT("host=%s user=%s db=%s port=%u flags=%u persistent=%u state=%u", - hostname.s?hostname.s:"", username.s?username.s:"", database.s?database.s:"", port, mysql_flags, - conn? conn->persistent:0, conn? (int)GET_CONNECTION_STATE(&conn->state):-1); + DBG_INF_FMT("host=%s user=%s db=%s port=%u flags=%u persistent=%u state=%u", + hostname.s?hostname.s:"", username.s?username.s:"", database.s?database.s:"", port, mysql_flags, + conn? conn->persistent:0, conn? (int)GET_CONNECTION_STATE(&conn->state):-1); - if (GET_CONNECTION_STATE(&conn->state) > CONN_ALLOCED) { - DBG_INF("Connecting on a connected handle."); + if (GET_CONNECTION_STATE(&conn->state) > CONN_ALLOCED) { + DBG_INF("Connecting on a connected handle."); - if (GET_CONNECTION_STATE(&conn->state) < CONN_QUIT_SENT) { - MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_CLOSE_IMPLICIT); - reconnect = TRUE; - conn->m->send_close(conn); - } + if (GET_CONNECTION_STATE(&conn->state) < CONN_QUIT_SENT) { + MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_CLOSE_IMPLICIT); + reconnect = TRUE; + conn->m->send_close(conn); + } - conn->m->free_contents(conn); - /* Now reconnect using the same handle */ - if (pfc->data->compressed) { - /* - we need to save the state. As we will re-connect, pfc->compressed should be off, or - we will look for a compression header as part of the greet message, but there will - be none. - */ - saved_compression = TRUE; - pfc->data->compressed = FALSE; - } - if (pfc->data->ssl) { - pfc->data->ssl = FALSE; - } - } else { - unsigned int max_allowed_size = MYSQLND_ASSEMBLED_PACKET_MAX_SIZE; - conn->m->set_client_option(conn, MYSQLND_OPT_MAX_ALLOWED_PACKET, (char *)&max_allowed_size); - } + conn->m->free_contents(conn); + /* Now reconnect using the same handle */ + if (pfc->data->compressed) { + /* + we need to save the state. As we will re-connect, pfc->compressed should be off, or + we will look for a compression header as part of the greet message, but there will + be none. + */ + saved_compression = TRUE; + pfc->data->compressed = FALSE; + } + if (pfc->data->ssl) { + pfc->data->ssl = FALSE; + } + } else { + unsigned int max_allowed_size = MYSQLND_ASSEMBLED_PACKET_MAX_SIZE; + conn->m->set_client_option(conn, MYSQLND_OPT_MAX_ALLOWED_PACKET, (char *)&max_allowed_size); + } - if (!hostname.s || !hostname.s[0]) { - hostname.s = "localhost"; - hostname.l = strlen(hostname.s); - } - if (!username.s) { - DBG_INF_FMT("no user given, using empty string"); - username.s = ""; - username.l = 0; - } - if (!password.s) { - DBG_INF_FMT("no password given, using empty string"); - password.s = ""; - password.l = 0; - } - if (!database.s || !database.s[0]) { - DBG_INF_FMT("no db given, using empty string"); - database.s = ""; - database.l = 0; - } else { - mysql_flags |= CLIENT_CONNECT_WITH_DB; - } + if (!hostname.s || !hostname.s[0]) { + hostname.s = "localhost"; + hostname.l = strlen(hostname.s); + } + if (!username.s) { + DBG_INF_FMT("no user given, using empty string"); + username.s = ""; + username.l = 0; + } + if (!password.s) { + DBG_INF_FMT("no password given, using empty string"); + password.s = ""; + password.l = 0; + } + if (!database.s || !database.s[0]) { + DBG_INF_FMT("no db given, using empty string"); + database.s = ""; + database.l = 0; + } else { + mysql_flags |= CLIENT_CONNECT_WITH_DB; + } - transport = conn->m->get_scheme(conn, hostname, &socket_or_pipe, port, &unix_socket, &named_pipe); + transport = conn->m->get_scheme(conn, hostname, &socket_or_pipe, port, &unix_socket, &named_pipe); - mysql_flags = conn->m->get_updated_connect_flags(conn, mysql_flags); + mysql_flags = conn->m->get_updated_connect_flags(conn, mysql_flags); - { - const MYSQLND_CSTRING scheme = { transport.s, transport.l }; - if (FAIL == conn->m->connect_handshake(conn, &scheme, &username, &password, &database, mysql_flags)) { - goto err; - } - } + { + const MYSQLND_CSTRING scheme = { transport.s, transport.l }; + if (FAIL == conn->m->connect_handshake(conn, &scheme, &username, &password, &database, mysql_flags)) { + goto err; + } + } - /*start of Azure Redirection logic*/ - //Redirect before run init_command - { - SET_CONNECTION_STATE(&conn->state, CONN_READY); //set ready status so the connection can be closed correctly later if redirect succeeds + /*start of Azure Redirection logic*/ + //Redirect before run init_command + { + SET_CONNECTION_STATE(&conn->state, CONN_READY); //set ready status so the connection can be closed correctly later if redirect succeeds - DBG_ENTER("[redirect]: mysqlnd_azure_data::connect::redirect"); - char redirect_host[MAX_REDIRECT_HOST_LEN] = { 0 }; - char redirect_user[MAX_REDIRECT_USER_LEN] = { 0 }; - unsigned int ui_redirect_port = 0; - zend_bool serverSupportRedirect = get_redirect_info(conn, redirect_host, redirect_user, &ui_redirect_port); - if (!serverSupportRedirect) { - //do nothing else for redirection, just use the previous connection - DBG_ENTER("[redirect]: Server doesnot supoort redirection, do not need redirection. "); - goto after_conn; - } + DBG_ENTER("[redirect]: mysqlnd_azure_data::connect::redirect"); + char redirect_host[MAX_REDIRECT_HOST_LEN] = { 0 }; + char redirect_user[MAX_REDIRECT_USER_LEN] = { 0 }; + unsigned int ui_redirect_port = 0; + zend_bool serverSupportRedirect = get_redirect_info(conn, redirect_host, redirect_user, &ui_redirect_port); + if (!serverSupportRedirect) { + //do nothing else for redirection, just use the previous connection + DBG_ENTER("[redirect]: Server doesnot supoort redirection, do not need redirection. "); + goto after_conn; + } - //Get here means serverSupportRedirect + //Get here means serverSupportRedirect - //Already use redirected connection, or the connection string is a redirected one - if (strcmp(redirect_host, hostname.s) == 0 && strcmp(redirect_user, username.s) == 0 && ui_redirect_port == port) { - DBG_ENTER("[redirect]: Is using redirection, or redirection info are equal to origin, no need to redirect"); - goto after_conn; - } + //Already use redirected connection, or the connection string is a redirected one + if (strcmp(redirect_host, hostname.s) == 0 && strcmp(redirect_user, username.s) == 0 && ui_redirect_port == port) { + DBG_ENTER("[redirect]: Is using redirection, or redirection info are equal to origin, no need to redirect"); + goto after_conn; + } - //serverSupportRedirect, and currently used conn is not redirected connection, start redirection handshake - { - DBG_INF_FMT("[redirect]: redirect host=%s user=%s port=%d ", redirect_host, redirect_user, ui_redirect_port); - enum_func_status ret = FAIL; - MYSQLND* redirect_conneHandle = mysqlnd_init(MYSQLND_CLIENT_KNOWS_RSET_COPY_DATA, conn->persistent); //init MYSQLND but only need only MYSQLND_CONN_DATA here + //serverSupportRedirect, and currently used conn is not redirected connection, start redirection handshake + { + DBG_INF_FMT("[redirect]: redirect host=%s user=%s port=%d ", redirect_host, redirect_user, ui_redirect_port); + enum_func_status ret = FAIL; + MYSQLND* redirect_conneHandle = mysqlnd_init(MYSQLND_CLIENT_KNOWS_RSET_COPY_DATA, conn->persistent); //init MYSQLND but only need only MYSQLND_CONN_DATA here if(!redirect_conneHandle) { //redirect_conneHandle init failed, do nothing more, just use the original connection - goto after_conn; + goto after_conn; } - MYSQLND_CONN_DATA* redirect_conn = redirect_conneHandle->data; - redirect_conneHandle->data = NULL; - mnd_pefree(redirect_conneHandle, redirect_conneHandle->persistent); - redirect_conneHandle = NULL; + MYSQLND_CONN_DATA* redirect_conn = redirect_conneHandle->data; + redirect_conneHandle->data = NULL; + mnd_pefree(redirect_conneHandle, redirect_conneHandle->persistent); + redirect_conneHandle = NULL; - ret = set_redirect_client_options(conn, redirect_conn); + ret = set_redirect_client_options(conn, redirect_conn); - //init redirect_conn options failed, just use the proxy connection - if (ret == FAIL) { - //release resource - redirect_conn->m->dtor(redirect_conn); - goto after_conn; - } + //init redirect_conn options failed, just use the proxy connection + if (ret == FAIL) { + //release resource + redirect_conn->m->dtor(redirect_conn); + goto after_conn; + } - //init redirect_conn succeeded, use this conn to start a new connection and handshake + //init redirect_conn succeeded, use this conn to start a new connection and handshake - const MYSQLND_CSTRING redirect_hostname = { redirect_host, strlen(redirect_host) }; - const MYSQLND_CSTRING redirect_username = { redirect_user, strlen(redirect_user) }; - MYSQLND_STRING redirect_transport = redirect_conn->m->get_scheme(redirect_conn, redirect_hostname, &socket_or_pipe, ui_redirect_port, &unix_socket, &named_pipe); + const MYSQLND_CSTRING redirect_hostname = { redirect_host, strlen(redirect_host) }; + const MYSQLND_CSTRING redirect_username = { redirect_user, strlen(redirect_user) }; + MYSQLND_STRING redirect_transport = redirect_conn->m->get_scheme(redirect_conn, redirect_hostname, &socket_or_pipe, ui_redirect_port, &unix_socket, &named_pipe); - const MYSQLND_CSTRING redirect_scheme = { redirect_transport.s, redirect_transport.l }; + const MYSQLND_CSTRING redirect_scheme = { redirect_transport.s, redirect_transport.l }; - enum_func_status redirectState = redirect_conn->m->connect_handshake(redirect_conn, &redirect_scheme, &redirect_username, &password, &database, mysql_flags); + enum_func_status redirectState = redirect_conn->m->connect_handshake(redirect_conn, &redirect_scheme, &redirect_username, &password, &database, mysql_flags); - if (redirectState == PASS) { //handshake with redirect_conn succeeded, replace original connection info with redirect_conn and add the redirect info into cache table + if (redirectState == PASS) { //handshake with redirect_conn succeeded, replace original connection info with redirect_conn and add the redirect info into cache table - //add the redirect info into cache table - mysqlnd_azure_add_redirect_cache(username.s, hostname.s, port, redirect_username.s, redirect_hostname.s, ui_redirect_port); + //add the redirect info into cache table + mysqlnd_azure_add_redirect_cache(username.s, hostname.s, port, redirect_username.s, redirect_hostname.s, ui_redirect_port); - //close previous proxy connection - conn->m->send_close(conn); - conn->m->dtor(conn); - if (transport.s) { - mnd_sprintf_free(transport.s); - transport.s = NULL; - } + //close previous proxy connection + conn->m->send_close(conn); + conn->m->dtor(conn); + if (transport.s) { + mnd_sprintf_free(transport.s); + transport.s = NULL; + } - //upate conn, pfc, pconn for later user - conn = redirect_conn; - pfc = redirect_conn->protocol_frame_codec; //this variable will be used in after_conn context, so need take care - *pconn = redirect_conn; //use new conn outside for caller + //upate conn, pfc, pconn for later user + conn = redirect_conn; + pfc = redirect_conn->protocol_frame_codec; //this variable will be used in after_conn context, so need take care + *pconn = redirect_conn; //use new conn outside for caller - //upate host, user, transport for later user - hostname = redirect_hostname; - username = redirect_username; - port = ui_redirect_port; - transport = redirect_transport; + //upate host, user, transport for later user + hostname = redirect_hostname; + username = redirect_username; + port = ui_redirect_port; + transport = redirect_transport; - DBG_ENTER("[redirect]: mysql redirect handshake succeeded."); + DBG_ENTER("[redirect]: mysql redirect handshake succeeded."); - } - else { //redirect failed. use original connection information + } + else { //redirect failed. use original connection information - //free resource, and use original connection information - redirect_conn->m->dtor(redirect_conn); - if (redirect_transport.s) { - mnd_sprintf_free(redirect_transport.s); - redirect_transport.s = NULL; - } - DBG_ENTER("[redirect]: mysql redirect handshake fails, use original connection information!"); + //free resource, and use original connection information + redirect_conn->m->dtor(redirect_conn); + if (redirect_transport.s) { + mnd_sprintf_free(redirect_transport.s); + redirect_transport.s = NULL; + } + DBG_ENTER("[redirect]: mysql redirect handshake fails, use original connection information!"); - } - } + } + } - } - /*end of Azure Redirection Logic*/ + } + /*end of Azure Redirection Logic*/ after_conn: - { - SET_CONNECTION_STATE(&conn->state, CONN_READY); + { + SET_CONNECTION_STATE(&conn->state, CONN_READY); - if (saved_compression) { - pfc->data->compressed = TRUE; - } - /* - If a connect on a existing handle is performed and mysql_flags is - passed which doesn't CLIENT_COMPRESS, then we need to overwrite the value - which we set based on saved_compression. - */ - pfc->data->compressed = mysql_flags & CLIENT_COMPRESS? TRUE:FALSE; + if (saved_compression) { + pfc->data->compressed = TRUE; + } + /* + If a connect on a existing handle is performed and mysql_flags is + passed which doesn't CLIENT_COMPRESS, then we need to overwrite the value + which we set based on saved_compression. + */ + pfc->data->compressed = mysql_flags & CLIENT_COMPRESS? TRUE:FALSE; - conn->scheme.s = mnd_pestrndup(transport.s, transport.l, conn->persistent); - conn->scheme.l = transport.l; - if (transport.s) { - mnd_sprintf_free(transport.s); - transport.s = NULL; - } + conn->scheme.s = mnd_pestrndup(transport.s, transport.l, conn->persistent); + conn->scheme.l = transport.l; + if (transport.s) { + mnd_sprintf_free(transport.s); + transport.s = NULL; + } - if (!conn->scheme.s) { - goto err; /* OOM */ - } + if (!conn->scheme.s) { + goto err; /* OOM */ + } - conn->username.l = username.l; - conn->username.s = mnd_pestrndup(username.s, conn->username.l, conn->persistent); - conn->password.l = password.l; - conn->password.s = mnd_pestrndup(password.s, conn->password.l, conn->persistent); - conn->port = port; - conn->connect_or_select_db.l = database.l; - conn->connect_or_select_db.s = mnd_pestrndup(database.s, conn->connect_or_select_db.l, conn->persistent); + conn->username.l = username.l; + conn->username.s = mnd_pestrndup(username.s, conn->username.l, conn->persistent); + conn->password.l = password.l; + conn->password.s = mnd_pestrndup(password.s, conn->password.l, conn->persistent); + conn->port = port; + conn->connect_or_select_db.l = database.l; + conn->connect_or_select_db.s = mnd_pestrndup(database.s, conn->connect_or_select_db.l, conn->persistent); - if (!conn->username.s || !conn->password.s|| !conn->connect_or_select_db.s) { - SET_OOM_ERROR(conn->error_info); - goto err; /* OOM */ - } + if (!conn->username.s || !conn->password.s|| !conn->connect_or_select_db.s) { + SET_OOM_ERROR(conn->error_info); + goto err; /* OOM */ + } - if (!unix_socket && !named_pipe) { - conn->hostname.s = mnd_pestrndup(hostname.s, hostname.l, conn->persistent); - if (!conn->hostname.s) { - SET_OOM_ERROR(conn->error_info); - goto err; /* OOM */ - } - conn->hostname.l = hostname.l; - { - char *p; - mnd_sprintf(&p, 0, "%s via TCP/IP", conn->hostname.s); - if (!p) { - SET_OOM_ERROR(conn->error_info); - goto err; /* OOM */ - } - conn->host_info = mnd_pestrdup(p, conn->persistent); - mnd_sprintf_free(p); - if (!conn->host_info) { - SET_OOM_ERROR(conn->error_info); - goto err; /* OOM */ - } - } - } else { - conn->unix_socket.s = mnd_pestrdup(socket_or_pipe.s, conn->persistent); - if (unix_socket) { - conn->host_info = mnd_pestrdup("Localhost via UNIX socket", conn->persistent); - } else if (named_pipe) { - char *p; - mnd_sprintf(&p, 0, "%s via named pipe", conn->unix_socket.s); - if (!p) { - SET_OOM_ERROR(conn->error_info); - goto err; /* OOM */ - } - conn->host_info = mnd_pestrdup(p, conn->persistent); - mnd_sprintf_free(p); - if (!conn->host_info) { - SET_OOM_ERROR(conn->error_info); - goto err; /* OOM */ - } - } else { - php_error_docref(NULL, E_WARNING, "Impossible. Should be either socket or a pipe. Report a bug!"); - } - if (!conn->unix_socket.s || !conn->host_info) { - SET_OOM_ERROR(conn->error_info); - goto err; /* OOM */ - } - conn->unix_socket.l = strlen(conn->unix_socket.s); - } + if (!unix_socket && !named_pipe) { + conn->hostname.s = mnd_pestrndup(hostname.s, hostname.l, conn->persistent); + if (!conn->hostname.s) { + SET_OOM_ERROR(conn->error_info); + goto err; /* OOM */ + } + conn->hostname.l = hostname.l; + { + char *p; + mnd_sprintf(&p, 0, "%s via TCP/IP", conn->hostname.s); + if (!p) { + SET_OOM_ERROR(conn->error_info); + goto err; /* OOM */ + } + conn->host_info = mnd_pestrdup(p, conn->persistent); + mnd_sprintf_free(p); + if (!conn->host_info) { + SET_OOM_ERROR(conn->error_info); + goto err; /* OOM */ + } + } + } else { + conn->unix_socket.s = mnd_pestrdup(socket_or_pipe.s, conn->persistent); + if (unix_socket) { + conn->host_info = mnd_pestrdup("Localhost via UNIX socket", conn->persistent); + } else if (named_pipe) { + char *p; + mnd_sprintf(&p, 0, "%s via named pipe", conn->unix_socket.s); + if (!p) { + SET_OOM_ERROR(conn->error_info); + goto err; /* OOM */ + } + conn->host_info = mnd_pestrdup(p, conn->persistent); + mnd_sprintf_free(p); + if (!conn->host_info) { + SET_OOM_ERROR(conn->error_info); + goto err; /* OOM */ + } + } else { + php_error_docref(NULL, E_WARNING, "Impossible. Should be either socket or a pipe. Report a bug!"); + } + if (!conn->unix_socket.s || !conn->host_info) { + SET_OOM_ERROR(conn->error_info); + goto err; /* OOM */ + } + conn->unix_socket.l = strlen(conn->unix_socket.s); + } - SET_EMPTY_ERROR(conn->error_info); + SET_EMPTY_ERROR(conn->error_info); - mysqlnd_local_infile_default(conn); + mysqlnd_local_infile_default(conn); - if (FAIL == conn->m->execute_init_commands(conn)) { - goto err; - } + if (FAIL == conn->m->execute_init_commands(conn)) { + goto err; + } - MYSQLND_INC_CONN_STATISTIC_W_VALUE2(conn->stats, STAT_CONNECT_SUCCESS, 1, STAT_OPENED_CONNECTIONS, 1); - if (reconnect) { - MYSQLND_INC_GLOBAL_STATISTIC(STAT_RECONNECT); - } - if (conn->persistent) { - MYSQLND_INC_CONN_STATISTIC_W_VALUE2(conn->stats, STAT_PCONNECT_SUCCESS, 1, STAT_OPENED_PERSISTENT_CONNECTIONS, 1); - } + MYSQLND_INC_CONN_STATISTIC_W_VALUE2(conn->stats, STAT_CONNECT_SUCCESS, 1, STAT_OPENED_CONNECTIONS, 1); + if (reconnect) { + MYSQLND_INC_GLOBAL_STATISTIC(STAT_RECONNECT); + } + if (conn->persistent) { + MYSQLND_INC_CONN_STATISTIC_W_VALUE2(conn->stats, STAT_PCONNECT_SUCCESS, 1, STAT_OPENED_PERSISTENT_CONNECTIONS, 1); + } - DBG_INF_FMT("connection_id=%llu", conn->thread_id); + DBG_INF_FMT("connection_id=%llu", conn->thread_id); - conn->m->local_tx_end(conn, this_func, PASS); - DBG_RETURN(PASS); - } + conn->m->local_tx_end(conn, this_func, PASS); + DBG_RETURN(PASS); + } err: - if (transport.s) { - mnd_sprintf_free(transport.s); - transport.s = NULL; - } + if (transport.s) { + mnd_sprintf_free(transport.s); + transport.s = NULL; + } - DBG_ERR_FMT("[%u] %.128s (trying to connect via %s)", conn->error_info->error_no, conn->error_info->error, conn->scheme.s); - if (!conn->error_info->error_no) { - SET_CLIENT_ERROR(conn->error_info, CR_CONNECTION_ERROR, UNKNOWN_SQLSTATE, conn->error_info->error? conn->error_info->error:"Unknown error"); - php_error_docref(NULL, E_WARNING, "[%u] %.128s (trying to connect via %s)", conn->error_info->error_no, conn->error_info->error, conn->scheme.s); - } + DBG_ERR_FMT("[%u] %.128s (trying to connect via %s)", conn->error_info->error_no, conn->error_info->error, conn->scheme.s); + if (!conn->error_info->error_no) { + SET_CLIENT_ERROR(conn->error_info, CR_CONNECTION_ERROR, UNKNOWN_SQLSTATE, conn->error_info->error? conn->error_info->error:"Unknown error"); + php_error_docref(NULL, E_WARNING, "[%u] %.128s (trying to connect via %s)", conn->error_info->error_no, conn->error_info->error, conn->scheme.s); + } - conn->m->free_contents(conn); - MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_CONNECT_FAILURE); - if (TRUE == local_tx_started) { - conn->m->local_tx_end(conn, this_func, FAIL); - } + conn->m->free_contents(conn); + MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_CONNECT_FAILURE); + if (TRUE == local_tx_started) { + conn->m->local_tx_end(conn, this_func, FAIL); + } - DBG_RETURN(FAIL); + DBG_RETURN(FAIL); } /* }}} */ /* {{{ mysqlnd_azure::connect */ static enum_func_status MYSQLND_METHOD(mysqlnd_azure, connect)(MYSQLND * conn_handle, - const MYSQLND_CSTRING hostname, - const MYSQLND_CSTRING username, - const MYSQLND_CSTRING password, - const MYSQLND_CSTRING database, - unsigned int port, - const MYSQLND_CSTRING socket_or_pipe, - unsigned int mysql_flags) + const MYSQLND_CSTRING hostname, + const MYSQLND_CSTRING username, + const MYSQLND_CSTRING password, + const MYSQLND_CSTRING database, + unsigned int port, + const MYSQLND_CSTRING socket_or_pipe, + unsigned int mysql_flags) { - const size_t this_func = STRUCT_OFFSET(MYSQLND_CLASS_METHODS_TYPE(mysqlnd_conn_data), connect); - enum_func_status ret = FAIL; - MYSQLND_CONN_DATA ** pconn = &conn_handle->data; + const size_t this_func = STRUCT_OFFSET(MYSQLND_CLASS_METHODS_TYPE(mysqlnd_conn_data), connect); + enum_func_status ret = FAIL; + MYSQLND_CONN_DATA ** pconn = &conn_handle->data; - DBG_ENTER("mysqlnd_azure::connect"); + DBG_ENTER("mysqlnd_azure::connect"); - if (PASS == (*pconn)->m->local_tx_start(*pconn, this_func)) { - mysqlnd_options4(conn_handle, MYSQL_OPT_CONNECT_ATTR_ADD, "_client_name", "mysqlnd"); - if (hostname.l > 0) { - mysqlnd_options4(conn_handle, MYSQL_OPT_CONNECT_ATTR_ADD, "_server_host", hostname.s); - } + if (PASS == (*pconn)->m->local_tx_start(*pconn, this_func)) { + mysqlnd_options4(conn_handle, MYSQL_OPT_CONNECT_ATTR_ADD, "_client_name", "mysqlnd"); + if (hostname.l > 0) { + mysqlnd_options4(conn_handle, MYSQL_OPT_CONNECT_ATTR_ADD, "_server_host", hostname.s); + } - if (!MYSQLND_AZURE_G(enabled)) { - DBG_ENTER("mysqlnd_azure::connect redirect disabled"); - ret = org_conn_d_m.connect(*pconn, hostname, username, password, database, port, socket_or_pipe, mysql_flags); - } - else { - DBG_ENTER("mysqlnd_azure::connect redirect enabled"); + if (!MYSQLND_AZURE_G(enabled)) { + DBG_ENTER("mysqlnd_azure::connect redirect disabled"); + ret = org_conn_d_m.connect(*pconn, hostname, username, password, database, port, socket_or_pipe, mysql_flags); + } + else { + DBG_ENTER("mysqlnd_azure::connect redirect enabled"); - //Redirection is only possible with SSL at present. Continue with no redirection if SSL is not set - unsigned int temp_flags = (*pconn)->m->get_updated_connect_flags(*pconn, mysql_flags); - if (!(temp_flags & CLIENT_SSL)) { - ret = org_conn_d_m.connect(*pconn, hostname, username, password, database, port, socket_or_pipe, mysql_flags); - } - else { //SSL is enabled + //Redirection is only possible with SSL at present. Continue with no redirection if SSL is not set + unsigned int temp_flags = (*pconn)->m->get_updated_connect_flags(*pconn, mysql_flags); + if (!(temp_flags & CLIENT_SSL)) { + ret = org_conn_d_m.connect(*pconn, hostname, username, password, database, port, socket_or_pipe, mysql_flags); + } + else { //SSL is enabled - //first check whether the redirect info already cached - MYSQLND_AZURE_REDIRECT_INFO* redirect_info = mysqlnd_azure_find_redirect_cache(username.s, hostname.s, port); - if (redirect_info != NULL) { - DBG_ENTER("mysqlnd_azure::connect try the cached info first"); - const MYSQLND_CSTRING redirect_host = { redirect_info->redirect_host, strlen(redirect_info->redirect_host) }; - const MYSQLND_CSTRING redirect_user = { redirect_info->redirect_user, strlen(redirect_info->redirect_user) }; + //first check whether the redirect info already cached + MYSQLND_AZURE_REDIRECT_INFO* redirect_info = mysqlnd_azure_find_redirect_cache(username.s, hostname.s, port); + if (redirect_info != NULL) { + DBG_ENTER("mysqlnd_azure::connect try the cached info first"); + const MYSQLND_CSTRING redirect_host = { redirect_info->redirect_host, strlen(redirect_info->redirect_host) }; + const MYSQLND_CSTRING redirect_user = { redirect_info->redirect_user, strlen(redirect_info->redirect_user) }; - ret = (*pconn)->m->connect(pconn, redirect_host, redirect_user, password, database, redirect_info->redirect_port, socket_or_pipe, mysql_flags); - if (ret == FAIL) { - //remove invalid cache - mysqlnd_azure_remove_redirect_cache(username.s, hostname.s, port); + ret = (*pconn)->m->connect(pconn, redirect_host, redirect_user, password, database, redirect_info->redirect_port, socket_or_pipe, mysql_flags); + if (ret == FAIL) { + //remove invalid cache + mysqlnd_azure_remove_redirect_cache(username.s, hostname.s, port); - ret = (*pconn)->m->connect(pconn, hostname, username, password, database, port, socket_or_pipe, mysql_flags); - } - } - else { - ret = (*pconn)->m->connect(pconn, hostname, username, password, database, port, socket_or_pipe, mysql_flags); - } + ret = (*pconn)->m->connect(pconn, hostname, username, password, database, port, socket_or_pipe, mysql_flags); + } + } + else { + ret = (*pconn)->m->connect(pconn, hostname, username, password, database, port, socket_or_pipe, mysql_flags); + } - } - } + } + } - (*pconn)->m->local_tx_end(*pconn, this_func, FAIL); + (*pconn)->m->local_tx_end(*pconn, this_func, FAIL); - } - DBG_RETURN(ret); + } + DBG_RETURN(ret); } /* }}} */ @@ -629,16 +629,16 @@ MYSQLND_METHOD(mysqlnd_azure, connect)(MYSQLND * conn_handle, /* {{{ mysqlnd_azure_minit_register_hooks */ void mysqlnd_azure_minit_register_hooks() { - mysqlnd_azure_plugin_id = mysqlnd_plugin_register(); + mysqlnd_azure_plugin_id = mysqlnd_plugin_register(); - conn_m = mysqlnd_conn_get_methods(); - memcpy(&org_conn_m, conn_m, sizeof(struct st_mysqlnd_conn_methods)); + conn_m = mysqlnd_conn_get_methods(); + memcpy(&org_conn_m, conn_m, sizeof(struct st_mysqlnd_conn_methods)); - conn_d_m = mysqlnd_conn_data_get_methods(); - memcpy(&org_conn_d_m, conn_d_m, sizeof(struct st_mysqlnd_conn_data_methods)); + conn_d_m = mysqlnd_conn_data_get_methods(); + memcpy(&org_conn_d_m, conn_d_m, sizeof(struct st_mysqlnd_conn_data_methods)); - conn_m->connect = MYSQLND_METHOD(mysqlnd_azure, connect); - conn_d_m->connect = MYSQLND_METHOD(mysqlnd_azure_data, connect); + conn_m->connect = MYSQLND_METHOD(mysqlnd_azure, connect); + conn_d_m->connect = MYSQLND_METHOD(mysqlnd_azure_data, connect); } /* }}} */ From 9476f820a9d2ec71c5e06cea257d164da2528b8f Mon Sep 17 00:00:00 2001 From: Qianqian Bu Date: Tue, 11 Feb 2020 17:42:45 +0800 Subject: [PATCH 02/10] adjust design, add preferrred and enforce redirect when on, and new test cases --- Notes.txt | 22 ++- README.md | 61 +++++++- mysqlnd_azure.c | 89 +++++++++--- mysqlnd_azure.h | 2 + package.xml | 43 ++++-- php_mysqlnd_azure.c | 53 ++++--- php_mysqlnd_azure.h | 14 +- tests/mysqli_azure_option_test.phpt | 133 ++++++++++++++++++ tests/mysqli_azure_redirection_disabled.phpt | 38 ----- tests/mysqli_azure_redirection_enabled.phpt | 38 ----- tests/mysqli_azure_redirection_off.phpt | 72 ++++++++++ tests/mysqli_azure_redirection_on.phpt | 68 +++++++++ tests/mysqli_azure_redirection_preferred.phpt | 72 ++++++++++ tests/server_basic_mysqli.phpt | 8 +- tests/server_basic_mysqli_testcase.php | 12 +- tests/server_basic_pdo.phpt | 8 +- tests/server_basic_pdo_testcase.php | 12 +- tests/skipif_pdo.inc | 2 +- tests/skipifconnectfailure.inc | 1 + 19 files changed, 597 insertions(+), 151 deletions(-) create mode 100644 tests/mysqli_azure_option_test.phpt delete mode 100644 tests/mysqli_azure_redirection_disabled.phpt delete mode 100644 tests/mysqli_azure_redirection_enabled.phpt create mode 100644 tests/mysqli_azure_redirection_off.phpt create mode 100644 tests/mysqli_azure_redirection_on.phpt create mode 100644 tests/mysqli_azure_redirection_preferred.phpt diff --git a/Notes.txt b/Notes.txt index a8e0f7f..4520daf 100644 --- a/Notes.txt +++ b/Notes.txt @@ -9,7 +9,23 @@ connection, and use the new one afterward. +---------------------------+ OPTION DESCRIPTION ------------------ ---------------------------------------------------------- -mysqlnd_azure.enabled This option is to control enable or disable mysqlnd_rd. -If this is set to 0, it will not use redirection. -(Default: 0) +mysqlnd_azure.enableRedirect This option is to control enable or disable redirection feature of mysqlnd_azure. +If this is set to off, it will not use redirection. +Available option values: +(Default: off) +---------------|------------------------------------------------------------------------------------------------------------------------------------------ +off(0) | - It will not use redirection. +---------------|------------------------------------------------------------------------------------------------------------------------------------------ +on(1) | - If ssl is off, no connection will be made, return error: + | "mysqlnd_azure.enableRedirect is on, but SSL option is not set in connection string. Redirection is only possible with SSL." + | - If on server side redirection is not available, abort the first connection and return error: + | "Connection aborted because redirection is not enabled on the MySQL server or the network package doesn't meet meet redirection protocol." + | - If server supports redirection, but the redirected connection failed for any reason, also abort the first proxy connection. + | Return the error of the redirected connection. +---------------|------------------------------------------------------------------------------------------------------------------------------------------ +preferred(2) | - it will use redirection if possible. + | - If connection does not use SSL, or server does not support redirection, or redirected connection fails + | to connect for any non-fatal reason while the proxy connection is still a valid one, it will fallback + | to the first proxy connection. +---------------|------------------------------------------------------------------------------------------------------------------------------------------ diff --git a/README.md b/README.md index b00615d..6caac8b 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,52 @@ The source code here is a PHP extension implemented using mysqlnd plugin API (ht **Important notice: There is a limitation that for Azure MySQL, redirection is only possible when the connection is configured with SSL, and it will only support TLS 1.2 with FIPS approved cipher for redirection.** +## Option Usage +In 1.0.x versions, the option is with name **mysqlnd_azure.enabled**. When redirection is turned on, but connection does not use SSL, +or server does not support redirection, or redirected connection fails to connect for any non-fatal reason while the proxy connection +is still a valid one, it will fallback to the first proxy connection. The detailed usage of the option enableRedirect is as follows: +(Version 1.0.x. Config name: **mysqlnd_azure.enabled**. Valid value: on/off. Default value: off) + + + + + + + + + +
off(0) - It will not use redirection.
on(1) - It will use redirection if possible (Connection is with SSL and Server supports/need redirection).
+ - If connection does not use SSL, or server does not support redirection, or redirected connection fails to connect for any non-fatal reason while the proxy connection is still a valid one, it will fallback to the first proxy connection. +
+ +Since 1.1.0RC1, the logic changes as follows: +- The option mysqlnd_azure.enabled is renamed to **mysqlnd_azure.enableRedirect**, and there is a new option value "preferred" provided. +- The detailed usage of the option enableRedirect is as follows: + +(Version 1.1.0RC1. Config name: **mysqlnd_azure.enableRedirect**. Valid value: on/off/preferred. Default value: off) + + + + + + + + + + + + + +
off(0) - It will not use redirection.
on(1) - If SSL is off, no connection will be made, return error: + "mysqlnd_azure.enableRedirect is on, but SSL option is not set in connection string. Redirection is only possible with SSL."
+ - If on server side redirection is not supported, abort the first connection and return error: "Connection aborted because redirection is not enabled on the MySQL server or the network package doesn't meet meet redirection protocol."
+ - If server supports redirection, but the redirected connection failed for any reason, also abort the first proxy connection. Return the error of the redirected connection. +
+preferred(2) + - It will use redirection if possible.
+ - If connection does not use SSL, or server does not support redirection, or redirected connection fails to connect for any non-fatal reason while the proxy connection is still a valid one, it will fallback to the first proxy connection. +
+ ## Name and Extension Version Extension name: **mysqlnd_azure** @@ -15,6 +61,12 @@ Valid version: - 1.0.3RC Change: fix the crash problem when working with PDO interface with flag PDO::ATTR_PERSISTENT=>false. This version is marked as beta, so please use *pecl install mysqlnd_azure-1.0.3RC* to install when using pecl. - 1.0.3 Change: Remove the use of is_using_redirect flag. More strict validation and new test cases with php built-in web server. +- 1.1.0RC1 Change: + 1. Rename option mysqlnd_azure.enabled to mysqlnd_azure.enableRedirect, and add a new option value "preferred". + 2. When enableRedirect is "preferred", it will use redirection if possible. If connection does not use SSL, or server does not support redirection, or redirected connection fails to connect for any non-fatal reason while the proxy connection is still a valid one, it will fallback to the first proxy connection. + 3. When enableRedirect is "on", SSL is off, no connection will be made, return error "mysqlnd_azure.enableRedirect is on, but SSL option is not set in connection string. Redirection is only possible with SSL." + 4. When enableRedirect is "on", but on server side redirection is not supported, abort the first connection and return error "Connection aborted because redirection is not enabled on the MySQL server or the network package doesn't meet meet redirection protocol." + 5. When enableRedirect is "on" and server supports redirection, but the redirected connection failed for any reason, also abort the first proxy connection. Return the error of the redirected connection. Following is a brief guide of how to install using pecl or build and test the extension from source. @@ -93,7 +145,8 @@ Then you can run **make install** to put the .so to your php so library. However - put mysqlnd_azure.so under extension_dir. - under directory for additional .ini files, you will find the ini files for the common used modules, e.g. 10-mysqlnd.ini for mysqlnd, 20-mysqli.ini for mysqli. Create a new ini file for mysqlnd_azure here. **Make sure the alphabet order of the name is after that of mysqnld**, since the modules are loaded according to the name order of the ini files. E.g. if mysqlnd ini is with name 10-mysqlnd.ini,then name the ini as 20-mysqlnd-azure.ini. In the ini file, add the following two lines: - extension=mysqlnd_azure - - mysqlnd_azure.enabled = on ; you can also set this to off to disable redirection + - mysqlnd_azure.enableRedirect = on/off/preferred + - **Notice:** since 1.1.0RC1, if this value is set to on, the connection must be configured with SSL, and it requires server support redirection. Otherwise, the connection will fail. Please check the Option Usage section for detailed information. ## Step to build on Windows @@ -139,15 +192,17 @@ After this, the code directory should look like C:\php-sdk\phpdev\vc15\x64\php-s - extension=mysqlnd_azure - Under the Module Settings section add: - [mysqlnd_azure] - - mysqlnd_azure.enabled = on + - mysqlnd_azure.enableRedirect = on/off/preferred + - **Notice:** since 1.1.0RC1, if this value is set to on, the connection must be configured with SSL, and it requires server support redirection. Otherwise, the connection will fail. Please check the Option Usage section for detailed information. ## Test * Currently redirection is only possible when the connection is via ssl, and it need that the redirection feature switch is enabled on server side. Following is a snippet to test connection with redirection: ```php - echo "mysqlnd_azure.enabled: ", ini_get("mysqlnd_azure.enabled") == true?"On":"Off", "\n"; + echo "mysqlnd_azure.enableRedirect: ", ini_get("mysqlnd_azure.enableRedirect"), "\n"; $db = mysqli_init(); + //The connection must be configured with SSL for redirection test $link = mysqli_real_connect ($db, 'your-hostname-with-redirection-enabled', 'user@host', 'password', "db", 3306, NULL, MYSQLI_CLIENT_SSL); if (!$link) { die ('Connect error (' . mysqli_connect_errno() . '): ' . mysqli_connect_error() . "\n"); diff --git a/mysqlnd_azure.c b/mysqlnd_azure.c index 1c6aecd..6c39690 100644 --- a/mysqlnd_azure.c +++ b/mysqlnd_azure.c @@ -340,9 +340,16 @@ MYSQLND_METHOD(mysqlnd_azure_data, connect)(MYSQLND_CONN_DATA ** pconn, unsigned int ui_redirect_port = 0; zend_bool serverSupportRedirect = get_redirect_info(conn, redirect_host, redirect_user, &ui_redirect_port); if (!serverSupportRedirect) { - //do nothing else for redirection, just use the previous connection - DBG_ENTER("[redirect]: Server doesnot supoort redirection, do not need redirection. "); - goto after_conn; + DBG_ENTER("[redirect]: Server doesnot supoort redirection."); + if(MYSQLND_AZURE_G(enableRedirect) == REDIRECT_ON) { + //REDIRECT_ON, if redirection is not supported, abort the original connection and return error + conn->m->send_close(conn); + SET_CLIENT_ERROR(conn->error_info, MYSQLND_AZURE_ENFORCE_REDIRECT_ERROR_NO, UNKNOWN_SQLSTATE, "Connection aborted because redirection is not enabled on the MySQL server or the network package doesn't meet meet redirection protocol."); + goto err; + } else { + //REDIRECT_PREFERRED, do nothing else for redirection, just use the previous connection + goto after_conn; + } } //Get here means serverSupportRedirect @@ -359,9 +366,18 @@ MYSQLND_METHOD(mysqlnd_azure_data, connect)(MYSQLND_CONN_DATA ** pconn, enum_func_status ret = FAIL; MYSQLND* redirect_conneHandle = mysqlnd_init(MYSQLND_CLIENT_KNOWS_RSET_COPY_DATA, conn->persistent); //init MYSQLND but only need only MYSQLND_CONN_DATA here if(!redirect_conneHandle) { - //redirect_conneHandle init failed, do nothing more, just use the original connection - goto after_conn; + DBG_ENTER("[redirect]: init redirect_conneHandle failed"); + if(MYSQLND_AZURE_G(enableRedirect) == REDIRECT_ON) { + //REDIRECT_ON, abort the original connection and return error + conn->m->send_close(conn); + SET_CLIENT_ERROR(conn->error_info, MYSQLND_AZURE_ENFORCE_REDIRECT_ERROR_NO, UNKNOWN_SQLSTATE, "Connection aborted because init redirection failed."); + goto err; + } else { + //REDIRECT_PREFERRED, do nothing else for redirection, just use the previous connection + goto after_conn; + } } + MYSQLND_CONN_DATA* redirect_conn = redirect_conneHandle->data; redirect_conneHandle->data = NULL; mnd_pefree(redirect_conneHandle, redirect_conneHandle->persistent); @@ -371,13 +387,22 @@ MYSQLND_METHOD(mysqlnd_azure_data, connect)(MYSQLND_CONN_DATA ** pconn, //init redirect_conn options failed, just use the proxy connection if (ret == FAIL) { - //release resource - redirect_conn->m->dtor(redirect_conn); - goto after_conn; + DBG_ENTER("[redirect]: init redirection option failed. "); + redirect_conn->m->dtor(redirect_conn); //release created resource + + if(MYSQLND_AZURE_G(enableRedirect) == REDIRECT_ON) { + //REDIRECT_ON, abort the original connection + conn->m->send_close(conn); + SET_CLIENT_ERROR(conn->error_info, MYSQLND_AZURE_ENFORCE_REDIRECT_ERROR_NO, UNKNOWN_SQLSTATE, "Connection aborted because init redirection failed."); + goto err; + } else { + //REDIRECT_PREFERRED, do nothing else for redirection, just use the previous connection + goto after_conn; + } } //init redirect_conn succeeded, use this conn to start a new connection and handshake - + const MYSQLND_CSTRING redirect_hostname = { redirect_host, strlen(redirect_host) }; const MYSQLND_CSTRING redirect_username = { redirect_user, strlen(redirect_user) }; MYSQLND_STRING redirect_transport = redirect_conn->m->get_scheme(redirect_conn, redirect_hostname, &socket_or_pipe, ui_redirect_port, &unix_socket, &named_pipe); @@ -387,6 +412,7 @@ MYSQLND_METHOD(mysqlnd_azure_data, connect)(MYSQLND_CONN_DATA ** pconn, enum_func_status redirectState = redirect_conn->m->connect_handshake(redirect_conn, &redirect_scheme, &redirect_username, &password, &database, mysql_flags); if (redirectState == PASS) { //handshake with redirect_conn succeeded, replace original connection info with redirect_conn and add the redirect info into cache table + DBG_ENTER("[redirect]: mysql redirect handshake succeeded."); //add the redirect info into cache table mysqlnd_azure_add_redirect_cache(username.s, hostname.s, port, redirect_username.s, redirect_hostname.s, ui_redirect_port); @@ -410,19 +436,32 @@ MYSQLND_METHOD(mysqlnd_azure_data, connect)(MYSQLND_CONN_DATA ** pconn, port = ui_redirect_port; transport = redirect_transport; - DBG_ENTER("[redirect]: mysql redirect handshake succeeded."); + } else { //redirect failed. if REDIRECT_ON, also abort the original conn, if REDIRECT_PREFERRED, use original connection + DBG_ENTER("[redirect]: mysql redirect handshake fails"); - } - else { //redirect failed. use original connection information + if (MYSQLND_AZURE_G(enableRedirect) == REDIRECT_PREFERRED) { + //free resource and use original connection + redirect_conn->m->dtor(redirect_conn); + if (redirect_transport.s) { + mnd_sprintf_free(redirect_transport.s); + redirect_transport.s = NULL; + } + goto after_conn; - //free resource, and use original connection information - redirect_conn->m->dtor(redirect_conn); - if (redirect_transport.s) { - mnd_sprintf_free(redirect_transport.s); - redirect_transport.s = NULL; + } else { //REDIRECT_ON, free original connect, and use redirect_conn to handle error + conn->m->send_close(conn); + conn->m->dtor(conn); + pfc = NULL; + if (transport.s) { + mnd_sprintf_free(transport.s); + transport.s = NULL; + } + + conn = redirect_conn; + *pconn = redirect_conn; + pfc = redirect_conn->protocol_frame_codec; + goto err; } - DBG_ENTER("[redirect]: mysql redirect handshake fails, use original connection information!"); - } } @@ -582,7 +621,7 @@ MYSQLND_METHOD(mysqlnd_azure, connect)(MYSQLND * conn_handle, mysqlnd_options4(conn_handle, MYSQL_OPT_CONNECT_ATTR_ADD, "_server_host", hostname.s); } - if (!MYSQLND_AZURE_G(enabled)) { + if (MYSQLND_AZURE_G(enableRedirect) == REDIRECT_OFF) { DBG_ENTER("mysqlnd_azure::connect redirect disabled"); ret = org_conn_d_m.connect(*pconn, hostname, username, password, database, port, socket_or_pipe, mysql_flags); } @@ -592,7 +631,15 @@ MYSQLND_METHOD(mysqlnd_azure, connect)(MYSQLND * conn_handle, //Redirection is only possible with SSL at present. Continue with no redirection if SSL is not set unsigned int temp_flags = (*pconn)->m->get_updated_connect_flags(*pconn, mysql_flags); if (!(temp_flags & CLIENT_SSL)) { - ret = org_conn_d_m.connect(*pconn, hostname, username, password, database, port, socket_or_pipe, mysql_flags); + if((MYSQLND_AZURE_G(enableRedirect) == REDIRECT_ON)) { + SET_CLIENT_ERROR((*pconn)->error_info, MYSQLND_AZURE_ENFORCE_REDIRECT_ERROR_NO, UNKNOWN_SQLSTATE, "mysqlnd_azure.enableRedirect is on, but SSL option is not set in connection string. Redirection is only possible with SSL."); + (*pconn)->m->local_tx_end(*pconn, this_func, FAIL); + (*pconn)->m->free_contents(*pconn); + return FAIL; + } + else { + ret = org_conn_d_m.connect(*pconn, hostname, username, password, database, port, socket_or_pipe, mysql_flags); + } } else { //SSL is enabled diff --git a/mysqlnd_azure.h b/mysqlnd_azure.h index 511ba65..74dc082 100644 --- a/mysqlnd_azure.h +++ b/mysqlnd_azure.h @@ -36,6 +36,8 @@ typedef struct st_mysqlnd_azure_redirect_info { #define MAX_REDIRECT_HOST_LEN 128 #define MAX_REDIRECT_USER_LEN 128 +#define MYSQLND_AZURE_ENFORCE_REDIRECT_ERROR_NO CR_NOT_IMPLEMENTED + void mysqlnd_azure_minit_register_hooks(); enum_func_status mysqlnd_azure_add_redirect_cache(const char* user, const char* host, int port, const char* redirect_user, const char* redirect_host, int redirect_port); diff --git a/package.xml b/package.xml index 0cf4943..ec5b674 100644 --- a/package.xml +++ b/package.xml @@ -16,19 +16,24 @@ Qianqian.Bu@microsoft.com yes - 2020-02-10 + 2020-02-15 - 1.0.3 - 1.0.3 + 1.1.0RC1 + 1.1.0RC1 - stable - stable + beta + beta PHP License -- Remove the use of is_using_redirect flag. More strict validation and test cases with php built-in web server. +- 1. Rename option mysqlnd_azure.enabled to mysqlnd_azure.enableRedirect. +- 2. When enableRedirect is "on", ssl is off, no connection will be made, return error "mysqlnd_azure.enableRedirect is on, but SSL option is not set in connection string. Redirection is only possible with SSL." +- 3. When enableRedirect is "on", but on server side redirection is not available, abort the first connection and return error "Connection aborted because redirection is not enabled on the MySQL server or the network package doesn't meet meet redirection protocol." +- 4. When enableRedirect is "on" and server supports redirection, but the redirected connection failed for any reason, also abort the first proxy connection. Return the error of the redirected connection. +- 5. A new option for mysqlnd_azure.enableRedirect is introduced with name "preferred". When enableRedirect is "preferred", it will use redirection if possible. + If connection does not use SSL, or server does not support redirection, or redirected connection fails to connect for any non-fatal reason while the proxy connection is still a valid one, it will fallback to the first proxy connection. @@ -39,8 +44,10 @@ - - + + + + @@ -72,6 +79,26 @@ mysqlnd_azure + + + 1.1.0RC1 + 1.1.0RC1 + + + beta + beta + + 2020-02-15 + PHP License + +- 1. Rename option mysqlnd_azure.enabled to mysqlnd_azure.enableRedirect, and add a new option value "preferred". +- 2. When enableRedirect is "on", ssl is off, no connection will be made, return error "mysqlnd_azure.enableRedirect is on, but SSL option is not set in connection string. Redirection is only possible with SSL." +- 3. When enableRedirect is "on", but on server side redirection is not available, abort the first connection and return error "Connection aborted because redirection is not enabled on the MySQL server or the network package doesn't meet meet redirection protocol." +- 4. When enableRedirect is "on" and server supports redirection, but the redirected connection failed for any reason, also abort the first proxy connection. Return the error of the redirected connection. +- 5. A new option for mysqlnd_azure.enableRedirect is introduced with name "preferred". When enableRedirect is "preferred", it will use redirection if possible. + If connection does not use SSL, or server does not support redirection, or redirected connection fails to connect for any non-fatal reason while the proxy connection is still a valid one, it will fallback to the first proxy connection. + + 1.0.3 diff --git a/php_mysqlnd_azure.c b/php_mysqlnd_azure.c index 5c45c4e..7df8a1c 100644 --- a/php_mysqlnd_azure.c +++ b/php_mysqlnd_azure.c @@ -28,13 +28,45 @@ ZEND_DECLARE_MODULE_GLOBALS(mysqlnd_azure) +/* {{{ OnUpdateEnableRedirect */ +static ZEND_INI_MH(OnUpdateEnableRedirect) +{ + if (STRING_EQUALS(new_value,"preferred") + || STRING_EQUALS(new_value, "2")) { + + MYSQLND_AZURE_G(enableRedirect) = REDIRECT_PREFERRED; + + } else if (STRING_EQUALS(new_value, "on") + || STRING_EQUALS(new_value, "yes") + || STRING_EQUALS(new_value, "true") + || STRING_EQUALS(new_value, "1")) { + + MYSQLND_AZURE_G(enableRedirect) = REDIRECT_ON; + + } else { + + MYSQLND_AZURE_G(enableRedirect) = REDIRECT_OFF; + + } + + return SUCCESS; + +} +/* }}} */ + +/* {{{ PHP_INI */ +PHP_INI_BEGIN() +STD_PHP_INI_ENTRY("mysqlnd_azure.enableRedirect", "preferred", PHP_INI_ALL, OnUpdateEnableRedirect, enableRedirect, zend_mysqlnd_azure_globals, mysqlnd_azure_globals) +PHP_INI_END() +/* }}} */ + /* {{{ PHP_GINIT_FUNCTION */ static PHP_GINIT_FUNCTION(mysqlnd_azure) { #if defined(COMPILE_DL_MYSQLND_AZURE) && defined(ZTS) ZEND_TSRMLS_CACHE_UPDATE(); #endif - mysqlnd_azure_globals->enabled = 0; + mysqlnd_azure_globals->enableRedirect = REDIRECT_PREFERRED; mysqlnd_azure_globals->redirectCache = NULL; } /* }}} */ @@ -50,17 +82,6 @@ static PHP_GSHUTDOWN_FUNCTION(mysqlnd_azure) } /* }}} */ -/* {{{ PHP_INI */ -/* - It is handy to allow users to disable any mysqlnd plugin globally - not only for debugging :-) - Because we register our plugin in MINIT changes to mysqlnd_ed.enabled shall be bound to - INI_SYSTEM (and PHP restarts). -*/ -PHP_INI_BEGIN() -STD_PHP_INI_ENTRY("mysqlnd_azure.enabled", "0", PHP_INI_ALL, OnUpdateBool, enabled, zend_mysqlnd_azure_globals, mysqlnd_azure_globals) -PHP_INI_END() -/* }}} */ - /* {{{ PHP_MINIT_FUNCTION */ static PHP_MINIT_FUNCTION(mysqlnd_azure) @@ -87,8 +108,8 @@ static PHP_MSHUTDOWN_FUNCTION(mysqlnd_azure) PHP_MINFO_FUNCTION(mysqlnd_azure) { php_info_print_table_start(); - php_info_print_table_header(2, "mysqlnd_azure", "enabled"); - php_info_print_table_row(2, "enabled", MYSQLND_AZURE_G(enabled)? "Yes":"No"); + php_info_print_table_header(2, "mysqlnd_azure", "enableRedirect"); + php_info_print_table_row(2, "enableRedirect", MYSQLND_AZURE_G(enableRedirect) == REDIRECT_OFF ? "off" : (MYSQLND_AZURE_G(enableRedirect) == REDIRECT_ON ? "on" : "preferred")); php_info_print_table_end(); } /* }}} */ @@ -103,14 +124,14 @@ zend_module_entry mysqlnd_azure_module_entry = { STANDARD_MODULE_HEADER_EX, NULL, mysqlnd_azure_deps, - EXT_MYSQLND_AZURE_NAME, + PHP_MYSQLND_AZURE_NAME, NULL, PHP_MINIT(mysqlnd_azure), PHP_MSHUTDOWN(mysqlnd_azure), NULL, NULL, PHP_MINFO(mysqlnd_azure), - EXT_MYSQLND_AZURE_VERSION, + PHP_MYSQLND_AZURE_VERSION, PHP_MODULE_GLOBALS(mysqlnd_azure), PHP_GINIT(mysqlnd_azure), PHP_GSHUTDOWN(mysqlnd_azure), diff --git a/php_mysqlnd_azure.h b/php_mysqlnd_azure.h index c8dcbd5..497dd90 100644 --- a/php_mysqlnd_azure.h +++ b/php_mysqlnd_azure.h @@ -28,14 +28,22 @@ extern zend_module_entry mysqlnd_azure_module_entry; #define phpext_mysqlnd_azure_ptr &mysqlnd_azure_module_entry -#define EXT_MYSQLND_AZURE_NAME "mysqlnd_azure" -#define EXT_MYSQLND_AZURE_VERSION "1.0.3" +#define PHP_MYSQLND_AZURE_NAME "mysqlnd_azure" +#define PHP_MYSQLND_AZURE_VERSION "1.1.0RC1" + +#define STRING_EQUALS(z_str,str) (ZSTR_LEN((z_str)) == strlen((str)) && strcasecmp((str), ZSTR_VAL((z_str))) == 0) ZEND_BEGIN_MODULE_GLOBALS(mysqlnd_azure) - zend_bool enabled; + zend_bool enableRedirect; HashTable* redirectCache; ZEND_END_MODULE_GLOBALS(mysqlnd_azure) +typedef enum _mysqlnd_azure_redirect_mode { + REDIRECT_OFF = 0, /* completely disabled */ + REDIRECT_ON = 1, /* enabled without fallback, block if redirection fail */ + REDIRECT_PREFERRED = 2 /* enabled with fallback */ +} mysqlnd_azure_redirect_mode; + PHPAPI ZEND_EXTERN_MODULE_GLOBALS(mysqlnd_azure) #define MYSQLND_AZURE_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(mysqlnd_azure, v) diff --git a/tests/mysqli_azure_option_test.phpt b/tests/mysqli_azure_option_test.phpt new file mode 100644 index 0000000..d31f9d6 --- /dev/null +++ b/tests/mysqli_azure_option_test.phpt @@ -0,0 +1,133 @@ +--TEST-- +Azure redirection option test for mysqlnd_azure.enableRedirect +--SKIPIF-- + +--FILE-- +host_info, 0, strlen($host)) == $host) + echo "equal\n"; + else + echo "not equal\n"; + $link->close(); + } + + $link = mysqli_init(); + $ret = @mysqli_real_connect($link, $host, $user, $passwd, $db, $port, NULL, MYSQLI_CLIENT_SSL); + $last_message = ""; + if($ret) + $last_message = $link->info; + + //Server supports redirection + if(strlen($last_message) > 27 && strcmp(substr($last_message, 0, strlen("Location:")), "Location:")==0) { + $config = ini_get("mysqlnd_azure.enableRedirect"); + if(substr($link->host_info, 0, strlen($host)) == $host && (strcasecmp($config, "preferred")==0 || strcasecmp($config, "2")==0)) + echo "FAIL\n"; + else + echo "PASS\n"; + } + else if($ret && is_object($link)) { + if(substr($link->host_info, 0, strlen($host)) == $host) + echo "PASS\n"; + else + echo "FAIL\n"; + } + else if(!$ret) { //Server does not support redirection and redirect on + $lastError = error_get_last()["message"]; + if (strpos($lastError, "Connection aborted because redirection is not enabled on the MySQL server or the network package doesn't meet meet redirection protocol.") !== false) + echo "PASS\n"; + else + echo "FAIL\n"; + } + if($ret) $link->close(); +} + +ini_set_test("on"); +ini_set_test("On"); +ini_set_test("yes"); +ini_set_test("Yes"); +ini_set_test("true"); +ini_set_test("True"); +ini_set_test("1"); +ini_set_test(1); + +ini_set_test("preferred"); +ini_set_test("Preferred"); +ini_set_test("2"); +ini_set_test(2); + +ini_set_test("off"); +ini_set_test("Off"); +ini_set_test("0"); +ini_set_test(0); +ini_set_test("otherValue"); + +echo "Done\n"; +?> +--EXPECTF-- +on +mysqli_real_connect(): (HY000/2054): mysqlnd_azure.enableRedirect is on, but SSL option is not set in connection string. Redirection is only possible with SSL. +PASS +On +mysqli_real_connect(): (HY000/2054): mysqlnd_azure.enableRedirect is on, but SSL option is not set in connection string. Redirection is only possible with SSL. +PASS +yes +mysqli_real_connect(): (HY000/2054): mysqlnd_azure.enableRedirect is on, but SSL option is not set in connection string. Redirection is only possible with SSL. +PASS +Yes +mysqli_real_connect(): (HY000/2054): mysqlnd_azure.enableRedirect is on, but SSL option is not set in connection string. Redirection is only possible with SSL. +PASS +true +mysqli_real_connect(): (HY000/2054): mysqlnd_azure.enableRedirect is on, but SSL option is not set in connection string. Redirection is only possible with SSL. +PASS +True +mysqli_real_connect(): (HY000/2054): mysqlnd_azure.enableRedirect is on, but SSL option is not set in connection string. Redirection is only possible with SSL. +PASS +1 +mysqli_real_connect(): (HY000/2054): mysqlnd_azure.enableRedirect is on, but SSL option is not set in connection string. Redirection is only possible with SSL. +PASS +1 +mysqli_real_connect(): (HY000/2054): mysqlnd_azure.enableRedirect is on, but SSL option is not set in connection string. Redirection is only possible with SSL. +PASS +preferred +equal +PASS +Preferred +equal +PASS +2 +equal +PASS +2 +equal +PASS +off +equal +PASS +Off +equal +PASS +0 +equal +PASS +0 +equal +PASS +otherValue +equal +PASS +Done \ No newline at end of file diff --git a/tests/mysqli_azure_redirection_disabled.phpt b/tests/mysqli_azure_redirection_disabled.phpt deleted file mode 100644 index c5c2393..0000000 --- a/tests/mysqli_azure_redirection_disabled.phpt +++ /dev/null @@ -1,38 +0,0 @@ ---TEST-- -Azure redirection test for servers with mysqlnd_azure.enabled=0 ---INI-- -mysqlnd_azure.enabled=0 ---SKIPIF-- - ---FILE-- -host_info."\n"; -echo $link->info."\n"; -if(substr($link->host_info, 0, strlen($host)) == $host) - echo "1\n"; -else - echo "0\n"; -mysqli_close($link); -echo "Done\n"; -?> ---EXPECTF-- -%s -Location: mysql://%s.%s:%d/user=%s@%s -1 -Done diff --git a/tests/mysqli_azure_redirection_enabled.phpt b/tests/mysqli_azure_redirection_enabled.phpt deleted file mode 100644 index 400c629..0000000 --- a/tests/mysqli_azure_redirection_enabled.phpt +++ /dev/null @@ -1,38 +0,0 @@ ---TEST-- -Azure redirection test for servers when mysqlnd_azure.enabled ---INI-- -mysqlnd_azure.enabled=1 ---SKIPIF-- - ---FILE-- -host_info."\n"; -echo $link->info."\n"; -if(substr($link->host_info, 0, strlen($host)) == $host) - echo "1\n"; -else - echo "0\n"; -mysqli_close($link); -echo "Done\n"; -?> ---EXPECTF-- -%s.%s -Location: mysql://%s.%s:%d/user=%s@%s -0 -Done diff --git a/tests/mysqli_azure_redirection_off.phpt b/tests/mysqli_azure_redirection_off.phpt new file mode 100644 index 0000000..602408f --- /dev/null +++ b/tests/mysqli_azure_redirection_off.phpt @@ -0,0 +1,72 @@ +--TEST-- +Azure redirection test for servers when mysqlnd_azure.enableRedirect="off" +--INI-- +mysqlnd_azure.enableRedirect="off" +--SKIPIF-- + +--FILE-- +host_info."\n"; +$last_message = $link->info; + +//Server supports redirection +if(strlen($last_message) > 27 && strcmp(substr($last_message, 0, strlen("Location:")), "Location:")==0) { + if(substr($link->host_info, 0, strlen($host)) == $host) + echo "[003] pass\n"; + else + echo "[003] fail\n"; +} +else { //Server does not support redirection, use the proxy connection + if(substr($link->host_info, 0, strlen($host)) == $host) + echo "[003] pass\n"; + else + echo "[003] fail\n"; +} + +mysqli_close($link); + +//Step 3: check connection result when not use SSL +$link = mysqli_init(); +$ret = @mysqli_real_connect($link, $host, $user, $passwd, $db, $port, NULL, NULL); +if (!$ret || !is_object($link)) +{ + printf("[004] Cannot connect to the server using host=%s, user=%s, passwd=***, dbname=%s, port=%s, socket=%s\n - [%d] %s without ssl\n", + $host, $user, $db, $port, $socket, mysqli_connect_errno(), mysqli_connect_error()); + die(); +} + +if(substr($link->host_info, 0, strlen($host)) == $host) + echo "[004] pass\n"; +else + echo "[004] fail\n"; + +echo "Done\n"; +?> +--EXPECTF-- +off +%s +[003] pass +[004] pass +Done \ No newline at end of file diff --git a/tests/mysqli_azure_redirection_on.phpt b/tests/mysqli_azure_redirection_on.phpt new file mode 100644 index 0000000..5678f0b --- /dev/null +++ b/tests/mysqli_azure_redirection_on.phpt @@ -0,0 +1,68 @@ +--TEST-- +Azure redirection test for servers when mysqlnd_azure.enableRedirect="on" +--INI-- +mysqlnd_azure.enableRedirect="on" +--SKIPIF-- + +--FILE-- +info; + +//Server supports redirection +if(strlen($last_message) > 27 && strcmp(substr($last_message, 0, strlen("Location:")), "Location:")==0) { + if(substr($link->host_info, 0, strlen($host)) == $host) + echo "[003] fail\n"; + else + echo "[003] pass\n"; +} +else { //Server does not support redirection + $lastError = error_get_last()["message"]; + if (strpos($lastError, "Connection aborted because redirection is not enabled on the MySQL server or the network package doesn't meet meet redirection protocol.") !== false) + echo "[003] pass\n"; + else + echo "[003] fail\n"; +} + +mysqli_close($link); + +//Step 3: check connection result when not use SSL +$link = mysqli_init(); +$ret = @mysqli_real_connect($link, $host, $user, $passwd, $db, $port, NULL, NULL); +if ($ret) +{ + printf("[004] When enableRedirect=on, connect without SSL expects failure, got pass\n"); + die(); +} + +$lastError = error_get_last()["message"]; +if (strpos($lastError, "mysqlnd_azure.enableRedirect is on, but SSL option is not set in connection string. Redirection is only possible with SSL.") !== false) + echo "[004] pass\n"; + else + echo "[004] fail\n"; + +echo "Done\n"; +?> +--EXPECTF-- +on +[003] pass +[004] pass +Done \ No newline at end of file diff --git a/tests/mysqli_azure_redirection_preferred.phpt b/tests/mysqli_azure_redirection_preferred.phpt new file mode 100644 index 0000000..0a358d8 --- /dev/null +++ b/tests/mysqli_azure_redirection_preferred.phpt @@ -0,0 +1,72 @@ +--TEST-- +Azure redirection test for servers when mysqlnd_azure.enableRedirect="preferred" +--INI-- +mysqlnd_azure.enableRedirect="preferred" +--SKIPIF-- + +--FILE-- +host_info."\n"; +$last_message = $link->info; + +//Server supports redirection +if(strlen($last_message) > 27 && strcmp(substr($last_message, 0, strlen("Location:")), "Location:")==0) { + if(substr($link->host_info, 0, strlen($host)) == $host) + echo "[003] fail\n"; + else + echo "[003] pass\n"; +} +else { //Server does not support redirection, use the proxy connection + if(substr($link->host_info, 0, strlen($host)) == $host) + echo "[003] pass\n"; + else + echo "[003] fail\n"; +} + +mysqli_close($link); + +//Step 3: check connection result when not use SSL +$link = mysqli_init(); +$ret = @mysqli_real_connect($link, $host, $user, $passwd, $db, $port, NULL, NULL); +if (!$ret || !is_object($link)) +{ + printf("[004] Cannot connect to the server using host=%s, user=%s, passwd=***, dbname=%s, port=%s, socket=%s\n - [%d] %s without ssl\n", + $host, $user, $db, $port, $socket, mysqli_connect_errno(), mysqli_connect_error()); + die(); +} + +if(substr($link->host_info, 0, strlen($host)) == $host) + echo "[004] pass\n"; +else + echo "[004] fail\n"; + +echo "Done\n"; +?> +--EXPECTF-- +preferred +%s +[003] pass +[004] pass +Done \ No newline at end of file diff --git a/tests/server_basic_mysqli.phpt b/tests/server_basic_mysqli.phpt index 1e3c26e..37a7757 100644 --- a/tests/server_basic_mysqli.phpt +++ b/tests/server_basic_mysqli.phpt @@ -33,22 +33,22 @@ fclose($fp); --EXPECTF-- *** Testing mysqli in web server: basic functionality *** step1: redirect enabled, non-persistent connection -mysqlnd_azure.enabled: On +mysqlnd_azure.enableRedirect: preferred %s Location: mysql://%s:%d/user=%s 0 step2: redirect enabled, persistent connection -mysqlnd_azure.enabled: On +mysqlnd_azure.enableRedirect: preferred %s Location: mysql://%s:%d/user=%s 0 step3: redirect disabled, non-persistent connection -mysqlnd_azure.enabled: Off +mysqlnd_azure.enableRedirect: off %s Location: mysql://%s:%d/user=%s 1 step4: redirect disabled, persistent connection -mysqlnd_azure.enabled: Off +mysqlnd_azure.enableRedirect: off %s 0 diff --git a/tests/server_basic_mysqli_testcase.php b/tests/server_basic_mysqli_testcase.php index 490a704..4918b5b 100644 --- a/tests/server_basic_mysqli_testcase.php +++ b/tests/server_basic_mysqli_testcase.php @@ -1,11 +1,11 @@ Date: Wed, 12 Feb 2020 19:09:48 +0800 Subject: [PATCH 03/10] change the variable type --- php_mysqlnd_azure.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/php_mysqlnd_azure.h b/php_mysqlnd_azure.h index 497dd90..8a3b6e5 100644 --- a/php_mysqlnd_azure.h +++ b/php_mysqlnd_azure.h @@ -33,17 +33,17 @@ extern zend_module_entry mysqlnd_azure_module_entry; #define STRING_EQUALS(z_str,str) (ZSTR_LEN((z_str)) == strlen((str)) && strcasecmp((str), ZSTR_VAL((z_str))) == 0) -ZEND_BEGIN_MODULE_GLOBALS(mysqlnd_azure) - zend_bool enableRedirect; - HashTable* redirectCache; -ZEND_END_MODULE_GLOBALS(mysqlnd_azure) - typedef enum _mysqlnd_azure_redirect_mode { REDIRECT_OFF = 0, /* completely disabled */ REDIRECT_ON = 1, /* enabled without fallback, block if redirection fail */ REDIRECT_PREFERRED = 2 /* enabled with fallback */ } mysqlnd_azure_redirect_mode; +ZEND_BEGIN_MODULE_GLOBALS(mysqlnd_azure) + mysqlnd_azure_redirect_mode enableRedirect; + HashTable* redirectCache; +ZEND_END_MODULE_GLOBALS(mysqlnd_azure) + PHPAPI ZEND_EXTERN_MODULE_GLOBALS(mysqlnd_azure) #define MYSQLND_AZURE_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(mysqlnd_azure, v) From 1f09d08f5f2f19329bd2c42455e5e43cc2d2b073 Mon Sep 17 00:00:00 2001 From: Qianqian Bu Date: Wed, 12 Feb 2020 19:49:04 +0800 Subject: [PATCH 04/10] free redirect_transport in both cases and format --- mysqlnd_azure.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/mysqlnd_azure.c b/mysqlnd_azure.c index 6c39690..20c7c1e 100644 --- a/mysqlnd_azure.c +++ b/mysqlnd_azure.c @@ -340,7 +340,7 @@ MYSQLND_METHOD(mysqlnd_azure_data, connect)(MYSQLND_CONN_DATA ** pconn, unsigned int ui_redirect_port = 0; zend_bool serverSupportRedirect = get_redirect_info(conn, redirect_host, redirect_user, &ui_redirect_port); if (!serverSupportRedirect) { - DBG_ENTER("[redirect]: Server doesnot supoort redirection."); + DBG_ENTER("[redirect]: Server does not support redirection."); if(MYSQLND_AZURE_G(enableRedirect) == REDIRECT_ON) { //REDIRECT_ON, if redirection is not supported, abort the original connection and return error conn->m->send_close(conn); @@ -435,31 +435,31 @@ MYSQLND_METHOD(mysqlnd_azure_data, connect)(MYSQLND_CONN_DATA ** pconn, username = redirect_username; port = ui_redirect_port; transport = redirect_transport; + redirect_transport = NULL; } else { //redirect failed. if REDIRECT_ON, also abort the original conn, if REDIRECT_PREFERRED, use original connection DBG_ENTER("[redirect]: mysql redirect handshake fails"); + //need free in both cases + if (redirect_transport.s) { + mnd_sprintf_free(redirect_transport.s); + redirect_transport.s = NULL; + } if (MYSQLND_AZURE_G(enableRedirect) == REDIRECT_PREFERRED) { - //free resource and use original connection + //free object and use original connection redirect_conn->m->dtor(redirect_conn); - if (redirect_transport.s) { - mnd_sprintf_free(redirect_transport.s); - redirect_transport.s = NULL; - } goto after_conn; } else { //REDIRECT_ON, free original connect, and use redirect_conn to handle error conn->m->send_close(conn); conn->m->dtor(conn); pfc = NULL; - if (transport.s) { - mnd_sprintf_free(transport.s); - transport.s = NULL; - } + //transport will be free after goto err conn = redirect_conn; *pconn = redirect_conn; pfc = redirect_conn->protocol_frame_codec; + redirect_conn = NULL; goto err; } } From 76c518511ee2d9334be0ebc9238d1ff25080ca3e Mon Sep 17 00:00:00 2001 From: Qianqian Bu Date: Thu, 13 Feb 2020 09:59:25 +0800 Subject: [PATCH 05/10] set right value to NULL --- mysqlnd_azure.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mysqlnd_azure.c b/mysqlnd_azure.c index 20c7c1e..221aa10 100644 --- a/mysqlnd_azure.c +++ b/mysqlnd_azure.c @@ -389,6 +389,7 @@ MYSQLND_METHOD(mysqlnd_azure_data, connect)(MYSQLND_CONN_DATA ** pconn, if (ret == FAIL) { DBG_ENTER("[redirect]: init redirection option failed. "); redirect_conn->m->dtor(redirect_conn); //release created resource + redirect_conn = NULL; if(MYSQLND_AZURE_G(enableRedirect) == REDIRECT_ON) { //REDIRECT_ON, abort the original connection @@ -435,7 +436,7 @@ MYSQLND_METHOD(mysqlnd_azure_data, connect)(MYSQLND_CONN_DATA ** pconn, username = redirect_username; port = ui_redirect_port; transport = redirect_transport; - redirect_transport = NULL; + redirect_transport.s = NULL; } else { //redirect failed. if REDIRECT_ON, also abort the original conn, if REDIRECT_PREFERRED, use original connection DBG_ENTER("[redirect]: mysql redirect handshake fails"); From ab761cebcb66bd5f3f876d0e1ca8c7297927ff0c Mon Sep 17 00:00:00 2001 From: Qianqian Bu Date: Thu, 13 Feb 2020 11:17:22 +0800 Subject: [PATCH 06/10] change version number, correct default value for 1.1.0, improve doc and test --- Notes.txt | 2 +- README.md | 18 +++++----- mysqlnd_azure.c | 5 +-- package.xml | 25 ++++++------- php_mysqlnd_azure.h | 2 +- tests/server_basic_mysqli.phpt | 9 ++++- tests/server_basic_mysqli_testcase.php | 36 +++++++++++++++++++ ...ifconnectfailure.inc => skipif_mysqli.inc} | 0 8 files changed, 70 insertions(+), 27 deletions(-) rename tests/{skipifconnectfailure.inc => skipif_mysqli.inc} (100%) diff --git a/Notes.txt b/Notes.txt index 4520daf..8febf3b 100644 --- a/Notes.txt +++ b/Notes.txt @@ -13,7 +13,7 @@ mysqlnd_azure.enableRedirect This option is to control enable or disable redirec If this is set to off, it will not use redirection. Available option values: -(Default: off) +(Default: preferred) ---------------|------------------------------------------------------------------------------------------------------------------------------------------ off(0) | - It will not use redirection. ---------------|------------------------------------------------------------------------------------------------------------------------------------------ diff --git a/README.md b/README.md index 6caac8b..376e22e 100644 --- a/README.md +++ b/README.md @@ -4,10 +4,8 @@ The source code here is a PHP extension implemented using mysqlnd plugin API (ht **Important notice: There is a limitation that for Azure MySQL, redirection is only possible when the connection is configured with SSL, and it will only support TLS 1.2 with FIPS approved cipher for redirection.** ## Option Usage -In 1.0.x versions, the option is with name **mysqlnd_azure.enabled**. When redirection is turned on, but connection does not use SSL, -or server does not support redirection, or redirected connection fails to connect for any non-fatal reason while the proxy connection -is still a valid one, it will fallback to the first proxy connection. The detailed usage of the option enableRedirect is as follows: -(Version 1.0.x. Config name: **mysqlnd_azure.enabled**. Valid value: on/off. Default value: off) +Before 1.1.0, the option is with name **mysqlnd_azure.enabled**. Valid values are on/off, and the option "on" supports fallback logic. The detailed usage of the option enableRedirect is as follows: +(Version before 1.1.0. Config name: **mysqlnd_azure.enabled**. Valid value: on/off. Default value: off) @@ -21,11 +19,11 @@ is still a valid one, it will fallback to the first proxy connection. The detail
off(0)
-Since 1.1.0RC1, the logic changes as follows: -- The option mysqlnd_azure.enabled is renamed to **mysqlnd_azure.enableRedirect**, and there is a new option value "preferred" provided. +Since 1.1.0, the logic changes as follows: +- The option mysqlnd_azure.enabled is renamed to **mysqlnd_azure.enableRedirect**, option "on" enforces redirection, and there is a new option value "preferred" provided which becomes the default option. - The detailed usage of the option enableRedirect is as follows: -(Version 1.1.0RC1. Config name: **mysqlnd_azure.enableRedirect**. Valid value: on/off/preferred. Default value: off) +(Version 1.1.0. Config name: **mysqlnd_azure.enableRedirect**. Valid value: on/off/preferred. Default value: preferred) @@ -61,7 +59,7 @@ Valid version: - 1.0.3RC Change: fix the crash problem when working with PDO interface with flag PDO::ATTR_PERSISTENT=>false. This version is marked as beta, so please use *pecl install mysqlnd_azure-1.0.3RC* to install when using pecl. - 1.0.3 Change: Remove the use of is_using_redirect flag. More strict validation and new test cases with php built-in web server. -- 1.1.0RC1 Change: +- 1.1.0 Change: 1. Rename option mysqlnd_azure.enabled to mysqlnd_azure.enableRedirect, and add a new option value "preferred". 2. When enableRedirect is "preferred", it will use redirection if possible. If connection does not use SSL, or server does not support redirection, or redirected connection fails to connect for any non-fatal reason while the proxy connection is still a valid one, it will fallback to the first proxy connection. 3. When enableRedirect is "on", SSL is off, no connection will be made, return error "mysqlnd_azure.enableRedirect is on, but SSL option is not set in connection string. Redirection is only possible with SSL." @@ -146,7 +144,7 @@ Then you can run **make install** to put the .so to your php so library. However - under directory for additional .ini files, you will find the ini files for the common used modules, e.g. 10-mysqlnd.ini for mysqlnd, 20-mysqli.ini for mysqli. Create a new ini file for mysqlnd_azure here. **Make sure the alphabet order of the name is after that of mysqnld**, since the modules are loaded according to the name order of the ini files. E.g. if mysqlnd ini is with name 10-mysqlnd.ini,then name the ini as 20-mysqlnd-azure.ini. In the ini file, add the following two lines: - extension=mysqlnd_azure - mysqlnd_azure.enableRedirect = on/off/preferred - - **Notice:** since 1.1.0RC1, if this value is set to on, the connection must be configured with SSL, and it requires server support redirection. Otherwise, the connection will fail. Please check the Option Usage section for detailed information. + - **Notice:** since 1.1.0, if this value is set to on, the connection must be configured with SSL, and it requires server support redirection. Otherwise, the connection will fail. Please check the Option Usage section for detailed information. ## Step to build on Windows @@ -193,7 +191,7 @@ After this, the code directory should look like C:\php-sdk\phpdev\vc15\x64\php-s - Under the Module Settings section add: - [mysqlnd_azure] - mysqlnd_azure.enableRedirect = on/off/preferred - - **Notice:** since 1.1.0RC1, if this value is set to on, the connection must be configured with SSL, and it requires server support redirection. Otherwise, the connection will fail. Please check the Option Usage section for detailed information. + - **Notice:** since 1.1.0, if this value is set to on, the connection must be configured with SSL, and it requires server support redirection. Otherwise, the connection will fail. Please check the Option Usage section for detailed information. ## Test diff --git a/mysqlnd_azure.c b/mysqlnd_azure.c index 221aa10..bb3c0cf 100644 --- a/mysqlnd_azure.c +++ b/mysqlnd_azure.c @@ -629,16 +629,17 @@ MYSQLND_METHOD(mysqlnd_azure, connect)(MYSQLND * conn_handle, else { DBG_ENTER("mysqlnd_azure::connect redirect enabled"); - //Redirection is only possible with SSL at present. Continue with no redirection if SSL is not set + //Redirection is only possible with SSL at present. unsigned int temp_flags = (*pconn)->m->get_updated_connect_flags(*pconn, mysql_flags); if (!(temp_flags & CLIENT_SSL)) { + //REDIRECT_ON, no ssl, return error if((MYSQLND_AZURE_G(enableRedirect) == REDIRECT_ON)) { SET_CLIENT_ERROR((*pconn)->error_info, MYSQLND_AZURE_ENFORCE_REDIRECT_ERROR_NO, UNKNOWN_SQLSTATE, "mysqlnd_azure.enableRedirect is on, but SSL option is not set in connection string. Redirection is only possible with SSL."); (*pconn)->m->local_tx_end(*pconn, this_func, FAIL); (*pconn)->m->free_contents(*pconn); return FAIL; } - else { + else { //REDIRECT_PREFERRED, no ssl, do not redirect ret = org_conn_d_m.connect(*pconn, hostname, username, password, database, port, socket_or_pipe, mysql_flags); } } diff --git a/package.xml b/package.xml index ec5b674..66e0571 100644 --- a/package.xml +++ b/package.xml @@ -16,23 +16,24 @@ Qianqian.Bu@microsoft.comyes - 2020-02-15 + 2020-02-14 - 1.1.0RC1 - 1.1.0RC1 + 1.1.0 + 1.1.0 - beta - beta + stable + stable PHP License - 1. Rename option mysqlnd_azure.enabled to mysqlnd_azure.enableRedirect. -- 2. When enableRedirect is "on", ssl is off, no connection will be made, return error "mysqlnd_azure.enableRedirect is on, but SSL option is not set in connection string. Redirection is only possible with SSL." -- 3. When enableRedirect is "on", but on server side redirection is not available, abort the first connection and return error "Connection aborted because redirection is not enabled on the MySQL server or the network package doesn't meet meet redirection protocol." -- 4. When enableRedirect is "on" and server supports redirection, but the redirected connection failed for any reason, also abort the first proxy connection. Return the error of the redirected connection. -- 5. A new option for mysqlnd_azure.enableRedirect is introduced with name "preferred". When enableRedirect is "preferred", it will use redirection if possible. +- 2. Add a new option choice "preferred". +- 3. When enableRedirect is "on", ssl is off, no connection will be made, return error "mysqlnd_azure.enableRedirect is on, but SSL option is not set in connection string. Redirection is only possible with SSL." +- 4. When enableRedirect is "on", but on server side redirection is not available, abort the first connection and return error "Connection aborted because redirection is not enabled on the MySQL server or the network package doesn't meet meet redirection protocol." +- 5. When enableRedirect is "on" and server supports redirection, but the redirected connection failed for any reason, also abort the first proxy connection. Return the error of the redirected connection. +- 6. When enableRedirect is "preferred", it will use redirection if possible. If connection does not use SSL, or server does not support redirection, or redirected connection fails to connect for any non-fatal reason while the proxy connection is still a valid one, it will fallback to the first proxy connection. @@ -50,7 +51,7 @@ - + @@ -81,8 +82,8 @@ - 1.1.0RC1 - 1.1.0RC1 + 1.1.0 + 1.1.0 beta diff --git a/php_mysqlnd_azure.h b/php_mysqlnd_azure.h index 8a3b6e5..f349c44 100644 --- a/php_mysqlnd_azure.h +++ b/php_mysqlnd_azure.h @@ -29,7 +29,7 @@ extern zend_module_entry mysqlnd_azure_module_entry; #define phpext_mysqlnd_azure_ptr &mysqlnd_azure_module_entry #define PHP_MYSQLND_AZURE_NAME "mysqlnd_azure" -#define PHP_MYSQLND_AZURE_VERSION "1.1.0RC1" +#define PHP_MYSQLND_AZURE_VERSION "1.1.0" #define STRING_EQUALS(z_str,str) (ZSTR_LEN((z_str)) == strlen((str)) && strcasecmp((str), ZSTR_VAL((z_str))) == 0) diff --git a/tests/server_basic_mysqli.phpt b/tests/server_basic_mysqli.phpt index 37a7757..521a2c5 100644 --- a/tests/server_basic_mysqli.phpt +++ b/tests/server_basic_mysqli.phpt @@ -4,7 +4,7 @@ Test redirection in web server with baisc functionality - mysqli --CONFLICTS-- server @@ -51,5 +51,12 @@ step4: redirect disabled, persistent connection mysqlnd_azure.enableRedirect: off %s +0 +step5: redirect enforced, non-ssl connection +mysqlnd_azure.enableRedirect: on +mysqli_real_connect(): (HY000/2054): mysqlnd_azure.enableRedirect is on, but SSL option is not set in connection string. Redirection is only possible with SSL. +step6: redirect enforced, ssl connection +%s +Location: mysql://%s:%d/user=%s 0 ===DONE=== \ No newline at end of file diff --git a/tests/server_basic_mysqli_testcase.php b/tests/server_basic_mysqli_testcase.php index 4918b5b..77acf90 100644 --- a/tests/server_basic_mysqli_testcase.php +++ b/tests/server_basic_mysqli_testcase.php @@ -85,4 +85,40 @@ echo "step4: redirect disabled, persistent connection \n"; mysqli_close($link); } +ini_set("mysqlnd_azure.enableRedirect", "on"); + +echo "step5: redirect enforced, non-ssl connection \n"; +{ + echo "mysqlnd_azure.enableRedirect: ", ini_get("mysqlnd_azure.enableRedirect"), "\n"; + $link = mysqli_init(); + $ret = mysqli_real_connect($link, $host, $user, $passwd, $db, $port, NULL, NULL); + if ($ret || is_object($link)) + { + printf("[001] when enableRedirect=on, Connection without SSL should fail.\n"); + mysqli_close($link); + die(); + } + echo error_get_last()["message"]; +} + +echo "step6: redirect enforced, ssl connection \n"; +{ + echo "mysqlnd_azure.enableRedirect: ", ini_get("mysqlnd_azure.enableRedirect"), "\n"; + $link = mysqli_init(); + $ret = mysqli_real_connect($link, $host, $user, $passwd, $db, $port, NULL, MYSQLI_CLIENT_SSL); + if (!$ret || !is_object($link)) + { + printf("[001] Cannot connect to the server using host=%s, user=%s, passwd=***, dbname=%s, port=%s, socket=%s\n - [%d] %s with ssl", + $host, $user, $db, $port, $socket, mysqli_connect_errno(), mysqli_connect_error()); + die(); + } + echo $link->host_info."\n"; + echo $link->info."\n"; + if(substr($link->host_info, 0, strlen($host)) == $host) + echo "1\n"; + else + echo "0\n"; + mysqli_close($link); +} + ?> \ No newline at end of file diff --git a/tests/skipifconnectfailure.inc b/tests/skipif_mysqli.inc similarity index 100% rename from tests/skipifconnectfailure.inc rename to tests/skipif_mysqli.inc From 9993db8dfc61b46019e35b48f41219b6371fa96b Mon Sep 17 00:00:00 2001 From: Qianqian Bu Date: Thu, 13 Feb 2020 13:00:18 +0800 Subject: [PATCH 07/10] update test cases and settings --- tests/server_basic_mysqli.phpt | 1 + tests/server_basic_mysqli_testcase.php | 6 +++--- tests/server_basic_pdo_testcase.php | 2 +- tests/skipif_pdo.inc | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/tests/server_basic_mysqli.phpt b/tests/server_basic_mysqli.phpt index 521a2c5..c5b4b30 100644 --- a/tests/server_basic_mysqli.phpt +++ b/tests/server_basic_mysqli.phpt @@ -56,6 +56,7 @@ step5: redirect enforced, non-ssl connection mysqlnd_azure.enableRedirect: on mysqli_real_connect(): (HY000/2054): mysqlnd_azure.enableRedirect is on, but SSL option is not set in connection string. Redirection is only possible with SSL. step6: redirect enforced, ssl connection +mysqlnd_azure.enableRedirect: on %s Location: mysql://%s:%d/user=%s 0 diff --git a/tests/server_basic_mysqli_testcase.php b/tests/server_basic_mysqli_testcase.php index 77acf90..23e3dc5 100644 --- a/tests/server_basic_mysqli_testcase.php +++ b/tests/server_basic_mysqli_testcase.php @@ -91,14 +91,14 @@ echo "step5: redirect enforced, non-ssl connection \n"; { echo "mysqlnd_azure.enableRedirect: ", ini_get("mysqlnd_azure.enableRedirect"), "\n"; $link = mysqli_init(); - $ret = mysqli_real_connect($link, $host, $user, $passwd, $db, $port, NULL, NULL); - if ($ret || is_object($link)) + $ret = @mysqli_real_connect($link, $host, $user, $passwd, $db, $port, NULL, NULL); + if ($ret) { printf("[001] when enableRedirect=on, Connection without SSL should fail.\n"); mysqli_close($link); die(); } - echo error_get_last()["message"]; + echo error_get_last()["message"], "\n"; } echo "step6: redirect enforced, ssl connection \n"; diff --git a/tests/server_basic_pdo_testcase.php b/tests/server_basic_pdo_testcase.php index 9b4974e..e929a41 100644 --- a/tests/server_basic_pdo_testcase.php +++ b/tests/server_basic_pdo_testcase.php @@ -1,7 +1,7 @@ Date: Thu, 13 Feb 2020 19:19:07 +0800 Subject: [PATCH 08/10] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 376e22e..feb377c 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ The source code here is a PHP extension implemented using mysqlnd plugin API (ht **Important notice: There is a limitation that for Azure MySQL, redirection is only possible when the connection is configured with SSL, and it will only support TLS 1.2 with FIPS approved cipher for redirection.** ## Option Usage -Before 1.1.0, the option is with name **mysqlnd_azure.enabled**. Valid values are on/off, and the option "on" supports fallback logic. The detailed usage of the option enableRedirect is as follows: +**Before 1.1.0**, the option is with name **mysqlnd_azure.enabled**. Valid values are on/off, and the option "on" supports fallback logic. The detailed usage of the option enableRedirect is as follows: (Version before 1.1.0. Config name: **mysqlnd_azure.enabled**. Valid value: on/off. Default value: off)
off(0)
@@ -19,7 +19,7 @@ Before 1.1.0, the option is with name **mysqlnd_azure.enabled**. Valid values ar
-Since 1.1.0, the logic changes as follows: +**Since 1.1.0**, the logic changes as follows: - The option mysqlnd_azure.enabled is renamed to **mysqlnd_azure.enableRedirect**, option "on" enforces redirection, and there is a new option value "preferred" provided which becomes the default option. - The detailed usage of the option enableRedirect is as follows: From 5881d944b41c58d633cf4638c76ae9674accd510 Mon Sep 17 00:00:00 2001 From: GuuBu <46982854+GuuBu@users.noreply.github.com> Date: Fri, 14 Feb 2020 14:32:23 +0800 Subject: [PATCH 09/10] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index feb377c..294c502 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ The source code here is a PHP extension implemented using mysqlnd plugin API (ht ## Option Usage **Before 1.1.0**, the option is with name **mysqlnd_azure.enabled**. Valid values are on/off, and the option "on" supports fallback logic. The detailed usage of the option enableRedirect is as follows: + (Version before 1.1.0. Config name: **mysqlnd_azure.enabled**. Valid value: on/off. Default value: off) From 0f368927c56a7b6f0e0903709b4eeff789ad22d2 Mon Sep 17 00:00:00 2001 From: GuuBu <46982854+GuuBu@users.noreply.github.com> Date: Fri, 14 Feb 2020 14:36:47 +0800 Subject: [PATCH 10/10] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 294c502..98d8be4 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ The source code here is a PHP extension implemented using mysqlnd plugin API (ht -
on(1) - It will use redirection if possible (Connection is with SSL and Server supports/need redirection).
+
- It will use redirection if possible (Connection is with SSL and Server supports/needs redirection).
- If connection does not use SSL, or server does not support redirection, or redirected connection fails to connect for any non-fatal reason while the proxy connection is still a valid one, it will fallback to the first proxy connection.