1
0
mirror of https://github.com/mariadb-corporation/mariadb-connector-c.git synced 2025-08-07 02:42:49 +03:00

Fix for asynchronous (reconnect)

Fixed memory leak after reconnect/change user
This commit is contained in:
Georg Richter
2015-11-19 16:55:25 +01:00
parent 0af129fe80
commit f30bb95c6a
17 changed files with 267 additions and 213 deletions

View File

@@ -165,40 +165,45 @@ INCLUDE(${CMAKE_SOURCE_DIR}/cmake/CheckFunctions.cmake)
# check for various types # check for various types
INCLUDE(${CMAKE_SOURCE_DIR}/cmake/CheckTypes.cmake) INCLUDE(${CMAKE_SOURCE_DIR}/cmake/CheckTypes.cmake)
IF(WITH_SSL STREQUAL "OPENSSL") IF(NOT WITH_SSL)
FIND_PACKAGE(OpenSSL) IF(WIN32)
IF(OPENSSL_FOUND) SET(WITH_SSL "SCHANNEL")
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() ELSE()
MESSAGE(FATAL "OpenSSL not found") SET(WITH_SSL "OPENSSL")
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()
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()
MARK_AS_ADVANCED(SSL_SOURCES)
IF(WITH_SQLITE)
ADD_DEFINITIONS(-DHAVE_SQLITE)
ENDIF() ENDIF()
IF(NOT WIN32) IF(NOT WIN32)

View File

@@ -76,6 +76,7 @@ extern const char *mariadb_client_errors[]; /* Error messages */
#define CR_NO_STMT_METADATA 2052 #define CR_NO_STMT_METADATA 2052
#define CR_NOT_IMPLEMENTED 2054 #define CR_NOT_IMPLEMENTED 2054
#define CR_SERVER_LOST_EXTENDED 2055 #define CR_SERVER_LOST_EXTENDED 2055
#define CR_STMT_CLOSED 2056
#define CR_NEW_STMT_METADATA 2057 #define CR_NEW_STMT_METADATA 2057
#define CR_AUTH_PLUGIN_CANNOT_LOAD 2058 #define CR_AUTH_PLUGIN_CANNOT_LOAD 2058
#define CR_ALREADY_CONNECTED 2059 #define CR_ALREADY_CONNECTED 2059

View File

@@ -16,9 +16,17 @@
struct st_ma_pvio_methods; struct st_ma_pvio_methods;
typedef struct st_ma_pvio_methods PVIO_METHODS; typedef struct st_ma_pvio_methods PVIO_METHODS;
#define IS_ASYNC_ACTIVE(a) \ #define IS_PVIO_ASYNC(a) \
((a)->mysql->options.extension && (a)->mysql->options.extension->async_context && \ ((a)->mysql && (a)->mysql->options.extension && (a)->mysql->options.extension->async_context)
(a)->mysql->options.extension->async_context->active)
#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 #ifndef ssl_defined
#define 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 (*get_handle)(MARIADB_PVIO *pvio, void *handle);
my_bool (*is_blocking)(MARIADB_PVIO *pvio); my_bool (*is_blocking)(MARIADB_PVIO *pvio);
my_bool (*is_alive)(MARIADB_PVIO *pvio); my_bool (*is_alive)(MARIADB_PVIO *pvio);
my_bool (*has_data)(MARIADB_PVIO *pvio, ssize_t *data_len);
}; };
/* Function prototypes */ /* 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_connect(MARIADB_PVIO *pvio, MA_PVIO_CINFO *cinfo);
my_bool ma_pvio_is_alive(MARIADB_PVIO *pvio); my_bool ma_pvio_is_alive(MARIADB_PVIO *pvio);
my_bool ma_pvio_get_handle(MARIADB_PVIO *pvio, void *handle); 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_ */ #endif /* _ma_pvio_h_ */

View File

@@ -136,7 +136,7 @@ const char *client_errors[]=
/* 2053 */ "", /* 2053 */ "",
/* 2054 */ "This feature is not implemented or disabled", /* 2054 */ "This feature is not implemented or disabled",
/* 2055 */ "Lost connection to MySQL server at '%s', system error: %d", /* 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", /* 2057 */ "The number of parameters in bound buffers differs from number of columns in resultset",
/* 2058 */ "Plugin %s could not be loaded: %s", /* 2058 */ "Plugin %s could not be loaded: %s",
/* 2059 */ "Can't connect twice. Already connected", /* 2059 */ "Can't connect twice. Already connected",

View File

@@ -384,6 +384,13 @@ mthd_my_send_cmd(MYSQL *mysql,enum enum_server_command command, const char *arg,
if (!arg) if (!arg)
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, if (net_write_command(net,(uchar) command,arg,
length ? length : (ulong) strlen(arg))) length ? length : (ulong) strlen(arg)))
{ {
@@ -1684,10 +1691,36 @@ error:
DBUG_RETURN(0); 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) static my_bool mysql_reconnect(MYSQL *mysql)
{ {
MYSQL tmp_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"); DBUG_ENTER("mysql_reconnect");
if (!mysql->reconnect || if (!mysql->reconnect ||
@@ -1705,19 +1738,21 @@ static my_bool mysql_reconnect(MYSQL *mysql)
/* don't reread options from configuration files */ /* don't reread options from configuration files */
tmp_mysql.options.my_cnf_group= tmp_mysql.options.my_cnf_file= NULL; tmp_mysql.options.my_cnf_group= tmp_mysql.options.my_cnf_file= NULL;
/* make sure that we reconnect with the same character set */ if (IS_MYSQL_ASYNC_ACTIVE(mysql))
if (!tmp_mysql.options.charset_name ||
strcmp(tmp_mysql.options.charset_name, mysql->charset->csname))
{ {
my_free(tmp_mysql.options.charset_name); hook_data.orig_mysql= mysql;
tmp_mysql.options.charset_name= my_strdup(mysql->charset->csname, MYF(MY_WME)); 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, if (!mysql_real_connect(&tmp_mysql,mysql->host,mysql->user,mysql->passwd,
mysql->db, mysql->port, mysql->unix_socket, 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) */ /* don't free options (CONC-118) */
memset(&tmp_mysql.options, 0, sizeof(struct st_mysql_options)); memset(&tmp_mysql.options, 0, sizeof(struct st_mysql_options));
my_set_error(mysql, tmp_mysql.net.last_errno, my_set_error(mysql, tmp_mysql.net.last_errno,
@@ -1727,19 +1762,7 @@ static my_bool mysql_reconnect(MYSQL *mysql)
DBUG_RETURN(1); DBUG_RETURN(1);
} }
/* reset the connection in all active statements tmp_mysql.reconnect= mysql->reconnect;
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.free_me= mysql->free_me; tmp_mysql.free_me= mysql->free_me;
tmp_mysql.stmts= mysql->stmts; tmp_mysql.stmts= mysql->stmts;
mysql->stmts= NULL; mysql->stmts= NULL;
@@ -1747,16 +1770,31 @@ static my_bool mysql_reconnect(MYSQL *mysql)
/* Don't free options, we moved them to tmp_mysql */ /* Don't free options, we moved them to tmp_mysql */
memset(&mysql->options, 0, sizeof(mysql->options)); memset(&mysql->options, 0, sizeof(mysql->options));
mysql->free_me=0; mysql->free_me=0;
mysql->stmts= NULL;
mysql_close(mysql); mysql_close(mysql);
*mysql=tmp_mysql; *mysql=tmp_mysql;
mysql->reconnect= 1; mysql->net.pvio->mysql= mysql;
net_clear(&mysql->net); net_clear(&mysql->net);
mysql->affected_rows= ~(my_ulonglong) 0; mysql->affected_rows= ~(my_ulonglong) 0;
DBUG_RETURN(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 ** Change user and database
**************************************************************************/ **************************************************************************/
@@ -1786,36 +1824,33 @@ my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user,
else else
mysql->charset=default_charset_info; mysql->charset=default_charset_info;
mysql->user= (char *)user; mysql->user= my_strdup(user ? user : "", MYF(MY_WME));
mysql->passwd= (char *)passwd; mysql->passwd= my_strdup(passwd ? passwd : "", MYF(MY_WME));
mysql->db= (char *)db;
/* db will be set in run_plugin_auth */
mysql->db= 0;
rc= run_plugin_auth(mysql, 0, 0, 0, db); 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) if (rc==0)
{ {
LIST *li_stmt= mysql->stmts;
my_free(s_user); my_free(s_user);
my_free(s_passwd); my_free(s_passwd);
my_free(s_db); my_free(s_db);
if (!(mysql->user= my_strdup(user,MYF(MY_WME))) || if (db && !(mysql->db= my_strdup(db,MYF(MY_WME))))
!(mysql->passwd=my_strdup(passwd,MYF(MY_WME))) ||
!(mysql->db= db ? my_strdup(db,MYF(MY_WME)) : 0))
{ {
SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate, 0); SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate, 0);
rc= 1; 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 } else
{ {
my_free(mysql->user);
my_free(mysql->passwd);
my_free(mysql->db);
mysql->user= s_user; mysql->user= s_user;
mysql->passwd= s_passwd; mysql->passwd= s_passwd;
mysql->db= s_db; 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.my_cnf_group);
my_free(mysql->options.charset_dir); my_free(mysql->options.charset_dir);
my_free(mysql->options.charset_name); my_free(mysql->options.charset_name);
my_free(mysql->options.bind_address);
my_free(mysql->options.ssl_key); my_free(mysql->options.ssl_key);
my_free(mysql->options.ssl_cert); my_free(mysql->options.ssl_cert);
my_free(mysql->options.ssl_ca); my_free(mysql->options.ssl_ca);
@@ -1946,12 +1982,9 @@ void mysql_close_slow_part(MYSQL *mysql)
void STDCALL void STDCALL
mysql_close(MYSQL *mysql) mysql_close(MYSQL *mysql)
{ {
MYSQL_STMT *stmt;
DBUG_ENTER("mysql_close"); DBUG_ENTER("mysql_close");
if (mysql) /* Some simple safety */ if (mysql) /* Some simple safety */
{ {
LIST *li_stmt= mysql->stmts;
if (mysql->net.conn_hdlr && mysql->net.conn_hdlr->data) if (mysql->net.conn_hdlr && mysql->net.conn_hdlr->data)
{ {
void *p= (void *)mysql->net.conn_hdlr; void *p= (void *)mysql->net.conn_hdlr;
@@ -1963,14 +1996,8 @@ mysql_close(MYSQL *mysql)
if (mysql->methods) if (mysql->methods)
mysql->methods->db_close(mysql); mysql->methods->db_close(mysql);
/* reset the connection in all active statements /* reset the connection in all active statements */
todo: check stmt->mysql in mysql_stmt* functions ! */ ma_invalidate_stmts(mysql, "mysql_close()");
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);
}
mysql_close_memory(mysql); mysql_close_memory(mysql);
mysql_close_options(mysql); mysql_close_options(mysql);
mysql->host_info=mysql->user=mysql->passwd=mysql->db=0; mysql->host_info=mysql->user=mysql->passwd=mysql->db=0;

View File

@@ -185,7 +185,7 @@ static size_t ma_pvio_read_async(MARIADB_PVIO *pvio, uchar *buffer, size_t lengt
/* todo: async */ /* todo: async */
if (pvio->methods->async_read) if (pvio->methods->async_read)
res= pvio->methods->async_read(pvio, buffer, length); res= pvio->methods->async_read(pvio, buffer, length);
if (res >= 0 /* || IS_BLOCKING_ERROR()*/) if (res >= 0 || IS_BLOCKING_ERROR())
return res; return res;
b->events_to_wait_for= MYSQL_WAIT_READ; b->events_to_wait_for= MYSQL_WAIT_READ;
if (timeout >= 0) if (timeout >= 0)
@@ -211,14 +211,14 @@ size_t ma_pvio_read(MARIADB_PVIO *pvio, uchar *buffer, size_t length)
if (!pvio) if (!pvio)
return -1; 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); r= ma_pvio_read_async(pvio, buffer, length);
goto end; goto end;
} }
else else
{ {
if (pvio->async_context) if (IS_PVIO_ASYNC(pvio))
{ {
/* /*
If switching from non-blocking to blocking API usage, set the socket 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 */ /* secure connection */
#ifdef HAVE_SSL #ifdef HAVE_SSL
if (pvio->cssl) if (pvio->cssl)
{
r= ma_pvio_ssl_read(pvio->cssl, buffer, length); r= ma_pvio_ssl_read(pvio->cssl, buffer, length);
else goto end;
}
#endif #endif
if (pvio->methods->read) if (pvio->methods->read)
r= pvio->methods->read(pvio, buffer, length); 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) if (!pvio)
return -1; 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 */ /* secure connection */
#ifdef HAVE_SSL #ifdef HAVE_SSL
if (pvio->cssl) if (pvio->cssl)
{
r= ma_pvio_ssl_write(pvio->cssl, buffer, length); r= ma_pvio_ssl_write(pvio->cssl, buffer, length);
goto end;
}
else else
#endif #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); r= ma_pvio_write_async(pvio, buffer, length);
goto end; goto end;
} }
else else
{ {
if (pvio->async_context) if (IS_PVIO_ASYNC(pvio))
{ {
/* /*
If switching from non-blocking to blocking API usage, set the socket 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 */ /* {{{ ma_pvio_wait_io_or_timeout */
int ma_pvio_wait_io_or_timeout(MARIADB_PVIO *pvio, my_bool is_read, int 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) if (IS_PVIO_ASYNC_ACTIVE(pvio))
return my_io_wait_async(pvio->async_context, return ma_pvio_wait_async(pvio->mysql->options.extension->async_context,
(is_read) ? VIO_IO_EVENT_READ : VIO_IO_EVENT_WRITE, (is_read) ? VIO_IO_EVENT_READ : VIO_IO_EVENT_WRITE,
timeout); timeout);
if (pvio && pvio->methods->wait_io_or_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 #ifdef HAVE_SSL
/* {{{ my_bool ma_pvio_start_ssl */ /* {{{ my_bool ma_pvio_start_ssl */
my_bool ma_pvio_start_ssl(MARIADB_PVIO *pvio) 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)) if (ma_pvio_ssl_connect(pvio->cssl))
{ {
my_free((gptr)pvio->cssl); my_free(pvio->cssl);
pvio->cssl= NULL; pvio->cssl= NULL;
return 1; return 1;
} }

View File

@@ -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) int store_param(MYSQL_STMT *stmt, int column, unsigned char **p)
{ {
DBUG_ENTER("store_param"); 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) { switch (stmt->params[column].buffer_type) {
case MYSQL_TYPE_TINY: case MYSQL_TYPE_TINY:
int1store(*p, *(uchar *)stmt->params[column].buffer); int1store(*p, *(uchar *)stmt->params[column].buffer);

View File

@@ -134,37 +134,6 @@ my_connect_async(MARIADB_PVIO *pvio,
#endif #endif
#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 #ifdef HAVE_SSL_FIXME
static my_bool static my_bool
my_ssl_async_check_result(int res, struct mysql_async_context *b, MARIADB_SSL *cssl) my_ssl_async_check_result(int res, struct mysql_async_context *b, MARIADB_SSL *cssl)

View File

@@ -179,67 +179,11 @@ static my_bool net_realloc(NET *net, size_t length)
DBUG_RETURN(0); DBUG_RETURN(0);
} }
/* Remove unwanted characters from connection */
/* 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 */
void net_clear(NET *net) void net_clear(NET *net)
{ {
my_socket sock;
DBUG_ENTER("net_clear"); 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->compress_pkt_nr= net->pkt_nr=0; /* Ready for new command */
net->write_pos=net->buff; net->write_pos=net->buff;
DBUG_VOID_RETURN; DBUG_VOID_RETURN;

View File

@@ -235,6 +235,12 @@ ssize_t ma_ssl_pull(gnutls_transport_ptr_t ptr, void* data, size_t len)
return rc; 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) my_bool ma_ssl_connect(MARIADB_SSL *cssl)
{ {
gnutls_session_t ssl = (gnutls_session_t)cssl->ssl; 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_ptr(ssl, pvio);
gnutls_transport_set_push_function(ssl, ma_ssl_push); gnutls_transport_set_push_function(ssl, ma_ssl_push);
gnutls_transport_set_pull_function(ssl, ma_ssl_pull); 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 { do {
ret = gnutls_handshake(ssl); 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 */ #endif /* HAVE_GNUTLS */

View File

@@ -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_get_handle(MARIADB_PVIO *pvio, void *handle);
my_bool pvio_socket_is_blocking(MARIADB_PVIO *pvio); my_bool pvio_socket_is_blocking(MARIADB_PVIO *pvio);
my_bool pvio_socket_is_alive(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, static int pvio_socket_init(char *unused1,
size_t unused2, size_t unused2,
@@ -98,7 +99,8 @@ struct st_ma_pvio_methods pvio_socket_methods= {
pvio_socket_keepalive, pvio_socket_keepalive,
pvio_socket_get_handle, pvio_socket_get_handle,
pvio_socket_is_blocking, pvio_socket_is_blocking,
pvio_socket_is_alive pvio_socket_is_alive,
pvio_socket_has_data
}; };
#ifndef HAVE_SOCKET_DYNAMIC #ifndef HAVE_SOCKET_DYNAMIC
@@ -913,11 +915,14 @@ my_bool pvio_socket_is_alive(MARIADB_PVIO *pvio)
#ifndef _WIN32 #ifndef _WIN32
memset(&poll_fd, 0, sizeof(struct pollfd)); memset(&poll_fd, 0, sizeof(struct pollfd));
poll_fd.events= POLLPRI | POLLIN; poll_fd.events= POLLPRI | POLLIN;
poll_fd.revents= POLLERR;
poll_fd.fd= csock->socket; poll_fd.fd= csock->socket;
res= poll(&poll_fd, 1, 0); res= poll(&poll_fd, 1, 0);
if (res <= 0) /* timeout or error */ if (res <= 0) /* timeout or error */
return FALSE; return FALSE;
if (!(poll_fd.revents & POLLERR))
return FALSE;
if (!(poll_fd.revents & (POLLIN | POLLPRI))) if (!(poll_fd.revents & (POLLIN | POLLPRI)))
return FALSE; return FALSE;
return TRUE; return TRUE;
@@ -931,10 +936,35 @@ my_bool pvio_socket_is_alive(MARIADB_PVIO *pvio)
FD_ZERO(&sfds); FD_ZERO(&sfds);
FD_SET(csock->socket, &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)) if (res > 0 && FD_ISSET(csock->socket, &sfds))
return TRUE; return TRUE;
return FALSE; return FALSE;
#endif #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;
}
/* }}} */

View File

@@ -39,8 +39,7 @@ static int test_conc75(MYSQL *my)
mysql= mysql_init(NULL); 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); 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"); rc= mysql_query(mysql, "DROP TABLE IF EXISTS a");

View File

@@ -487,6 +487,7 @@ static int bug30472_retrieve_charset_info(MYSQL *con,
row= mysql_fetch_row(rs); row= mysql_fetch_row(rs);
FAIL_IF(!row, "Couldn't fetch row"); FAIL_IF(!row, "Couldn't fetch row");
strcpy(character_set_client, row[1]); strcpy(character_set_client, row[1]);
diag("cs: %s", row[1]);
mysql_free_result(rs); mysql_free_result(rs);
rc= mysql_query(con, "SHOW VARIABLES LIKE 'character_set_results'"); rc= mysql_query(con, "SHOW VARIABLES LIKE 'character_set_results'");

View File

@@ -964,7 +964,6 @@ static int test_conc117(MYSQL *mysql)
mysql_kill(my, mysql_thread_id(my)); mysql_kill(my, mysql_thread_id(my));
sleep(5); sleep(5);
strcpy(my->host, "A");
my->reconnect= 1; my->reconnect= 1;
mysql_query(my, "SET @a:=1"); mysql_query(my, "SET @a:=1");

View File

@@ -374,7 +374,7 @@ MYSQL *test_connect(struct my_tests_st *test) {
return(NULL); 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); mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT, (const char *)&i);
/* option handling */ /* option handling */

View File

@@ -523,10 +523,12 @@ static int test_bug12744(MYSQL *mysql)
check_stmt_rc(rc, stmt); check_stmt_rc(rc, stmt);
/* set reconnect, kill and ping to reconnect */ /* 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"); rc= mysql_options(mysql, MYSQL_OPT_RECONNECT, "1");
check_mysql_rc(rc, mysql); check_mysql_rc(rc, mysql);
rc= mysql_kill(mysql, mysql_thread_id(mysql)); rc= mysql_kill(mysql, mysql_thread_id(mysql));
//check_mysql_rc(rc, mysql); check_mysql_rc(rc, mysql);
sleep(2); sleep(2);
rc= mysql_ping(mysql); rc= mysql_ping(mysql);
@@ -542,10 +544,10 @@ static int test_bug1500(MYSQL *mysql)
{ {
MYSQL_STMT *stmt; MYSQL_STMT *stmt;
MYSQL_BIND my_bind[3]; MYSQL_BIND my_bind[3];
int rc; int rc= 0;
int32 int_data[3]= {2, 3, 4}; int32 int_data[3]= {2, 3, 4};
const char *data; char *data;
const char *query; char *query;
rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_bg1500"); 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_type= MYSQL_TYPE_DATE;
my_bind[0].buffer= (void*)&tm; my_bind[0].buffer= (void*)&tm;
memset(&tm, 0, sizeof(MYSQL_TIME));
tm.year = 2006; tm.year = 2006;
tm.month = 6; tm.month = 6;
tm.day = 18; tm.day = 18;
@@ -2180,11 +2184,11 @@ static int test_bug4026(MYSQL *mysql)
rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
check_stmt_rc(rc, stmt); check_stmt_rc(rc, stmt);
/* Bind input buffers */ /* Bind input buffers */
memset(my_bind, '\0', sizeof(my_bind)); memset(my_bind, '\0', sizeof(MYSQL_BIND) * 2);
memset(&time_in, '\0', sizeof(time_in)); memset(&time_in, '\0', sizeof(MYSQL_TIME));
memset(&time_out, '\0', sizeof(time_out)); memset(&time_out, '\0', sizeof(MYSQL_TIME));
memset(&datetime_in, '\0', sizeof(datetime_in)); memset(&datetime_in, '\0', sizeof(MYSQL_TIME));
memset(&datetime_out, '\0', sizeof(datetime_out)); memset(&datetime_out, '\0', sizeof(MYSQL_TIME));
my_bind[0].buffer_type= MYSQL_TYPE_TIME; my_bind[0].buffer_type= MYSQL_TYPE_TIME;
my_bind[0].buffer= (void *) &time_in; my_bind[0].buffer= (void *) &time_in;
my_bind[1].buffer_type= MYSQL_TYPE_DATETIME; my_bind[1].buffer_type= MYSQL_TYPE_DATETIME;

View File

@@ -680,6 +680,9 @@ const char *ssl_cert_finger_print= "@SSL_CERT_FINGER_PRINT@";
static int test_ssl_fp(MYSQL *unused) static int test_ssl_fp(MYSQL *unused)
{ {
MYSQL *my; MYSQL *my;
MYSQL_RES *res;
MYSQL_ROW row;
int rc;
if (check_skip_ssl()) if (check_skip_ssl())
return SKIP; return SKIP;
@@ -695,6 +698,20 @@ static int test_ssl_fp(MYSQL *unused)
port, socketname, 0), mysql_error(my)); port, socketname, 0), mysql_error(my));
FAIL_IF(check_cipher(my) != 0, "Invalid cipher"); 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); mysql_close(my);
return OK; return OK;
} }