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

- Fixes for 10.2-integration

- As requested by Wlad we use connect timeout for read/write unless
    the connection was established.
- Added experimental session cache support for OpenSSL. It's currently
  disabled
This commit is contained in:
Georg Richter
2016-03-08 17:08:01 +01:00
parent 05eeef7fda
commit cc0c34554d
7 changed files with 143 additions and 47 deletions

View File

@@ -54,14 +54,6 @@ void ma_randominit(struct rand_struct *rand_st,ulong seed1, ulong seed2)
rand_st->seed2=seed2%rand_st->max_value; rand_st->seed2=seed2%rand_st->max_value;
} }
static void ma_old_randominit(struct rand_struct *rand_st,ulong seed1)
{ /* For mysql 3.20.# */
rand_st->max_value= 0x01FFFFFFL;
rand_st->max_value_dbl=(double) rand_st->max_value;
seed1%=rand_st->max_value;
rand_st->seed1=seed1 ; rand_st->seed2=seed1/2;
}
double rnd(struct rand_struct *rand_st) double rnd(struct rand_struct *rand_st)
{ {
rand_st->seed1=(rand_st->seed1*3+rand_st->seed2) % rand_st->max_value; rand_st->seed1=(rand_st->seed1*3+rand_st->seed2) % rand_st->max_value;

View File

@@ -100,6 +100,7 @@ MARIADB_PVIO *ma_pvio_init(MA_PVIO_CINFO *cinfo)
pvio_plugins[type], pvio_plugins[type],
MARIADB_CLIENT_PVIO_PLUGIN))) MARIADB_CLIENT_PVIO_PLUGIN)))
{ {
/* error already set in mysql_client_find_plugin */
return NULL; return NULL;
} }
@@ -115,12 +116,11 @@ MARIADB_PVIO *ma_pvio_init(MA_PVIO_CINFO *cinfo)
pvio->set_error= my_set_error; pvio->set_error= my_set_error;
pvio->type= cinfo->type; pvio->type= cinfo->type;
/* set tineouts */ /* set timeout to connect timeout - after successfull connect we will set
* correct values for read and write */
if (pvio->methods->set_timeout) if (pvio->methods->set_timeout)
{ {
pvio->methods->set_timeout(pvio, PVIO_CONNECT_TIMEOUT, cinfo->mysql->options.connect_timeout); pvio->methods->set_timeout(pvio, PVIO_CONNECT_TIMEOUT, cinfo->mysql->options.connect_timeout);
pvio->methods->set_timeout(pvio, PVIO_READ_TIMEOUT, cinfo->mysql->options.read_timeout);
pvio->methods->set_timeout(pvio, PVIO_WRITE_TIMEOUT, cinfo->mysql->options.write_timeout);
} }
if (!(pvio->cache= calloc(1, PVIO_READ_AHEAD_CACHE_SIZE))) if (!(pvio->cache= calloc(1, PVIO_READ_AHEAD_CACHE_SIZE)))
@@ -521,6 +521,12 @@ my_bool ma_pvio_start_ssl(MARIADB_PVIO *pvio)
pvio->cssl= NULL; pvio->cssl= NULL;
return 1; return 1;
} }
/* default behaviour:
1. peer certificate verification
2. verify CN (requires option ssl_verify_check)
3. verrify finger print
*/
if ((pvio->mysql->options.ssl_ca || pvio->mysql->options.ssl_capath) && if ((pvio->mysql->options.ssl_ca || pvio->mysql->options.ssl_capath) &&
(pvio->mysql->client_flag & CLIENT_SSL_VERIFY_SERVER_CERT) && (pvio->mysql->client_flag & CLIENT_SSL_VERIFY_SERVER_CERT) &&
ma_pvio_ssl_verify_server_cert(pvio->cssl)) ma_pvio_ssl_verify_server_cert(pvio->cssl))

View File

@@ -1349,8 +1349,6 @@ MYSQL *mthd_my_real_connect(MYSQL *mysql, const char *host, const char *user,
SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0); SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
goto error; goto error;
} }
strcpy(mysql->host_info,host_info);
strcpy(mysql->host, cinfo.host);
if (cinfo.unix_socket) if (cinfo.unix_socket)
mysql->unix_socket= strdup(cinfo.unix_socket); mysql->unix_socket= strdup(cinfo.unix_socket);
else else
@@ -1512,6 +1510,9 @@ MYSQL *mthd_my_real_connect(MYSQL *mysql, const char *host, const char *user,
strcpy(mysql->net.sqlstate, "00000"); strcpy(mysql->net.sqlstate, "00000");
/* connection established, apply timeouts */
ma_pvio_set_timeout(mysql->net.pvio, PVIO_READ_TIMEOUT, mysql->options.read_timeout);
ma_pvio_set_timeout(mysql->net.pvio, PVIO_WRITE_TIMEOUT, mysql->options.write_timeout);
return(mysql); return(mysql);
error: error:
@@ -1557,6 +1558,7 @@ my_bool STDCALL mariadb_reconnect(MYSQL *mysql)
struct mysql_async_context *ctxt= NULL; struct mysql_async_context *ctxt= NULL;
#endif #endif
LIST *li_stmt= mysql->stmts; LIST *li_stmt= mysql->stmts;
mysql_init(&tmp_mysql);
/* check if connection handler is active */ /* check if connection handler is active */
if (IS_CONNHDLR_ACTIVE(mysql)) if (IS_CONNHDLR_ACTIVE(mysql))
@@ -1835,11 +1837,12 @@ static void mysql_close_options(MYSQL *mysql)
static void mysql_close_memory(MYSQL *mysql) static void mysql_close_memory(MYSQL *mysql)
{ {
free(mysql->host_info); free(mysql->host_info);
free(mysql->host);
free(mysql->user); free(mysql->user);
free(mysql->passwd); free(mysql->passwd);
free(mysql->db); free(mysql->db);
free(mysql->server_version); free(mysql->server_version);
mysql->host_info= mysql->server_version=mysql->user=mysql->passwd=mysql->db=0; mysql->host_info= mysql->host= mysql->server_version=mysql->user=mysql->passwd=mysql->db=0;
} }
void my_set_error(MYSQL *mysql, void my_set_error(MYSQL *mysql,

View File

@@ -30,6 +30,7 @@
#include <openssl/conf.h> #include <openssl/conf.h>
#include <openssl/md4.h> #include <openssl/md4.h>
#define HAVE_SSL_SESSION_CACHE 1
#ifndef HAVE_OPENSSL_DEFAULT #ifndef HAVE_OPENSSL_DEFAULT
#include <memory.h> #include <memory.h>
#define ma_malloc(A,B) malloc((A)) #define ma_malloc(A,B) malloc((A))
@@ -111,7 +112,7 @@ static void my_cb_threadid(CRYPTO_THREADID *id)
} }
#endif #endif
#ifdef HAVE_OPENSSL_SESSION_TICKET #ifdef HAVE_SSL_SESSION_CACHE
typedef struct st_ma_ssl_session { typedef struct st_ma_ssl_session {
char md4_hash[17]; char md4_hash[17];
SSL_SESSION *session; SSL_SESSION *session;
@@ -120,10 +121,11 @@ typedef struct st_ma_ssl_session {
MA_SSL_SESSION *ma_ssl_sessions= NULL; MA_SSL_SESSION *ma_ssl_sessions= NULL;
unsigned int ma_ssl_session_cache_size= 128; unsigned int ma_ssl_session_cache_size= 128;
static char *ma_md4_hash(const char *host, unsigned int port, char *md4) static char *ma_md4_hash(const char *host, const char *user, unsigned int port, char *md4)
{ {
char buffer[260]; char buffer[195]; /* MAX_USERNAME_LEN + MAX_HOST_NAME_LEN + 2 + 5 */
snprintf(buffer, 258, "%s:%d", host, port); snprintf(buffer, 194, "%s@%s:%d", user ? user : "", host, port);
buffer[194]= 0;
MD4(buffer, strlen(buffer), md4); MD4(buffer, strlen(buffer), md4);
return md4; return md4;
} }
@@ -137,7 +139,7 @@ MA_SSL_SESSION *ma_ssl_get_session(MYSQL *mysql)
return NULL; return NULL;
memset(md4, 0, 16); memset(md4, 0, 16);
ma_md4_hash(mysql->host, mysql->port, md4); ma_md4_hash(mysql->host, mysql->user, mysql->port, md4);
for (i=0; i < ma_ssl_session_cache_size; i++) for (i=0; i < ma_ssl_session_cache_size; i++)
{ {
if (ma_ssl_sessions[i].session && if (ma_ssl_sessions[i].session &&
@@ -169,7 +171,7 @@ static int ma_ssl_session_cb(SSL *ssl, SSL_SESSION *session)
{ {
if (!ma_ssl_sessions[i].session) if (!ma_ssl_sessions[i].session)
{ {
ma_md4_hash(mysql->host, mysql->port, ma_ssl_sessions[i].md4_hash); ma_md4_hash(mysql->host, mysql->user, mysql->port, ma_ssl_sessions[i].md4_hash);
ma_ssl_sessions[i].session= session; ma_ssl_sessions[i].session= session;
} }
return 1; return 1;
@@ -268,7 +270,7 @@ int ma_ssl_start(char *errmsg, size_t errmsg_len)
ma_ssl_get_error(errmsg, errmsg_len); ma_ssl_get_error(errmsg, errmsg_len);
goto end; goto end;
} }
#ifdef HAVE_OPENSSL_SESSION_TICKET #ifdef HAVE_SSL_SESSION_CACHE
SSL_CTX_set_session_cache_mode(SSL_context, SSL_SESS_CACHE_CLIENT); SSL_CTX_set_session_cache_mode(SSL_context, SSL_SESS_CACHE_CLIENT);
ma_ssl_sessions= (MA_SSL_SESSION *)calloc(1, sizeof(struct st_ma_ssl_session) * ma_ssl_session_cache_size); ma_ssl_sessions= (MA_SSL_SESSION *)calloc(1, sizeof(struct st_ma_ssl_session) * ma_ssl_session_cache_size);
SSL_CTX_sess_set_new_cb(SSL_context, ma_ssl_session_cb); SSL_CTX_sess_set_new_cb(SSL_context, ma_ssl_session_cb);
@@ -452,7 +454,7 @@ void *ma_ssl_init(MYSQL *mysql)
{ {
int verify; int verify;
SSL *ssl= NULL; SSL *ssl= NULL;
#ifdef HAVE_OPENSSL_SESSION_TICKET #ifdef HAVE_SSL_SESSION_CACHE
MA_SSL_SESSION *session= ma_ssl_get_session(mysql); MA_SSL_SESSION *session= ma_ssl_get_session(mysql);
#endif #endif
pthread_mutex_lock(&LOCK_openssl_config); pthread_mutex_lock(&LOCK_openssl_config);
@@ -468,7 +470,7 @@ void *ma_ssl_init(MYSQL *mysql)
if (!SSL_set_app_data(ssl, mysql)) if (!SSL_set_app_data(ssl, mysql))
goto error; goto error;
#ifdef HAVE_OPENSSL_SESSION_TICKET #ifdef HAVE_SSL_SESSION_CACHE
if (session) if (session)
SSL_set_session(ssl, session->session); SSL_set_session(ssl, session->session);
#endif #endif

View File

@@ -158,6 +158,38 @@ static int pvio_socket_end(void)
return 0; return 0;
} }
my_bool pvio_socket_change_timeout(MARIADB_PVIO *pvio, enum enum_pvio_timeout type, int timeout)
{
struct timeval tm;
struct st_pvio_socket *csock= NULL;
if (!pvio)
return 1;
if (!(csock= (struct st_pvio_socket *)pvio->data))
return 1;
tm.tv_sec= timeout / 1000;
tm.tv_usec= (timeout % 1000) * 1000;
switch(type)
{
case PVIO_WRITE_TIMEOUT:
#ifndef _WIN32
setsockopt(csock->socket, SOL_SOCKET, SO_SNDTIMEO, (const char *)&tm, sizeof(tm));
#else
setsockopt(csock->socket, SOL_SOCKET, SO_SNDTIMEO, (const char *)&timeout, sizeof(int));
#endif
break;
case PVIO_READ_TIMEOUT:
#ifndef _WIN32
setsockopt(csock->socket, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tm, sizeof(tm));
#else
setsockopt(csock->socket, SOL_SOCKET, SO_RCVTIMEO, (const char *)&timeout, sizeof(int));
#endif
break;
default:
break;
}
return 0;
}
/* {{{ pvio_socket_set_timeout */ /* {{{ pvio_socket_set_timeout */
/* /*
set timeout value set timeout value
@@ -179,9 +211,13 @@ static int pvio_socket_end(void)
*/ */
my_bool pvio_socket_set_timeout(MARIADB_PVIO *pvio, enum enum_pvio_timeout type, int timeout) my_bool pvio_socket_set_timeout(MARIADB_PVIO *pvio, enum enum_pvio_timeout type, int timeout)
{ {
struct st_pvio_socket *csock= NULL;
if (!pvio) if (!pvio)
return 1; return 1;
csock= (struct st_pvio_socket *)pvio->data;
pvio->timeout[type]= (timeout > 0) ? timeout * 1000 : -1; pvio->timeout[type]= (timeout > 0) ? timeout * 1000 : -1;
if (csock)
return pvio_socket_change_timeout(pvio, type, timeout);
return 0; return 0;
} }
/* }}} */ /* }}} */
@@ -677,15 +713,13 @@ int pvio_socket_fast_send(MARIADB_PVIO *pvio)
/* Setting IP_TOS is not recommended on Windows. See /* Setting IP_TOS is not recommended on Windows. See
http://msdn.microsoft.com/en-us/library/windows/desktop/ms738586(v=vs.85).aspx http://msdn.microsoft.com/en-us/library/windows/desktop/ms738586(v=vs.85).aspx
*/ */
#ifndef _WIN32 #if !defined(_WIN32) && defined(IPTOS_THROUGHPUT)
#ifdef IPTOS_THROUGHPUT
{ {
int tos = IPTOS_THROUGHPUT; int tos = IPTOS_THROUGHPUT;
r= setsockopt(csock->socket, IPPROTO_IP, IP_TOS, r= setsockopt(csock->socket, IPPROTO_IP, IP_TOS,
(const void *)&tos, sizeof(tos)); (const void *)&tos, sizeof(tos));
} }
#endif /* IPTOS_THROUGHPUT */ #endif /* !_WIN32 && IPTOS_THROUGHPUT */
#endif
if (!r) if (!r)
{ {
int opt = 1; int opt = 1;
@@ -723,7 +757,6 @@ pvio_socket_connect_sync_or_async(MARIADB_PVIO *pvio,
my_bool pvio_socket_connect(MARIADB_PVIO *pvio, MA_PVIO_CINFO *cinfo) my_bool pvio_socket_connect(MARIADB_PVIO *pvio, MA_PVIO_CINFO *cinfo)
{ {
struct st_pvio_socket *csock= NULL; struct st_pvio_socket *csock= NULL;
struct timeval tm;
if (!pvio || !cinfo) if (!pvio || !cinfo)
return 1; return 1;
@@ -870,25 +903,17 @@ my_bool pvio_socket_connect(MARIADB_PVIO *pvio, MA_PVIO_CINFO *cinfo)
goto error; goto error;
} }
/* apply timeouts */ /* apply timeouts */
if (pvio->timeout[PVIO_WRITE_TIMEOUT] > 0) if (pvio->timeout[PVIO_CONNECT_TIMEOUT] > 0)
{ {
#ifndef _WIN32 pvio_socket_change_timeout(pvio, PVIO_READ_TIMEOUT, pvio->timeout[PVIO_CONNECT_TIMEOUT]);
tm.tv_sec= pvio->timeout[PVIO_WRITE_TIMEOUT] / 1000; pvio_socket_change_timeout(pvio, PVIO_WRITE_TIMEOUT, pvio->timeout[PVIO_CONNECT_TIMEOUT]);
tm.tv_usec= pvio->timeout[PVIO_WRITE_TIMEOUT] % 1000;
setsockopt(csock->socket, SOL_SOCKET, SO_SNDTIMEO, (const char *)&tm, sizeof(tm));
#else
setsockopt(csock->socket, SOL_SOCKET, SO_SNDTIMEO, (const char *)&pvio->timeout[PVIO_WRITE_TIMEOUT], sizeof(int));
#endif
} }
if (pvio->timeout[PVIO_READ_TIMEOUT] > 0) else
{ {
#ifndef _WIN32 if (pvio->timeout[PVIO_WRITE_TIMEOUT] > 0)
tm.tv_sec= pvio->timeout[PVIO_READ_TIMEOUT] / 1000; pvio_socket_change_timeout(pvio, PVIO_WRITE_TIMEOUT, pvio->timeout[PVIO_WRITE_TIMEOUT]);
tm.tv_usec= pvio->timeout[PVIO_READ_TIMEOUT] % 1000; if (pvio->timeout[PVIO_READ_TIMEOUT] > 0)
setsockopt(csock->socket, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tm, sizeof(tm)); pvio_socket_change_timeout(pvio, PVIO_READ_TIMEOUT, pvio->timeout[PVIO_READ_TIMEOUT]);
#else
setsockopt(csock->socket, SOL_SOCKET, SO_RCVTIMEO, (const char *)&pvio->timeout[PVIO_WRITE_TIMEOUT], sizeof(int));
#endif
} }
return 0; return 0;
error: error:

View File

@@ -49,8 +49,8 @@ static int test_conc66(MYSQL *my)
rc= mysql_options(mysql, MYSQL_READ_DEFAULT_GROUP, "conc-66"); rc= mysql_options(mysql, MYSQL_READ_DEFAULT_GROUP, "conc-66");
check_mysql_rc(rc, mysql); check_mysql_rc(rc, mysql);
// rc= mysql_options(mysql, MYSQL_READ_DEFAULT_FILE, "./my.cnf"); rc= mysql_options(mysql, MYSQL_READ_DEFAULT_FILE, "./my.cnf");
// check_mysql_rc(rc, mysql); check_mysql_rc(rc, mysql);
sprintf(query, "GRANT ALL ON %s.* TO 'conc66'@'%s' IDENTIFIED BY 'test\";#test'", schema, hostname); sprintf(query, "GRANT ALL ON %s.* TO 'conc66'@'%s' IDENTIFIED BY 'test\";#test'", schema, hostname);
rc= mysql_query(my, query); rc= mysql_query(my, query);
@@ -63,6 +63,7 @@ static int test_conc66(MYSQL *my)
diag("Error: %s", mysql_error(mysql)); diag("Error: %s", mysql_error(mysql));
return FAIL; return FAIL;
} }
sprintf(query, "DROP user conc66@%s", hostname); sprintf(query, "DROP user conc66@%s", hostname);
rc= mysql_query(my, query); rc= mysql_query(my, query);
@@ -660,6 +661,71 @@ int test_connection_timeout(MYSQL *my)
return OK; return OK;
} }
int test_connection_timeout2(MYSQL *my)
{
unsigned int timeout= 5;
time_t start, elapsed;
MYSQL *mysql= mysql_init(NULL);
mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT, (unsigned int *)&timeout);
mysql_options(mysql, MYSQL_INIT_COMMAND, "set @a:=SLEEP(6)");
start= time(NULL);
if (mysql_real_connect(mysql, hostname, username, password, schema, port, NULL, CLIENT_REMEMBER_OPTIONS))
{
diag("timeout error expected");
return FAIL;
}
elapsed= time(NULL) - start;
diag("elapsed: %lu", (unsigned long)elapsed);
mysql_close(mysql);
FAIL_IF(elapsed > 2 * timeout, "timeout ignored")
return OK;
}
int test_connection_timeout3(MYSQL *my)
{
unsigned int timeout= 5;
unsigned int read_write_timeout= 10;
int rc;
time_t start, elapsed;
MYSQL *mysql= mysql_init(NULL);
mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT, (unsigned int *)&timeout);
mysql_options(mysql, MYSQL_OPT_READ_TIMEOUT, (unsigned int *)&read_write_timeout);
mysql_options(mysql, MYSQL_OPT_WRITE_TIMEOUT, (unsigned int *)&read_write_timeout);
mysql_options(mysql, MYSQL_INIT_COMMAND, "set @a:=SLEEP(6)");
start= time(NULL);
if (mysql_real_connect(mysql, hostname, username, password, schema, port, NULL, CLIENT_REMEMBER_OPTIONS))
{
diag("timeout error expected");
elapsed= time(NULL) - start;
diag("elapsed: %lu", (unsigned long)elapsed);
return FAIL;
}
elapsed= time(NULL) - start;
diag("elapsed: %lu", (unsigned long)elapsed);
FAIL_IF(elapsed > timeout + 1, "timeout ignored")
mysql_close(mysql);
mysql= mysql_init(NULL);
mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT, (unsigned int *)&timeout);
mysql_options(mysql, MYSQL_OPT_READ_TIMEOUT, (unsigned int *)&read_write_timeout);
mysql_options(mysql, MYSQL_OPT_WRITE_TIMEOUT, (unsigned int *)&read_write_timeout);
if (!mysql_real_connect(mysql, hostname, username, password, schema, port, NULL, CLIENT_REMEMBER_OPTIONS))
{
diag("Error: %s", mysql_error(mysql));
return FAIL;
}
start= time(NULL);
rc= mysql_query(mysql, "SET @a:=SLEEP(12)");
elapsed= time(NULL) - start;
diag("elapsed: %lu", (unsigned long)elapsed);
FAIL_IF(!rc, "timeout expected");
mysql_close(mysql);
return OK;
}
/* test should run with valgrind */ /* test should run with valgrind */
static int test_conc118(MYSQL *mysql) static int test_conc118(MYSQL *mysql)
{ {
@@ -862,6 +928,8 @@ struct my_tests_st my_tests[] = {
{"test_conc21", test_conc21, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_conc21", test_conc21, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
{"test_conc26", test_conc26, TEST_CONNECTION_NONE, 0, NULL, NULL}, {"test_conc26", test_conc26, TEST_CONNECTION_NONE, 0, NULL, NULL},
{"test_connection_timeout", test_connection_timeout, TEST_CONNECTION_NONE, 0, NULL, NULL}, {"test_connection_timeout", test_connection_timeout, TEST_CONNECTION_NONE, 0, NULL, NULL},
{"test_connection_timeout2", test_connection_timeout2, TEST_CONNECTION_NONE, 0, NULL, NULL},
{"test_connection_timeout3", test_connection_timeout3, TEST_CONNECTION_NONE, 0, NULL, NULL},
{NULL, NULL, 0, 0, NULL, NULL} {NULL, NULL, 0, 0, NULL, NULL}
}; };

View File

@@ -182,8 +182,8 @@ static int test_conc95(MYSQL *my)
if (!mysql_real_connect(mysql, hostname, "ssluser1", sslpw, schema, if (!mysql_real_connect(mysql, hostname, "ssluser1", sslpw, schema,
port, socketname, 0)) port, socketname, 0))
{ {
diag("could not establish x509 connection. Error: %s", mysql_error(mysql));
mysql_close(mysql); mysql_close(mysql);
diag("could not establish x509 connection");
return FAIL; return FAIL;
} }
mysql_close(mysql); mysql_close(mysql);