diff --git a/CMakeLists.txt b/CMakeLists.txt index a31b6dbe..636de894 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -165,40 +165,45 @@ INCLUDE(${CMAKE_SOURCE_DIR}/cmake/CheckFunctions.cmake) # check for various types INCLUDE(${CMAKE_SOURCE_DIR}/cmake/CheckTypes.cmake) -IF(WITH_SSL STREQUAL "OPENSSL") - FIND_PACKAGE(OpenSSL) - IF(OPENSSL_FOUND) - ADD_DEFINITIONS(-DHAVE_OPENSSL -DHAVE_SSL) - SET(SSL_SOURCES "${CMAKE_SOURCE_DIR}/libmariadb/secure/openssl.c") - SET(SSL_LIBRARIES ${OPENSSL_LIBRARIES} ${OPENSSL_CRYPTO_LIBRARIES}) +IF(NOT WITH_SSL) + IF(WIN32) + SET(WITH_SSL "SCHANNEL") ELSE() - MESSAGE(FATAL "OpenSSL not found") - ENDIF() -ENDIF() -IF(WITH_SSL STREQUAL "GNUTLS") - FIND_PACKAGE(GnuTLS) - IF(GNUTLS_FOUND) - ADD_DEFINITIONS(-DHAVE_GNUTLS -DHAVE_SSL) - SET(SSL_SOURCES "${CMAKE_SOURCE_DIR}/libmariadb/secure/gnutls.c") - SET(SSL_LIBRARIES ${GNUTLS_LIBRARY}) - ELSE() - MESSAGE(FATAL "GnuTLS not found") - ENDIF() -ENDIF() -IF(WIN32) - IF(WITH_SSL STREQUAL "SCHANNEL") - MESSAGE(STATUS "SSL_TYPE ${SSL_TYPE}") - ADD_DEFINITIONS(-DHAVE_SCHANNEL -DHAVE_SSL) - SET(SSL_SOURCES "${CMAKE_SOURCE_DIR}/libmariadb/secure/schannel.c" "${CMAKE_SOURCE_DIR}/libmariadb/secure/ma_schannel.c") - INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/plugins/pvio/") + SET(WITH_SSL "OPENSSL") ENDIF() ENDIF() -MARK_AS_ADVANCED(SSL_SOURCES) +IF(NOT WITH_SSL STREQUAL "OFF") + IF(WITH_SSL STREQUAL "OPENSSL") + FIND_PACKAGE(OpenSSL) + IF(OPENSSL_FOUND) + ADD_DEFINITIONS(-DHAVE_OPENSSL -DHAVE_SSL) + SET(SSL_SOURCES "${CMAKE_SOURCE_DIR}/libmariadb/secure/openssl.c") + SET(SSL_LIBRARIES ${OPENSSL_LIBRARIES} ${OPENSSL_CRYPTO_LIBRARIES}) + ELSE() + MESSAGE(FATAL "OpenSSL not found") + ENDIF() + ENDIF() + IF(WITH_SSL STREQUAL "GNUTLS") + FIND_PACKAGE(GnuTLS) + IF(GNUTLS_FOUND) + ADD_DEFINITIONS(-DHAVE_GNUTLS -DHAVE_SSL) + SET(SSL_SOURCES "${CMAKE_SOURCE_DIR}/libmariadb/secure/gnutls.c") + SET(SSL_LIBRARIES ${GNUTLS_LIBRARY}) + ELSE() + MESSAGE(FATAL "GnuTLS not found") + ENDIF() + ENDIF() + IF(WIN32) + IF(WITH_SSL STREQUAL "SCHANNEL") + MESSAGE(STATUS "SSL_TYPE ${SSL_TYPE}") + ADD_DEFINITIONS(-DHAVE_SCHANNEL -DHAVE_SSL) + SET(SSL_SOURCES "${CMAKE_SOURCE_DIR}/libmariadb/secure/schannel.c" "${CMAKE_SOURCE_DIR}/libmariadb/secure/ma_schannel.c") + INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/plugins/pvio/") + ENDIF() + ENDIF() - -IF(WITH_SQLITE) - ADD_DEFINITIONS(-DHAVE_SQLITE) + MARK_AS_ADVANCED(SSL_SOURCES) ENDIF() IF(NOT WIN32) diff --git a/include/errmsg.h b/include/errmsg.h index 55c5a649..ff795a7b 100644 --- a/include/errmsg.h +++ b/include/errmsg.h @@ -76,6 +76,7 @@ extern const char *mariadb_client_errors[]; /* Error messages */ #define CR_NO_STMT_METADATA 2052 #define CR_NOT_IMPLEMENTED 2054 #define CR_SERVER_LOST_EXTENDED 2055 +#define CR_STMT_CLOSED 2056 #define CR_NEW_STMT_METADATA 2057 #define CR_AUTH_PLUGIN_CANNOT_LOAD 2058 #define CR_ALREADY_CONNECTED 2059 diff --git a/include/ma_pvio.h b/include/ma_pvio.h index 5e87ad42..0fada961 100644 --- a/include/ma_pvio.h +++ b/include/ma_pvio.h @@ -16,9 +16,17 @@ struct st_ma_pvio_methods; typedef struct st_ma_pvio_methods PVIO_METHODS; -#define IS_ASYNC_ACTIVE(a) \ - ((a)->mysql->options.extension && (a)->mysql->options.extension->async_context && \ - (a)->mysql->options.extension->async_context->active) +#define IS_PVIO_ASYNC(a) \ + ((a)->mysql && (a)->mysql->options.extension && (a)->mysql->options.extension->async_context) + +#define IS_PVIO_ASYNC_ACTIVE(a) \ + (IS_PVIO_ASYNC(a)&& (a)->mysql->options.extension->async_context->active) + +#define IS_MYSQL_ASYNC(a) \ + ((a)->options.extension && (a)->options.extension->async_context) + +#define IS_MYSQL_ASYNC_ACTIVE(a) \ + (IS_MYSQL_ASYNC(a)&& (a)->options.extension->async_context->active) #ifndef ssl_defined #define ssl_defined @@ -101,6 +109,7 @@ struct st_ma_pvio_methods my_bool (*get_handle)(MARIADB_PVIO *pvio, void *handle); my_bool (*is_blocking)(MARIADB_PVIO *pvio); my_bool (*is_alive)(MARIADB_PVIO *pvio); + my_bool (*has_data)(MARIADB_PVIO *pvio, ssize_t *data_len); }; /* Function prototypes */ @@ -121,5 +130,6 @@ int ma_pvio_wait_io_or_timeout(MARIADB_PVIO *pvio, my_bool is_read, int timeout) my_bool ma_pvio_connect(MARIADB_PVIO *pvio, MA_PVIO_CINFO *cinfo); my_bool ma_pvio_is_alive(MARIADB_PVIO *pvio); my_bool ma_pvio_get_handle(MARIADB_PVIO *pvio, void *handle); +my_bool ma_pvio_has_data(MARIADB_PVIO *pvio, ssize_t *length); #endif /* _ma_pvio_h_ */ diff --git a/libmariadb/errmsg.c b/libmariadb/errmsg.c index 43433031..8ae0fa04 100644 --- a/libmariadb/errmsg.c +++ b/libmariadb/errmsg.c @@ -136,7 +136,7 @@ const char *client_errors[]= /* 2053 */ "", /* 2054 */ "This feature is not implemented or disabled", /* 2055 */ "Lost connection to MySQL server at '%s', system error: %d", -/* 2056 */ "", +/* 2056 */ "Server closed statement due to a prior %s function call", /* 2057 */ "The number of parameters in bound buffers differs from number of columns in resultset", /* 2058 */ "Plugin %s could not be loaded: %s", /* 2059 */ "Can't connect twice. Already connected", diff --git a/libmariadb/libmariadb.c b/libmariadb/libmariadb.c index ae577c36..1590df17 100644 --- a/libmariadb/libmariadb.c +++ b/libmariadb/libmariadb.c @@ -384,6 +384,13 @@ mthd_my_send_cmd(MYSQL *mysql,enum enum_server_command command, const char *arg, if (!arg) arg=""; + /* check if connection kills itself */ + if (command == COM_PROCESS_KILL) + { + unsigned long thread_id= uint4korr(arg); + if (thread_id == mysql->thread_id) + skipp_check= 1; + } if (net_write_command(net,(uchar) command,arg, length ? length : (ulong) strlen(arg))) { @@ -1684,10 +1691,36 @@ error: DBUG_RETURN(0); } +struct my_hook_data { + MYSQL *orig_mysql; + MYSQL *new_mysql; + /* This is always NULL currently, but restoring does not hurt just in case. */ + MARIADB_PVIO *orig_pvio; +}; +/* + Callback hook to make the new VIO accessible via the old MYSQL to calling + application when suspending a non-blocking call during automatic reconnect. +*/ +static void +my_suspend_hook(my_bool suspend, void *data) +{ + struct my_hook_data *hook_data= (struct my_hook_data *)data; + if (suspend) + { + hook_data->orig_pvio= hook_data->orig_mysql->net.pvio; + hook_data->orig_mysql->net.pvio= hook_data->new_mysql->net.pvio; + } + else + hook_data->orig_mysql->net.pvio= hook_data->orig_pvio; +} + + static my_bool mysql_reconnect(MYSQL *mysql) { MYSQL tmp_mysql; - LIST *li_stmt= mysql->stmts; + struct my_hook_data hook_data; + struct mysql_async_context *ctxt= NULL; + DBUG_ENTER("mysql_reconnect"); if (!mysql->reconnect || @@ -1705,19 +1738,21 @@ static my_bool mysql_reconnect(MYSQL *mysql) /* don't reread options from configuration files */ tmp_mysql.options.my_cnf_group= tmp_mysql.options.my_cnf_file= NULL; - /* make sure that we reconnect with the same character set */ - if (!tmp_mysql.options.charset_name || - strcmp(tmp_mysql.options.charset_name, mysql->charset->csname)) + if (IS_MYSQL_ASYNC_ACTIVE(mysql)) { - my_free(tmp_mysql.options.charset_name); - tmp_mysql.options.charset_name= my_strdup(mysql->charset->csname, MYF(MY_WME)); + hook_data.orig_mysql= mysql; + hook_data.new_mysql= &tmp_mysql; + hook_data.orig_pvio= mysql->net.pvio; + my_context_install_suspend_resume_hook(ctxt, my_suspend_hook, &hook_data); } - tmp_mysql.reconnect= mysql->reconnect; if (!mysql_real_connect(&tmp_mysql,mysql->host,mysql->user,mysql->passwd, mysql->db, mysql->port, mysql->unix_socket, - mysql->client_flag | CLIENT_REMEMBER_OPTIONS)) + mysql->client_flag | CLIENT_REMEMBER_OPTIONS) || + mysql_set_character_set(&tmp_mysql, mysql->charset->csname)) { + if (ctxt) + my_context_install_suspend_resume_hook(ctxt, NULL, NULL); /* don't free options (CONC-118) */ memset(&tmp_mysql.options, 0, sizeof(struct st_mysql_options)); my_set_error(mysql, tmp_mysql.net.last_errno, @@ -1727,19 +1762,7 @@ static my_bool mysql_reconnect(MYSQL *mysql) DBUG_RETURN(1); } - /* reset the connection in all active statements - todo: check stmt->mysql in mysql_stmt* functions ! */ - for (;li_stmt;li_stmt= li_stmt->next) - { - MYSQL_STMT *stmt= (MYSQL_STMT *)li_stmt->data; - - if (stmt->state != MYSQL_STMT_INITTED) - { - stmt->state= MYSQL_STMT_INITTED; - SET_CLIENT_STMT_ERROR(stmt, CR_SERVER_LOST, SQLSTATE_UNKNOWN, 0); - } - } - + tmp_mysql.reconnect= mysql->reconnect; tmp_mysql.free_me= mysql->free_me; tmp_mysql.stmts= mysql->stmts; mysql->stmts= NULL; @@ -1747,16 +1770,31 @@ static my_bool mysql_reconnect(MYSQL *mysql) /* Don't free options, we moved them to tmp_mysql */ memset(&mysql->options, 0, sizeof(mysql->options)); mysql->free_me=0; - mysql->stmts= NULL; mysql_close(mysql); *mysql=tmp_mysql; - mysql->reconnect= 1; + mysql->net.pvio->mysql= mysql; net_clear(&mysql->net); mysql->affected_rows= ~(my_ulonglong) 0; DBUG_RETURN(0); } +static void ma_invalidate_stmts(MYSQL *mysql, const char *function_name) +{ + if (mysql->stmts) + { + LIST *li_stmt= mysql->stmts; + + for (; li_stmt; li_stmt= li_stmt->next) + { + MYSQL_STMT *stmt= (MYSQL_STMT *)li_stmt->data; + stmt->mysql= NULL; + SET_CLIENT_STMT_ERROR(stmt, CR_STMT_CLOSED, SQLSTATE_UNKNOWN, function_name); + } + mysql->stmts= NULL; + } +} + /************************************************************************** ** Change user and database **************************************************************************/ @@ -1786,36 +1824,33 @@ my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user, else mysql->charset=default_charset_info; - mysql->user= (char *)user; - mysql->passwd= (char *)passwd; - mysql->db= (char *)db; + mysql->user= my_strdup(user ? user : "", MYF(MY_WME)); + mysql->passwd= my_strdup(passwd ? passwd : "", MYF(MY_WME)); + + /* db will be set in run_plugin_auth */ + mysql->db= 0; rc= run_plugin_auth(mysql, 0, 0, 0, db); + /* COM_CHANGE_USER always releases prepared statements, so we need to invalidate them */ + ma_invalidate_stmts(mysql, "mysql_change_user()"); + if (rc==0) { - LIST *li_stmt= mysql->stmts; my_free(s_user); my_free(s_passwd); my_free(s_db); - if (!(mysql->user= my_strdup(user,MYF(MY_WME))) || - !(mysql->passwd=my_strdup(passwd,MYF(MY_WME))) || - !(mysql->db= db ? my_strdup(db,MYF(MY_WME)) : 0)) + if (db && !(mysql->db= my_strdup(db,MYF(MY_WME)))) { SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate, 0); rc= 1; } - - for (;li_stmt;li_stmt= li_stmt->next) - { - MYSQL_STMT *stmt= (MYSQL_STMT *)li_stmt->data; - stmt->mysql= NULL; - SET_CLIENT_STMT_ERROR(stmt, CR_SERVER_LOST, SQLSTATE_UNKNOWN, 0); - }/* detach stmts */ - mysql->stmts= NULL; - } else { + my_free(mysql->user); + my_free(mysql->passwd); + my_free(mysql->db); + mysql->user= s_user; mysql->passwd= s_passwd; mysql->db= s_db; @@ -1870,6 +1905,7 @@ static void mysql_close_options(MYSQL *mysql) my_free(mysql->options.my_cnf_group); my_free(mysql->options.charset_dir); my_free(mysql->options.charset_name); + my_free(mysql->options.bind_address); my_free(mysql->options.ssl_key); my_free(mysql->options.ssl_cert); my_free(mysql->options.ssl_ca); @@ -1946,12 +1982,9 @@ void mysql_close_slow_part(MYSQL *mysql) void STDCALL mysql_close(MYSQL *mysql) { - MYSQL_STMT *stmt; DBUG_ENTER("mysql_close"); if (mysql) /* Some simple safety */ { - LIST *li_stmt= mysql->stmts; - if (mysql->net.conn_hdlr && mysql->net.conn_hdlr->data) { void *p= (void *)mysql->net.conn_hdlr; @@ -1963,14 +1996,8 @@ mysql_close(MYSQL *mysql) if (mysql->methods) mysql->methods->db_close(mysql); - /* reset the connection in all active statements - todo: check stmt->mysql in mysql_stmt* functions ! */ - for (;li_stmt;li_stmt= li_stmt->next) - { - stmt= (MYSQL_STMT *)li_stmt->data; - stmt->mysql= NULL; - SET_CLIENT_STMT_ERROR(stmt, CR_SERVER_LOST, SQLSTATE_UNKNOWN, 0); - } + /* reset the connection in all active statements */ + ma_invalidate_stmts(mysql, "mysql_close()"); mysql_close_memory(mysql); mysql_close_options(mysql); mysql->host_info=mysql->user=mysql->passwd=mysql->db=0; diff --git a/libmariadb/ma_pvio.c b/libmariadb/ma_pvio.c index 420d83f2..2f9d2744 100644 --- a/libmariadb/ma_pvio.c +++ b/libmariadb/ma_pvio.c @@ -185,7 +185,7 @@ static size_t ma_pvio_read_async(MARIADB_PVIO *pvio, uchar *buffer, size_t lengt /* todo: async */ if (pvio->methods->async_read) res= pvio->methods->async_read(pvio, buffer, length); - if (res >= 0 /* || IS_BLOCKING_ERROR()*/) + if (res >= 0 || IS_BLOCKING_ERROR()) return res; b->events_to_wait_for= MYSQL_WAIT_READ; if (timeout >= 0) @@ -211,14 +211,14 @@ size_t ma_pvio_read(MARIADB_PVIO *pvio, uchar *buffer, size_t length) if (!pvio) return -1; - if (pvio && pvio->async_context && pvio->async_context->active) + if (IS_PVIO_ASYNC_ACTIVE(pvio)) { r= ma_pvio_read_async(pvio, buffer, length); goto end; } else { - if (pvio->async_context) + if (IS_PVIO_ASYNC(pvio)) { /* If switching from non-blocking to blocking API usage, set the socket @@ -232,8 +232,10 @@ size_t ma_pvio_read(MARIADB_PVIO *pvio, uchar *buffer, size_t length) /* secure connection */ #ifdef HAVE_SSL if (pvio->cssl) + { r= ma_pvio_ssl_read(pvio->cssl, buffer, length); - else + goto end; + } #endif if (pvio->methods->read) r= pvio->methods->read(pvio, buffer, length); @@ -330,32 +332,24 @@ size_t ma_pvio_write(MARIADB_PVIO *pvio, const uchar *buffer, size_t length) if (!pvio) return -1; - if (pvio_callback) - { - void (*callback)(int mode, MYSQL *mysql, const uchar *buffer, size_t length); - LIST *p= pvio_callback; - while (p) - { - callback= p->data; - callback(1, pvio->mysql, buffer, length); - p= p->next; - } - } - /* secure connection */ #ifdef HAVE_SSL if (pvio->cssl) + { r= ma_pvio_ssl_write(pvio->cssl, buffer, length); + goto end; + } else #endif - if (IS_ASYNC_ACTIVE(pvio)) +// printf("No ssl (write): %x\n", pvio->cssl); + if (IS_PVIO_ASYNC_ACTIVE(pvio)) { r= ma_pvio_write_async(pvio, buffer, length); goto end; } else { - if (pvio->async_context) + if (IS_PVIO_ASYNC(pvio)) { /* If switching from non-blocking to blocking API usage, set the socket @@ -408,13 +402,45 @@ my_bool ma_pvio_get_handle(MARIADB_PVIO *pvio, void *handle) } /* }}} */ +/* {{{ ma_pvio_wait_async */ +static my_bool +ma_pvio_wait_async(struct mysql_async_context *b, enum enum_pvio_io_event event, + int timeout) +{ + switch (event) + { + case VIO_IO_EVENT_READ: + b->events_to_wait_for = MYSQL_WAIT_READ; + break; + case VIO_IO_EVENT_WRITE: + b->events_to_wait_for = MYSQL_WAIT_WRITE; + break; + case VIO_IO_EVENT_CONNECT: + b->events_to_wait_for = MYSQL_WAIT_WRITE | IF_WIN(0, MYSQL_WAIT_EXCEPT); + break; + } + + if (timeout >= 0) + { + b->events_to_wait_for |= MYSQL_WAIT_TIMEOUT; + b->timeout_value= timeout; + } + if (b->suspend_resume_hook) + (*b->suspend_resume_hook)(TRUE, b->suspend_resume_hook_user_data); + my_context_yield(&b->async_context); + if (b->suspend_resume_hook) + (*b->suspend_resume_hook)(FALSE, b->suspend_resume_hook_user_data); + return (b->events_occured & MYSQL_WAIT_TIMEOUT) ? 0 : 1; +} +/* }}} */ + /* {{{ ma_pvio_wait_io_or_timeout */ int ma_pvio_wait_io_or_timeout(MARIADB_PVIO *pvio, my_bool is_read, int timeout) { - if (pvio && pvio->async_context && pvio->async_context->active) - return my_io_wait_async(pvio->async_context, - (is_read) ? VIO_IO_EVENT_READ : VIO_IO_EVENT_WRITE, - timeout); + if (IS_PVIO_ASYNC_ACTIVE(pvio)) + return ma_pvio_wait_async(pvio->mysql->options.extension->async_context, + (is_read) ? VIO_IO_EVENT_READ : VIO_IO_EVENT_WRITE, + timeout); if (pvio && pvio->methods->wait_io_or_timeout) @@ -450,6 +476,19 @@ my_bool ma_pvio_is_blocking(MARIADB_PVIO *pvio) } /* }}} */ +/* {{{ ma_pvio_has_data */ +my_bool ma_pvio_has_data(MARIADB_PVIO *pvio, ssize_t *data_len) +{ + /* check if we still have unread data in cache */ + if (pvio->cache) + if (pvio->cache_pos > pvio->cache) + return pvio->cache_pos - pvio->cache; + if (pvio && pvio->methods->has_data) + return pvio->methods->has_data(pvio, data_len); + return 1; +} +/* }}} */ + #ifdef HAVE_SSL /* {{{ my_bool ma_pvio_start_ssl */ my_bool ma_pvio_start_ssl(MARIADB_PVIO *pvio) @@ -463,7 +502,7 @@ my_bool ma_pvio_start_ssl(MARIADB_PVIO *pvio) } if (ma_pvio_ssl_connect(pvio->cssl)) { - my_free((gptr)pvio->cssl); + my_free(pvio->cssl); pvio->cssl= NULL; return 1; } diff --git a/libmariadb/my_stmt.c b/libmariadb/my_stmt.c index 5f4b9f98..7f0355b5 100644 --- a/libmariadb/my_stmt.c +++ b/libmariadb/my_stmt.c @@ -415,7 +415,8 @@ unsigned char *mysql_net_store_length(unsigned char *packet, size_t length) int store_param(MYSQL_STMT *stmt, int column, unsigned char **p) { DBUG_ENTER("store_param"); - DBUG_PRINT("info", ("column: %d type: x%x", column, stmt->params[column].buffer_type)); + DBUG_PRINT("info", ("column: %d type: %d", column, stmt->params[column].buffer_type)); + printf("type: %d\n", column, stmt->params[column].buffer_type); switch (stmt->params[column].buffer_type) { case MYSQL_TYPE_TINY: int1store(*p, *(uchar *)stmt->params[column].buffer); diff --git a/libmariadb/mysql_async.c b/libmariadb/mysql_async.c index 00581dbd..4a86ab90 100644 --- a/libmariadb/mysql_async.c +++ b/libmariadb/mysql_async.c @@ -134,37 +134,6 @@ my_connect_async(MARIADB_PVIO *pvio, #endif #endif -my_bool -my_io_wait_async(struct mysql_async_context *b, enum enum_pvio_io_event event, - int timeout) -{ - switch (event) - { - case VIO_IO_EVENT_READ: - b->events_to_wait_for = MYSQL_WAIT_READ; - break; - case VIO_IO_EVENT_WRITE: - b->events_to_wait_for = MYSQL_WAIT_WRITE; - break; - case VIO_IO_EVENT_CONNECT: - b->events_to_wait_for = MYSQL_WAIT_WRITE | IF_WIN(0, MYSQL_WAIT_EXCEPT); - break; - } - - if (timeout >= 0) - { - b->events_to_wait_for |= MYSQL_WAIT_TIMEOUT; - b->timeout_value= timeout; - } - if (b->suspend_resume_hook) - (*b->suspend_resume_hook)(TRUE, b->suspend_resume_hook_user_data); - my_context_yield(&b->async_context); - if (b->suspend_resume_hook) - (*b->suspend_resume_hook)(FALSE, b->suspend_resume_hook_user_data); - return (b->events_occured & MYSQL_WAIT_TIMEOUT) ? 0 : 1; -} - - #ifdef HAVE_SSL_FIXME static my_bool my_ssl_async_check_result(int res, struct mysql_async_context *b, MARIADB_SSL *cssl) diff --git a/libmariadb/net.c b/libmariadb/net.c index 46d8b11e..8c657d2a 100644 --- a/libmariadb/net.c +++ b/libmariadb/net.c @@ -179,67 +179,11 @@ static my_bool net_realloc(NET *net, size_t length) DBUG_RETURN(0); } - -/* check if the socket is still alive */ -static my_bool net_check_socket_status(my_socket sock) -{ -#ifndef _WIN32 - struct pollfd poll_fd; -#else - FD_SET sfds; - struct timeval tv= {0,0}; -#endif - int res; -#ifndef _WIN32 - memset(&poll_fd, 0, sizeof(struct pollfd)); - poll_fd.events= POLLPRI | POLLIN; - poll_fd.fd= sock; - - res= poll(&poll_fd, 1, 0); - if (res <= 0) /* timeout or error */ - return FALSE; - if (!(poll_fd.revents & (POLLIN | POLLPRI))) - return FALSE; - return TRUE; -#else - /* We can't use the WSAPoll function, it's broken :-( - (see Windows 8 Bugs 309411 - WSAPoll does not report failed connections) - Instead we need to use select function: - If TIMEVAL is initialized to {0, 0}, select will return immediately; - this is used to poll the state of the selected sockets. - */ - FD_ZERO(&sfds); - FD_SET(sock, &sfds); - - res= select((int)sock + 1, &sfds, NULL, NULL, &tv); - if (res > 0 && FD_ISSET(sock, &sfds)) - return TRUE; - return FALSE; -#endif - -} - - /* Remove unwanted characters from connection */ +/* Remove unwanted characters from connection */ void net_clear(NET *net) { - my_socket sock; DBUG_ENTER("net_clear"); - - ma_pvio_get_handle(net->pvio, &sock); - - /* see conc-71: we need to check the socket status first: - if the socket is dead we set net->error, so net_flush - will report an error */ - while (net_check_socket_status(sock)) - { - if ((ssize_t)ma_pvio_cache_read(net->pvio, (gptr)net->buff, (size_t) net->max_packet) <= 0) - { - net->error= 2; - DBUG_PRINT("info", ("socket disconnected")); - DBUG_VOID_RETURN; - } - } net->compress_pkt_nr= net->pkt_nr=0; /* Ready for new command */ net->write_pos=net->buff; DBUG_VOID_RETURN; diff --git a/libmariadb/secure/gnutls.c b/libmariadb/secure/gnutls.c index 45ab5ead..cfa89006 100644 --- a/libmariadb/secure/gnutls.c +++ b/libmariadb/secure/gnutls.c @@ -235,6 +235,12 @@ ssize_t ma_ssl_pull(gnutls_transport_ptr_t ptr, void* data, size_t len) return rc; } +static int ma_ssl_pull_timeout(gnutls_transport_ptr_t ptr, unsigned int ms) +{ + MARIADB_PVIO *pvio= (MARIADB_PVIO *)ptr; + return pvio->methods->wait_io_or_timeout(pvio, 0, ms); +} + my_bool ma_ssl_connect(MARIADB_SSL *cssl) { gnutls_session_t ssl = (gnutls_session_t)cssl->ssl; @@ -257,7 +263,8 @@ my_bool ma_ssl_connect(MARIADB_SSL *cssl) gnutls_transport_set_ptr(ssl, pvio); gnutls_transport_set_push_function(ssl, ma_ssl_push); gnutls_transport_set_pull_function(ssl, ma_ssl_pull); - gnutls_handshake_set_timeout(ssl, mysql->options.connect_timeout); + gnutls_transport_set_pull_timeout_function(ssl, ma_ssl_pull_timeout); + gnutls_handshake_set_timeout(ssl, pvio->timeout[PVIO_CONNECT_TIMEOUT]); do { ret = gnutls_handshake(ssl); @@ -417,3 +424,4 @@ unsigned int ma_ssl_get_finger_print(MARIADB_SSL *cssl, unsigned char *fp, unsig } #endif /* HAVE_GNUTLS */ + diff --git a/plugins/pvio/pvio_socket.c b/plugins/pvio/pvio_socket.c index 5a1c6eb8..01df4775 100644 --- a/plugins/pvio/pvio_socket.c +++ b/plugins/pvio/pvio_socket.c @@ -76,6 +76,7 @@ int pvio_socket_keepalive(MARIADB_PVIO *pvio); my_bool pvio_socket_get_handle(MARIADB_PVIO *pvio, void *handle); my_bool pvio_socket_is_blocking(MARIADB_PVIO *pvio); my_bool pvio_socket_is_alive(MARIADB_PVIO *pvio); +my_bool pvio_socket_has_data(MARIADB_PVIO *pvio, ssize_t *data_len); static int pvio_socket_init(char *unused1, size_t unused2, @@ -98,7 +99,8 @@ struct st_ma_pvio_methods pvio_socket_methods= { pvio_socket_keepalive, pvio_socket_get_handle, pvio_socket_is_blocking, - pvio_socket_is_alive + pvio_socket_is_alive, + pvio_socket_has_data }; #ifndef HAVE_SOCKET_DYNAMIC @@ -913,11 +915,14 @@ my_bool pvio_socket_is_alive(MARIADB_PVIO *pvio) #ifndef _WIN32 memset(&poll_fd, 0, sizeof(struct pollfd)); poll_fd.events= POLLPRI | POLLIN; + poll_fd.revents= POLLERR; poll_fd.fd= csock->socket; res= poll(&poll_fd, 1, 0); if (res <= 0) /* timeout or error */ return FALSE; + if (!(poll_fd.revents & POLLERR)) + return FALSE; if (!(poll_fd.revents & (POLLIN | POLLPRI))) return FALSE; return TRUE; @@ -931,10 +936,35 @@ my_bool pvio_socket_is_alive(MARIADB_PVIO *pvio) FD_ZERO(&sfds); FD_SET(csock->socket, &sfds); - res= select((int)+csock->socket + 1, &sfds, NULL, NULL, &tv); + res= select((int)csock->socket + 1, &sfds, NULL, NULL, &tv); if (res > 0 && FD_ISSET(csock->socket, &sfds)) return TRUE; return FALSE; #endif } /* }}} */ + +/* {{{ my_boool pvio_socket_has_data */ +my_bool pvio_socket_has_data(MARIADB_PVIO *pvio, ssize_t *data_len) +{ + struct st_pvio_socket *csock= NULL; + char tmp_buf[1024]; + ssize_t len; + my_bool mode; + + if (!pvio || !pvio->data) + return 0; + + csock= (struct st_pvio_socket *)pvio->data; + /* MSG_PEEK: Peeks at the incoming data. The data is copied into the buffer, + but is not removed from the input queue. + */ + pvio_socket_blocking(pvio, 0, &mode); + len= recv(csock->socket, &tmp_buf, sizeof(tmp_buf), MSG_PEEK); + pvio_socket_blocking(pvio, mode, 0); + if (len < 0) + return 1; + *data_len= len; + return 0; +} +/* }}} */ diff --git a/unittest/libmariadb/basic-t.c b/unittest/libmariadb/basic-t.c index 74cc4b0c..4e535852 100644 --- a/unittest/libmariadb/basic-t.c +++ b/unittest/libmariadb/basic-t.c @@ -39,8 +39,7 @@ static int test_conc75(MYSQL *my) mysql= mysql_init(NULL); - mysql_options(mysql, MYSQL_OPT_RECONNECT,(const char *)"true"); - + mysql->reconnect= 1; mysql_real_connect(mysql, hostname, username, password, schema, port, socketname, 0| CLIENT_MULTI_RESULTS | CLIENT_REMEMBER_OPTIONS); rc= mysql_query(mysql, "DROP TABLE IF EXISTS a"); diff --git a/unittest/libmariadb/charset.c b/unittest/libmariadb/charset.c index 662657cd..b5cdbf89 100644 --- a/unittest/libmariadb/charset.c +++ b/unittest/libmariadb/charset.c @@ -487,6 +487,7 @@ static int bug30472_retrieve_charset_info(MYSQL *con, row= mysql_fetch_row(rs); FAIL_IF(!row, "Couldn't fetch row"); strcpy(character_set_client, row[1]); + diag("cs: %s", row[1]); mysql_free_result(rs); rc= mysql_query(con, "SHOW VARIABLES LIKE 'character_set_results'"); diff --git a/unittest/libmariadb/misc.c b/unittest/libmariadb/misc.c index c658dc65..ede78ace 100644 --- a/unittest/libmariadb/misc.c +++ b/unittest/libmariadb/misc.c @@ -964,7 +964,6 @@ static int test_conc117(MYSQL *mysql) mysql_kill(my, mysql_thread_id(my)); sleep(5); - strcpy(my->host, "A"); my->reconnect= 1; mysql_query(my, "SET @a:=1"); diff --git a/unittest/libmariadb/my_test.h b/unittest/libmariadb/my_test.h index 2aec2a29..e862ced1 100644 --- a/unittest/libmariadb/my_test.h +++ b/unittest/libmariadb/my_test.h @@ -374,7 +374,7 @@ MYSQL *test_connect(struct my_tests_st *test) { return(NULL); } - mysql_options(mysql, MYSQL_REPORT_DATA_TRUNCATION, "1"); + mysql_options(mysql, MYSQL_REPORT_DATA_TRUNCATION, &i); mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT, (const char *)&i); /* option handling */ diff --git a/unittest/libmariadb/ps_bugs.c b/unittest/libmariadb/ps_bugs.c index ccf4b185..bd072646 100644 --- a/unittest/libmariadb/ps_bugs.c +++ b/unittest/libmariadb/ps_bugs.c @@ -523,10 +523,12 @@ static int test_bug12744(MYSQL *mysql) check_stmt_rc(rc, stmt); /* set reconnect, kill and ping to reconnect */ + rc= mysql_query(mysql, "SET @a:=1"); + check_mysql_rc(rc, mysql); rc= mysql_options(mysql, MYSQL_OPT_RECONNECT, "1"); check_mysql_rc(rc, mysql); rc= mysql_kill(mysql, mysql_thread_id(mysql)); - //check_mysql_rc(rc, mysql); + check_mysql_rc(rc, mysql); sleep(2); rc= mysql_ping(mysql); @@ -542,10 +544,10 @@ static int test_bug1500(MYSQL *mysql) { MYSQL_STMT *stmt; MYSQL_BIND my_bind[3]; - int rc; + int rc= 0; int32 int_data[3]= {2, 3, 4}; - const char *data; - const char *query; + char *data; + char *query; rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_bg1500"); @@ -1084,6 +1086,8 @@ static int test_bug20152(MYSQL *mysql) my_bind[0].buffer_type= MYSQL_TYPE_DATE; my_bind[0].buffer= (void*)&tm; + memset(&tm, 0, sizeof(MYSQL_TIME)); + tm.year = 2006; tm.month = 6; tm.day = 18; @@ -2180,11 +2184,11 @@ static int test_bug4026(MYSQL *mysql) rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); check_stmt_rc(rc, stmt); /* Bind input buffers */ - memset(my_bind, '\0', sizeof(my_bind)); - memset(&time_in, '\0', sizeof(time_in)); - memset(&time_out, '\0', sizeof(time_out)); - memset(&datetime_in, '\0', sizeof(datetime_in)); - memset(&datetime_out, '\0', sizeof(datetime_out)); + memset(my_bind, '\0', sizeof(MYSQL_BIND) * 2); + memset(&time_in, '\0', sizeof(MYSQL_TIME)); + memset(&time_out, '\0', sizeof(MYSQL_TIME)); + memset(&datetime_in, '\0', sizeof(MYSQL_TIME)); + memset(&datetime_out, '\0', sizeof(MYSQL_TIME)); my_bind[0].buffer_type= MYSQL_TYPE_TIME; my_bind[0].buffer= (void *) &time_in; my_bind[1].buffer_type= MYSQL_TYPE_DATETIME; diff --git a/unittest/libmariadb/ssl.c.in b/unittest/libmariadb/ssl.c.in index d74a4e6a..b6e51965 100644 --- a/unittest/libmariadb/ssl.c.in +++ b/unittest/libmariadb/ssl.c.in @@ -680,6 +680,9 @@ const char *ssl_cert_finger_print= "@SSL_CERT_FINGER_PRINT@"; static int test_ssl_fp(MYSQL *unused) { MYSQL *my; + MYSQL_RES *res; + MYSQL_ROW row; + int rc; if (check_skip_ssl()) return SKIP; @@ -693,8 +696,22 @@ static int test_ssl_fp(MYSQL *unused) FAIL_IF(!mysql_real_connect(my, hostname, ssluser, sslpw, schema, port, socketname, 0), mysql_error(my)); - + FAIL_IF(check_cipher(my) != 0, "Invalid cipher"); + + mysql_query(my, "SET @a:=1"); + check_mysql_rc(rc, my); + + mysql_query(my, "SELECT @a"); + check_mysql_rc(rc, my); + + if ((res= mysql_store_result(my))) + { + row= mysql_fetch_row(res); + diag("@a:=%s", row[0]); + mysql_free_result(res); + } + mysql_close(my); return OK; } @@ -741,7 +758,7 @@ struct my_tests_st my_tests[] = { {"test_multi_ssl_connections", test_multi_ssl_connections, TEST_CONNECTION_NONE, 0, NULL, NULL}, {"test_conc_102", test_conc_102, TEST_CONNECTION_NEW, 0, NULL, NULL}, {"test_ssl_threads", test_ssl_threads, TEST_CONNECTION_NEW, 0, NULL, NULL}, - {"test_password_protected", test_password_protected, TEST_CONNECTION_NEW, 0, NULL, NULL}, + {"test_password_protected", test_password_protected, TEST_CONNECTION_NEW, 0, NULL, NULL}, {NULL, NULL, 0, 0, NULL, NULL} };