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
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)

View File

@@ -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

View File

@@ -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_ */

View File

@@ -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",

View File

@@ -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;

View File

@@ -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;
}

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)
{
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);

View File

@@ -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)

View File

@@ -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;

View File

@@ -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 */

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_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;
}
/* }}} */

View File

@@ -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");

View File

@@ -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'");

View File

@@ -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");

View File

@@ -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 */

View File

@@ -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;

View File

@@ -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}
};