diff --git a/deps/mariadb-client-library/UPGRADE_NOTES.md b/deps/mariadb-client-library/UPGRADE_NOTES.md new file mode 100644 index 000000000..32e1a7f0c --- /dev/null +++ b/deps/mariadb-client-library/UPGRADE_NOTES.md @@ -0,0 +1,4 @@ +Please note that upgrading `mariadb-connector-c` can require some changes +in `include/MySQL_Data_Stream.h` where we define `P_MARIADB_TLS` as a copy +of `MARIADB_TLS` . If `MARIADB_TLS` is changed, `P_MARIADB_TLS` must be +updated too. diff --git a/deps/mariadb-client-library/mariadb-connector-c-2.3.1-src.tar.gz b/deps/mariadb-client-library/mariadb-connector-c-2.3.1-src.tar.gz deleted file mode 100644 index 5d68f7402..000000000 Binary files a/deps/mariadb-client-library/mariadb-connector-c-2.3.1-src.tar.gz and /dev/null differ diff --git a/deps/mariadb-client-library/mariadb-connector-c-3.0.2-src.tar.gz b/deps/mariadb-client-library/mariadb-connector-c-3.0.2-src.tar.gz deleted file mode 100644 index de98af6d2..000000000 Binary files a/deps/mariadb-client-library/mariadb-connector-c-3.0.2-src.tar.gz and /dev/null differ diff --git a/deps/mariadb-client-library/mariadb-connector-c-3.0.9-src.tar.gz b/deps/mariadb-client-library/mariadb-connector-c-3.0.9-src.tar.gz deleted file mode 100644 index d832031c9..000000000 Binary files a/deps/mariadb-client-library/mariadb-connector-c-3.0.9-src.tar.gz and /dev/null differ diff --git a/deps/mariadb-client-library/mariadb-connector-c-3.1.4-src.tar.gz b/deps/mariadb-client-library/mariadb-connector-c-3.1.4-src.tar.gz deleted file mode 100644 index e24be31d1..000000000 Binary files a/deps/mariadb-client-library/mariadb-connector-c-3.1.4-src.tar.gz and /dev/null differ diff --git a/include/MySQL_Data_Stream.h b/include/MySQL_Data_Stream.h index f4035856c..8cedfdea1 100644 --- a/include/MySQL_Data_Stream.h +++ b/include/MySQL_Data_Stream.h @@ -6,6 +6,21 @@ #include "MySQL_Protocol.h" +#ifndef uchar +typedef unsigned char uchar; +#endif + +#include "ma_pvio.h" +// here we define P_MARIADB_TLS as a copy of MARIADB_TLS +// copied from ma_tls.h +// note that ma_pvio.h defines it as void +typedef struct P_st_ma_pvio_tls { + void *data; + MARIADB_PVIO *pvio; + void *ssl; +} P_MARIADB_TLS; + + #define QUEUE_T_DEFAULT_SIZE 32768 #define MY_SSL_BUFFER 8192 @@ -196,6 +211,33 @@ class MySQL_Data_Stream myconn=mc; myconn->statuses.myconnpoll_get++; mc->myds=this; + encrypted = false; // this is the default + // we handle encryption for backend + // + // we have a similar code in MySQL_Connection + // in case of ASYNC_CONNECT_SUCCESSFUL + if (sess != NULL && sess->session_fast_forward == true) { + // if frontend and backend connection use SSL we will set + // encrypted = true and we will start using the SSL structure + // directly from P_MARIADB_TLS structure. + // + // For futher details: + // - without ssl: we use the file descriptor from mysql connection + // - with ssl: we use the SSL structure from mysql connection + if (myconn->mysql && myconn->ret_mysql) { + if (myconn->mysql->options.use_ssl == 1) { + encrypted = true; + if (ssl == NULL) { + // check the definition of P_MARIADB_TLS + P_MARIADB_TLS * matls = (P_MARIADB_TLS *)myconn->mysql->net.pvio->ctls; + ssl = (SSL *)matls->ssl; + rbio_ssl = BIO_new(BIO_s_mem()); + wbio_ssl = BIO_new(BIO_s_mem()); + SSL_set_bio(ssl, rbio_ssl, wbio_ssl); + } + } + } + } } // safe way to detach a MySQL Connection @@ -205,6 +247,15 @@ class MySQL_Data_Stream statuses.myconnpoll_put++; myconn->myds=NULL; myconn=NULL; + if (encrypted == true) { + if (sess != NULL && sess->session_fast_forward == true) { + // it seems we are a connection with SSL on a fast_forward session. + // See attach_connection() for more details . + // We now disable SSL metadata from the Data Stream + encrypted = false; + ssl = NULL; + } + } } void return_MySQL_Connection_To_Pool(); diff --git a/lib/ClickHouse_Server.cpp b/lib/ClickHouse_Server.cpp index 94cecdeb7..b3b61061c 100644 --- a/lib/ClickHouse_Server.cpp +++ b/lib/ClickHouse_Server.cpp @@ -567,6 +567,8 @@ void ClickHouse_Server_session_handler(MySQL_Session *sess, void *_pa, PtrSize_t query_no_space[query_no_space_length]=0; } + proxy_debug(PROXY_DEBUG_SQLITE, 4, "Received query on Session %p , thread_session_id %u : %s\n", sess, sess->thread_session_id, query_no_space); + if (sess->session_type == PROXYSQL_SESSION_CLICKHOUSE) { if (!strncasecmp("SET ", query_no_space, 4)) { @@ -1365,9 +1367,24 @@ static void *child_mysql(void *arg) { } } myds->revents=fds[0].revents; - myds->read_from_net(); + int rb = 0; + rb - myds->read_from_net(); if (myds->net_failure) goto __exit_child_mysql; myds->read_pkts(); + if (myds->encrypted == true) { + // PMC-10004 + // we probably should use SSL_pending() and/or SSL_has_pending() to determine + // if there is more data to be read, but it doesn't seem to be working. + // Therefore we hardcored the values 4096 (4K) as a special case and + // we try to call read_from_net() again. + // Previously we hardcoded 16KB but it seems that it can return in smaller + // chunks of 4KB. + while (rb > 0 && rb%4096 == 0) { + rb = myds->read_from_net(); + if (myds->net_failure) goto __exit_child_mysql; + myds->read_pkts(); + } + } sess->to_process=1; int rc=sess->handler(); if (rc==-1) goto __exit_child_mysql; diff --git a/lib/MySQL_Protocol.cpp b/lib/MySQL_Protocol.cpp index 642a2979e..756c28f97 100644 --- a/lib/MySQL_Protocol.cpp +++ b/lib/MySQL_Protocol.cpp @@ -1947,7 +1947,10 @@ __do_auth: #endif (*myds)->sess->schema_locked=schema_locked; (*myds)->sess->transaction_persistent=transaction_persistent; - (*myds)->sess->session_fast_forward=fast_forward; + (*myds)->sess->session_fast_forward=false; // default + if ((*myds)->sess->session_type == PROXYSQL_SESSION_MYSQL) { + (*myds)->sess->session_fast_forward=fast_forward; + } (*myds)->sess->user_max_connections=max_connections; } if (password == NULL) { diff --git a/lib/MySQL_Thread.cpp b/lib/MySQL_Thread.cpp index 717e78eb5..6c0771812 100644 --- a/lib/MySQL_Thread.cpp +++ b/lib/MySQL_Thread.cpp @@ -21,6 +21,8 @@ #include "MySQL_PreparedStatement.h" #include "MySQL_Logger.hpp" +#include + using std::vector; using std::function; @@ -2834,6 +2836,20 @@ MySQL_Session * MySQL_Thread::create_new_session_and_client_data_stream(int _fd) register_session(sess); // register session sess->client_myds = new MySQL_Data_Stream(); sess->client_myds->fd=_fd; + + // set not blocking for client connections too! + { + // PMC-10004 + // While implementing SSL and fast_forward it was noticed that all frontend connections + // are in blocking, although this was never a problem because we call poll() before reading. + // Although it became a problem with fast_forward, SSL and large packets because SSL handled + // data in chunks of 16KB and there may be data inside SSL even when there is no data + // received from the network. + // The only modules that seems to be affected by this issue are Admin, SQLite3 Server + // and Clickhouse Server + int nb = fcntl(_fd, F_SETFL, fcntl(_fd, F_GETFL, 0) | O_NONBLOCK); + assert (nb != -1); + } setsockopt(sess->client_myds->fd, IPPROTO_TCP, TCP_NODELAY, (char *) &arg_on, sizeof(arg_on)); if (mysql_thread___use_tcp_keepalive) { @@ -3578,17 +3594,40 @@ bool MySQL_Thread::process_data_on_data_stream(MySQL_Data_Stream *myds, unsigned if (rb > 0 && myds->myds_type == MYDS_BACKEND) { if (myds->sess->session_fast_forward) { - struct pollfd _fds; - nfds_t _nfds = 1; - _fds.fd = mypolls.fds[n].fd; - _fds.events = POLLIN; - _fds.revents = 0; - int _rc = poll(&_fds, _nfds, 0); - if ((_rc > 0) && _fds.revents == POLLIN) { - // there is more data - myds->revents = _fds.revents; - } else { + if (myds->encrypted == true) { // we are in fast_forward mode and encrypted == true + // PMC-10004 + // we probably should use SSL_pending() and/or SSL_has_pending() to determine + // if there is more data to be read, but it doesn't seem to be working. + // Therefore we hardcored the value 16384 (16KB) as a special case and + // we try to call read_from_net() again +/* + int sslp = SSL_pending(myds->ssl); + int sslhp = SSL_has_pending(myds->ssl); + proxy_debug(PROXY_DEBUG_NET, 5, "Session=%p: in fast_forward mode and SSL read %d bytes , SSL_pending: %d bytes , SSL_has_pending: %d\n", myds->sess, rb, sslp, sslhp); +*/ + proxy_debug(PROXY_DEBUG_NET, 5, "Session=%p, DataStream=%p , thread_session_id=%u -- in fast_forward mode and SSL read %d bytes\n", myds->sess, myds, myds->sess->thread_session_id, rb); + while (rb == 16384) { + rb = myds->read_from_net(); + if (rb > 0 && myds->myds_type == MYDS_FRONTEND) { + status_variables.stvar[st_var_queries_frontends_bytes_recv] += rb; + } + proxy_debug(PROXY_DEBUG_NET, 5, "Session=%p, DataStream=%p -- in fast_forward mode and SSL read %d bytes\n", myds->sess, myds, rb); + myds->read_pkts(); + } rb = 0; // exit loop + } else { // we are in fast_forward mode and encrypted == false + struct pollfd _fds; + nfds_t _nfds = 1; + _fds.fd = mypolls.fds[n].fd; + _fds.events = POLLIN; + _fds.revents = 0; + int _rc = poll(&_fds, _nfds, 0); + if ((_rc > 0) && _fds.revents == POLLIN) { + // there is more data + myds->revents = _fds.revents; + } else { + rb = 0; // exit loop + } } } else { rb = 0; // exit loop diff --git a/lib/ProxySQL_Admin.cpp b/lib/ProxySQL_Admin.cpp index 0e0650d51..54f8644a9 100644 --- a/lib/ProxySQL_Admin.cpp +++ b/lib/ProxySQL_Admin.cpp @@ -5458,9 +5458,24 @@ void *child_mysql(void *arg) { } mysql_thr->curtime = monotonic_time(); myds->revents=fds[0].revents; - myds->read_from_net(); + int rb = 0; + rb = myds->read_from_net(); if (myds->net_failure) goto __exit_child_mysql; myds->read_pkts(); + if (myds->encrypted == true) { + // PMC-10004 + // we probably should use SSL_pending() and/or SSL_has_pending() to determine + // if there is more data to be read, but it doesn't seem to be working. + // Therefore we hardcored the values 4096 (4K) as a special case and + // we try to call read_from_net() again. + // Previously we hardcoded 16KB but it seems that it can return in smaller + // chunks of 4KB. + while (rb > 0 && rb%4096 == 0) { + rb = myds->read_from_net(); + if (myds->net_failure) goto __exit_child_mysql; + myds->read_pkts(); + } + } sess->to_process=1; int rc=sess->handler(); if (rc==-1) goto __exit_child_mysql; diff --git a/lib/mysql_connection.cpp b/lib/mysql_connection.cpp index 19ca46555..acc06ba98 100644 --- a/lib/mysql_connection.cpp +++ b/lib/mysql_connection.cpp @@ -22,6 +22,7 @@ void ma_free_root(MA_MEM_ROOT *root, myf MyFLAGS); void *ma_alloc_root(MA_MEM_ROOT *mem_root, size_t Size); #define MAX(a,b) (((a) > (b)) ? (a) : (b)) + void * ma_alloc_root(MA_MEM_ROOT *mem_root, size_t Size) { size_t get_size; @@ -1113,6 +1114,33 @@ handler_again: } break; case ASYNC_CONNECT_SUCCESSFUL: + if (mysql && ret_mysql) { + // we handle encryption for backend + // + // we have a similar code in MySQL_Data_Stream::attach_connection() + // see there for further details + if (mysql->options.use_ssl == 1) + if (myds) + if (myds->sess != NULL) + if (myds->sess->session_fast_forward == true) { + assert(myds->ssl==NULL); + if (myds->ssl == NULL) { + // check the definition of P_MARIADB_TLS + P_MARIADB_TLS * matls = (P_MARIADB_TLS *)mysql->net.pvio->ctls; + if (matls != NULL) { + myds->encrypted = true; + myds->ssl = (SSL *)matls->ssl; + myds->rbio_ssl = BIO_new(BIO_s_mem()); + myds->wbio_ssl = BIO_new(BIO_s_mem()); + SSL_set_bio(myds->ssl, myds->rbio_ssl, myds->wbio_ssl); + } else { + // if mysql->options.use_ssl == 1 but matls == NULL + // it means that ProxySQL tried to use SSL to connect to the backend + // but the backend didn't support SSL + } + } + } + } __sync_fetch_and_add(&MyHGM->status.server_connections_connected,1); __sync_fetch_and_add(&parent->connect_OK,1); options.client_flag = mysql->client_flag; diff --git a/lib/mysql_data_stream.cpp b/lib/mysql_data_stream.cpp index 66d3f0914..35f878688 100644 --- a/lib/mysql_data_stream.cpp +++ b/lib/mysql_data_stream.cpp @@ -118,7 +118,9 @@ static void __dump_pkt(const char *func, unsigned char *_ptr, unsigned int len) } #define queue_zero(_q) { \ - memcpy(_q.buffer, (unsigned char *)_q.buffer + _q.tail, _q.head - _q.tail); \ + if (_q.tail != 0) { \ + memcpy(_q.buffer, (unsigned char *)_q.buffer + _q.tail, _q.head - _q.tail); \ + } \ _q.head-=_q.tail; \ _q.tail=0; \ } @@ -385,15 +387,6 @@ MySQL_Data_Stream::~MySQL_Data_Stream() { SSL_shutdown(ssl); } if (ssl) SSL_free(ssl); -/* - SSL_free() should also take care of these - if (rbio_ssl) { - BIO_free(rbio_ssl); - } - if (wbio_ssl) { - BIO_free(wbio_ssl); - } -*/ } if (multi_pkt.ptr) { l_free(multi_pkt.size,multi_pkt.ptr); @@ -532,7 +525,7 @@ int MySQL_Data_Stream::read_from_net() { r = recv(fd, queue_w_ptr(queueIN), s, 0); } } - } else { + } else { // encrypted == true /* if (!SSL_is_init_finished(ssl)) { int ret = SSL_do_handshake(ssl); @@ -638,11 +631,21 @@ int MySQL_Data_Stream::read_from_net() { } } else { int ssl_ret=SSL_get_error(ssl, r); - if (ssl_ret!=SSL_ERROR_WANT_READ && ssl_ret!=SSL_ERROR_WANT_WRITE) shut_soft(); - if (r==0 && revents==1) { - // revents returns 1 , but recv() returns 0 , so there is no data. - // Therefore the socket is already closed - shut_soft(); + proxy_debug(PROXY_DEBUG_NET, 5, "Session=%p, Datastream=%p -- session_id: %u , SSL_get_error(): %d , errno: %d\n", sess, this, sess->thread_session_id, ssl_ret, errno); + if (ssl_ret == SSL_ERROR_SYSCALL && (errno == EINTR || errno == EAGAIN)) { + // the read was interrupted, do nothing + proxy_debug(PROXY_DEBUG_NET, 5, "Session=%p, Datastream=%p -- SSL_get_error() is SSL_ERROR_SYSCALL, errno: %d\n", sess, this, errno); + } else { + if (r==0) { // we couldn't read any data + if (revents==1) { + // revents returns 1 , but recv() returns 0 , so there is no data. + // Therefore the socket is already closed + proxy_debug(PROXY_DEBUG_NET, 5, "Session=%p, Datastream=%p -- shutdown soft\n", sess, this); + shut_soft(); + } + } + if (ssl_ret!=SSL_ERROR_WANT_READ && ssl_ret!=SSL_ERROR_WANT_WRITE) shut_soft(); + // it seems we end in shut_soft() anyway } } } else { @@ -673,11 +676,13 @@ int MySQL_Data_Stream::write_to_net() { if (encrypted) { bytes_io = SSL_write (ssl, queue_r_ptr(queueOUT), s); //proxy_info("Used SSL_write to write %d bytes\n", bytes_io); + proxy_debug(PROXY_DEBUG_NET, 7, "Session=%p, Datastream=%p: SSL_write() wrote %d bytes . queueOUT before: %u\n", sess, this, bytes_io, queue_data(queueOUT)); if (ssl_write_len || wbio_ssl->num_write > wbio_ssl->num_read) { //proxy_info("ssl_write_len = %d , num_write = %d , num_read = %d\n", ssl_write_len , wbio_ssl->num_write , wbio_ssl->num_read); char buf[MY_SSL_BUFFER]; do { n = BIO_read(wbio_ssl, buf, sizeof(buf)); + proxy_debug(PROXY_DEBUG_NET, 7, "Session=%p, Datastream=%p: BIO_read() read %d bytes\n", sess, this, n); //proxy_info("BIO read = %d\n", n); if (n > 0) { //proxy_info("Setting %d byte in queue encrypted\n", n); @@ -690,8 +695,10 @@ int MySQL_Data_Stream::write_to_net() { } } while (n>0); } + proxy_debug(PROXY_DEBUG_NET, 7, "Session=%p, Datastream=%p: current ssl_write_len is %lu bytes\n", sess, this, ssl_write_len); if (ssl_write_len) { n = write(fd, ssl_write_buf, ssl_write_len); + proxy_debug(PROXY_DEBUG_NET, 7, "Session=%p, Datastream=%p: write() wrote %d bytes in FD %d\n", sess, this, n, fd); //proxy_info("Calling write() on SSL: %d\n", n); if (n>0) { if ((size_t)n < ssl_write_len) { @@ -722,6 +729,7 @@ int MySQL_Data_Stream::write_to_net() { #else bytes_io = send(fd, queue_r_ptr(queueOUT), s, MSG_NOSIGNAL); #endif + proxy_debug(PROXY_DEBUG_NET, 7, "Session=%p, Datastream=%p: send() wrote %d bytes in FD %d\n", sess, this, bytes_io, fd); } if (encrypted) { //proxy_info("bytes_io: %d\n", bytes_io); diff --git a/src/SQLite3_Server.cpp b/src/SQLite3_Server.cpp index 8f92fc02e..3c04a3f74 100644 --- a/src/SQLite3_Server.cpp +++ b/src/SQLite3_Server.cpp @@ -372,6 +372,7 @@ void SQLite3_Server_session_handler(MySQL_Session *sess, void *_pa, PtrSize_t *p query_no_space[query_no_space_length]=0; } + proxy_debug(PROXY_DEBUG_SQLITE, 4, "Received query on Session %p , thread_session_id %u : %s\n", sess, sess->thread_session_id, query_no_space); { SQLite3_Session *sqlite_sess = (SQLite3_Session *)sess->thread->gen_args; @@ -935,11 +936,25 @@ static void *child_mysql(void *arg) { // FIXME: CI test test_sqlite3_server-t or test_sqlite3_server_and_fast_routing-t // seems to result in fds->fd = -1 // it needs investigation - myds->read_from_net(); + int rb = 0; + rb = myds->read_from_net(); if (myds->net_failure) goto __exit_child_mysql; myds->read_pkts(); + if (myds->encrypted == true) { + // PMC-10004 + // we probably should use SSL_pending() and/or SSL_has_pending() to determine + // if there is more data to be read, but it doesn't seem to be working. + // Therefore we hardcored the values 4096 (4K) as a special case and + // we try to call read_from_net() again. + // Previously we hardcoded 16KB but it seems that it can return in smaller + // chunks of 4KB. + while (rb > 0 && rb%4096 == 0) { + rb = myds->read_from_net(); + if (myds->net_failure) goto __exit_child_mysql; + myds->read_pkts(); + } + } sess->to_process=1; - // Get and set the client address before the sesion is processed. union { struct sockaddr_in in; diff --git a/test/tap/tests/test_ssl_fast_forward-1-t.cpp b/test/tap/tests/test_ssl_fast_forward-1-t.cpp new file mode 100644 index 000000000..9cdb7dfa8 --- /dev/null +++ b/test/tap/tests/test_ssl_fast_forward-1-t.cpp @@ -0,0 +1,267 @@ +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "tap.h" +#include "command_line.h" +#include "utils.h" + + +/* +Several bugs were identified and fixed while developing this test: +- several memory corruption in SSL and fast_forward +- SQLite3 Server stops working if the user is a fast_forward user +- potential stalls with large resultset +- connections being closed because of interrupted syscall in SSL (SSL_ERROR_SYSCALL) + +*/ + + +char * username = (char *)"user1459"; +char * password = (char *)"pass1459"; + +std::vector queries_set1 = { + "SET mysql-have_ssl='false'", + "LOAD MYSQL VARIABLES TO RUNTIME", + "DELETE FROM mysql_servers WHERE hostgroup_id = 1459", + "INSERT INTO mysql_servers (hostgroup_id, hostname, port, use_ssl) VALUES (1459, '127.0.0.1', 6030, 0)", + "LOAD MYSQL SERVERS TO RUNTIME", + "DELETE FROM mysql_users WHERE username = 'user1459'", + "INSERT INTO mysql_users (username,password,fast_forward,default_hostgroup) VALUES ('" + std::string(username) + "','" + std::string(password) + "',1,1459)", + "LOAD MYSQL USERS TO RUNTIME", +}; + +std::vector queries_set2 = { + "SET mysql-have_ssl='true'", + "LOAD MYSQL VARIABLES TO RUNTIME", +}; + +std::vector queries_set3 = { + "SET mysql-have_ssl='false'", + "LOAD MYSQL VARIABLES TO RUNTIME", + "UPDATE mysql_servers SET use_ssl=1 WHERE hostgroup_id = 1459", + "LOAD MYSQL SERVERS TO RUNTIME", +}; + +std::vector queries_set4 = { + "SET mysql-have_ssl='true'", + "LOAD MYSQL VARIABLES TO RUNTIME", + "UPDATE mysql_servers SET use_ssl=1 WHERE hostgroup_id = 1459", + "LOAD MYSQL SERVERS TO RUNTIME", +}; + +std::vector queries_SQL1 = { + "DROP TABLE IF EXISTS tbl1459", + "CREATE TABLE tbl1459 (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL , i1 INTEGER , i2 INTEGER)", + "INSERT INTO tbl1459 VALUES (NULL, 1, 2)", +}; + +std::vector queries_SQL2 = { + "INSERT INTO tbl1459 SELECT NULL , i1 + id, i2 + id FROM tbl1459", +}; + +std::vector queries_limits = { + 1, 10, 20, 27, 103, 169, 320, 450, 512, 619, 915, 1022, + 1033, 1145, 1516, 1920, 2034, 5014, 9932, 10111, + 11033, 11145, 12516, 11920, 12034, 15014, 19932, + 21033, 21145, 22516, 21920, 22034, 25014, 29932 +}; + + +int run_queries_sets(std::vector& queries, MYSQL *my, const std::string& message_prefix) { + for (std::vector::iterator it = queries.begin(); it != queries.end(); it++) { + std::string q = *it; + diag("%s: %s", message_prefix.c_str(), q.c_str()); + MYSQL_QUERY(my, q.c_str()); + } + return 0; +} + +#define ITER1 10 +// ITER2 is big because we iterate many times in case SSL_ERROR_SYSCALL (interrupted syscall, that is normally a rare event) is triggered +#define ITER2 20 + +int main(int argc, char** argv) { + CommandLine cl; + + if(cl.getEnv()) + return exit_status(); + + unsigned int p = 0; + p += 5*ITER1; + p += (5-3)*ITER2*queries_limits.size(); // only on encrypted backend connections + plan(p); + diag("Testing SSL and fast_forward"); + + MYSQL* mysqladmin = mysql_init(NULL); + if (!mysqladmin) + return exit_status(); + + if (!mysql_real_connect(mysqladmin, cl.host, cl.admin_username, cl.admin_password, NULL, cl.admin_port, NULL, 0)) { + fprintf(stderr, "File %s, line %d, Error: %s\n", + __FILE__, __LINE__, mysql_error(mysqladmin)); + return exit_status(); + } + + MYSQL * mysqls[5]; + for (int i = 0 ; i<5 ; i++) { + mysqls[i] = NULL; + } + // We will loop ITER1 times. + // On each iteration we create 5 connections with different configuration and run a simple SELECT 1 + + for (int it = 0 ; itthread_id, l, rr); + mysql_free_result(result); + } + } + } + + + + + for (int i=0; i<5; i++) { + diag("Connection %d has thread_id: %lu", i, mysqls[i]->thread_id); + } + + mysql_close(mysqladmin); + + return exit_status(); +} + diff --git a/test/tap/tests/test_ssl_fast_forward-2-t.cpp b/test/tap/tests/test_ssl_fast_forward-2-t.cpp new file mode 100644 index 000000000..0ed603894 --- /dev/null +++ b/test/tap/tests/test_ssl_fast_forward-2-t.cpp @@ -0,0 +1,255 @@ +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "tap.h" +#include "command_line.h" +#include "utils.h" + + +/* +this test uses a lot of code from test_ssl_fast_forward-t.cpp +*/ + +char * username = (char *)"user1459"; +char * password = (char *)"pass1459"; + +std::vector queries_set1 = { + "SET mysql-have_ssl='false'", + "LOAD MYSQL VARIABLES TO RUNTIME", + "DELETE FROM mysql_servers WHERE hostgroup_id = 1459", + "INSERT INTO mysql_servers (hostgroup_id, hostname, port, use_ssl) VALUES (1459, '127.0.0.1', 6030, 0)", + "LOAD MYSQL SERVERS TO RUNTIME", + "DELETE FROM mysql_users WHERE username = 'user1459'", + "INSERT INTO mysql_users (username,password,fast_forward,default_hostgroup) VALUES ('" + std::string(username) + "','" + std::string(password) + "',1,1459)", + "LOAD MYSQL USERS TO RUNTIME", +}; + +std::vector queries_set2 = { + "SET mysql-have_ssl='true'", + "LOAD MYSQL VARIABLES TO RUNTIME", +}; + +std::vector queries_set3 = { + "SET mysql-have_ssl='false'", + "LOAD MYSQL VARIABLES TO RUNTIME", + "UPDATE mysql_servers SET use_ssl=1 WHERE hostgroup_id = 1459", + "LOAD MYSQL SERVERS TO RUNTIME", +}; + +std::vector queries_set4 = { + "SET mysql-have_ssl='true'", + "LOAD MYSQL VARIABLES TO RUNTIME", + "UPDATE mysql_servers SET use_ssl=1 WHERE hostgroup_id = 1459", + "LOAD MYSQL SERVERS TO RUNTIME", +}; + +std::vector queries_SQL3 = { + "DROP TABLE IF EXISTS tbl1459v", + "CREATE TABLE tbl1459v (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL , t1 VARCHAR)", +}; + + +int run_queries_sets(std::vector& queries, MYSQL *my, const std::string& message_prefix) { + for (std::vector::iterator it = queries.begin(); it != queries.end(); it++) { + std::string q = *it; + diag("%s: %s", message_prefix.c_str(), q.c_str()); + MYSQL_QUERY(my, q.c_str()); + } + return 0; +} + +#define ITER1 1 + +#define LL 16000 // lower limit +#define UL 96000 // upper limit + +int main(int argc, char** argv) { + CommandLine cl; + + if(cl.getEnv()) + return exit_status(); + + unsigned int p = 0; + p += 5*ITER1; + //p += (5-3)*ITER2*queries_limits.size(); // only on encrypted backend connections + p += ((UL-LL)/1000*2); + plan(p); + diag("Testing SSL and fast_forward"); + + MYSQL* mysqladmin = mysql_init(NULL); + if (!mysqladmin) + return exit_status(); + + if (!mysql_real_connect(mysqladmin, cl.host, cl.admin_username, cl.admin_password, NULL, cl.admin_port, NULL, 0)) { + fprintf(stderr, "File %s, line %d, Error: %s\n", + __FILE__, __LINE__, mysql_error(mysqladmin)); + return exit_status(); + } + + MYSQL * mysqls[5]; + for (int i = 0 ; i<5 ; i++) { + mysqls[i] = NULL; + } + // We will loop ITER1 times. + // On each iteration we create 5 connections with different configuration and run a simple SELECT 1 + + for (int it = 0 ; itthread_id); + } + + // We now sends long INSERTs. This code is similar of test_ssl_large_query-t.cpp + + // We now populate a table named tbl1459v + if (run_queries_sets(queries_SQL3, mysqls[0], "Running on SQLite3")) + return exit_status(); + + + std::string s0 = "0"; + //for (int i=16001; i<=48000; i++) { + for (int i=LL; i +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "tap.h" +#include "command_line.h" +#include "utils.h" +#include + + + +char * username = (char *)"user1459"; +char * password = (char *)"pass1459"; + +const std::string lorem = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."; + +std::vector queries_set1 = { + "SET mysql-have_ssl='true'", + "LOAD MYSQL VARIABLES TO RUNTIME", + "DELETE FROM mysql_servers WHERE hostgroup_id = 1459", + "INSERT INTO mysql_servers (hostgroup_id, hostname, port, use_ssl) VALUES (1459, '127.0.0.1', 6030, 1)", + "LOAD MYSQL SERVERS TO RUNTIME", + "DELETE FROM mysql_users WHERE username = 'user1459'", + "INSERT INTO mysql_users (username,password,fast_forward,default_hostgroup) VALUES ('" + std::string(username) + "','" + std::string(password) + "',1,1459)", + "LOAD MYSQL USERS TO RUNTIME", +}; + + +int run_queries_sets(std::vector& queries, MYSQL *my, const std::string& message_prefix) { + for (std::vector::iterator it = queries.begin(); it != queries.end(); it++) { + std::string q = *it; + diag("%s: %s", message_prefix.c_str(), q.c_str()); + MYSQL_QUERY(my, q.c_str()); + } + return 0; +} + +#define ITER 400 +#define NTHR 4 +#define CPTH 100 + +CommandLine cl; + +std::mutex mtx_; + +int my_conn_thread_in(void *arg) { + MYSQL * mysqls[CPTH]; + for (int i = 0 ; i lock(mtx_); + ok(c != NULL , "Cipher in use: %s", c == NULL ? "NULL" : c); + } + } + for (int i=1; i<=ITER; i++) { + std::string s = "SELECT ''"; + for (int j=0; j lock(mtx_); + ok(s.length() == rl + strlen((const char *)"SELECT ''") + i*4 , "Line %d : on connection %ld , executed SELECT %ld bytes long. Length returned: %ld", __LINE__ , mysqls[(i+j)%CPTH]->thread_id, s.length(), rl); + } + } + } + return 0; +} + +void * my_conn_thread(void *arg) { + diag("Starting thread..."); + int rc = my_conn_thread_in(NULL); + diag("... thread ended!"); + return NULL; +} + + +int main(int argc, char** argv) { + + if(cl.getEnv()) + return exit_status(); + + plan(NTHR*(ITER+CPTH/2)); + diag("Testing SSL and fast_forward"); + + MYSQL* mysqladmin = mysql_init(NULL); + if (!mysqladmin) + return exit_status(); + + if (!mysql_real_connect(mysqladmin, cl.host, cl.admin_username, cl.admin_password, NULL, cl.admin_port, NULL, 0)) { + fprintf(stderr, "File %s, line %d, Error: %s\n", + __FILE__, __LINE__, mysql_error(mysqladmin)); + return exit_status(); + } + + // We will loop ITER1 times. + // On each iteration we create 5 connections with different configuration and run a simple SELECT 1 + + //for (int it = 0 ; it +#include +#include +#include + +#include +#include +#include +#include + +#include "tap.h" +#include "command_line.h" +#include "utils.h" + + +char * username = (char *)"user1459"; +char * password = (char *)"pass1459"; + +std::vector queries_set1 = { + "SET mysql-have_ssl='true'", + "LOAD MYSQL VARIABLES TO RUNTIME", + "DELETE FROM mysql_servers WHERE hostgroup_id = 1459", + "INSERT INTO mysql_servers (hostgroup_id, hostname, port, use_ssl) VALUES (1459, '127.0.0.1', 6030, 0)", + "LOAD MYSQL SERVERS TO RUNTIME", + "DELETE FROM mysql_users WHERE username = 'user1459'", + "INSERT INTO mysql_users (username,password,default_hostgroup) VALUES ('" + std::string(username) + "','" + std::string(password) + "',1459)", + "LOAD MYSQL USERS TO RUNTIME", +}; + +std::vector queries_SQL1 = { + "DROP TABLE IF EXISTS tbl1459", + "CREATE TABLE tbl1459 (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL , t1 VARCHAR)", +}; + + +int run_queries_sets(std::vector& queries, MYSQL *my, const std::string& message_prefix) { + for (std::vector::iterator it = queries.begin(); it != queries.end(); it++) { + std::string q = *it; + diag("%s: %s", message_prefix.c_str(), q.c_str()); + MYSQL_QUERY(my, q.c_str()); + } + return 0; +} + + +int main(int argc, char** argv) { + CommandLine cl; + + if(cl.getEnv()) + return exit_status(); + + plan(33); + diag("Testing SSL and fast_forward"); + + MYSQL* mysqladmin = mysql_init(NULL); + if (!mysqladmin) + return exit_status(); + + if (!mysql_real_connect(mysqladmin, cl.host, cl.admin_username, cl.admin_password, NULL, cl.admin_port, NULL, 0)) { + fprintf(stderr, "File %s, line %d, Error: %s\n", + __FILE__, __LINE__, mysql_error(mysqladmin)); + return exit_status(); + } + + MYSQL * mysql = NULL; + + diag("We will reconfigure ProxySQL to use SQLite3 Server on hostgroup 1459, IP 127.0.0.1 and port 6030"); + if (run_queries_sets(queries_set1, mysqladmin, "Running on Admin")) + return exit_status(); + + mysql = mysql_init(NULL); + if (!mysql) + return exit_status(); + + mysql_ssl_set(mysql, NULL, NULL, NULL, NULL, NULL); + if (!mysql_real_connect(mysql, cl.host, username, password, NULL, cl.port, NULL, CLIENT_SSL)) { + fprintf(stderr, "Failed to connect to database: Error: %s\n", + mysql_error(mysql)); + return exit_status(); + } + const char * c = mysql_get_ssl_cipher(mysql); + ok(c != NULL , "Cipher in use: %s", c == NULL ? "NULL" : c); + + // We now create a table named tbl1459 + if (run_queries_sets(queries_SQL1, mysql, "Running on SQLite3")) + return exit_status(); + + std::string s0 = "0"; + for (int i=16001; i<=48000; i++) { + std::string s = "INSERT INTO tbl1459 VALUES (" + std::to_string(i) + ",'"; + for (int j=0; j +#include +#include +#include + +#include +#include +#include +#include + +#include "tap.h" +#include "command_line.h" +#include "utils.h" + + +char * username = (char *)"user1459"; +char * password = (char *)"pass1459"; + +std::vector queries_set1 = { + "SET mysql-have_ssl='true'", + "LOAD MYSQL VARIABLES TO RUNTIME", + "DELETE FROM mysql_users WHERE username = 'user1459'", + "INSERT INTO mysql_users (username,password,default_hostgroup) VALUES ('" + std::string(username) + "','" + std::string(password) + "',1459)", + "LOAD MYSQL USERS TO RUNTIME", +}; + +std::vector queries_SQL1 = { + "DROP TABLE IF EXISTS tbl1459", + "CREATE TABLE tbl1459 (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL , t1 VARCHAR)", +}; + + +int run_queries_sets(std::vector& queries, MYSQL *my, const std::string& message_prefix) { + for (std::vector::iterator it = queries.begin(); it != queries.end(); it++) { + std::string q = *it; + diag("%s: %s", message_prefix.c_str(), q.c_str()); + MYSQL_QUERY(my, q.c_str()); + } + return 0; +} + +#define ITER 400 + +const std::string lorem = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."; + +int main(int argc, char** argv) { + CommandLine cl; + + if(cl.getEnv()) + return exit_status(); + + plan(2+2*ITER); + diag("Testing SSL and fast_forward"); + + MYSQL* mysqladmin = mysql_init(NULL); + if (!mysqladmin) + return exit_status(); + + if (!mysql_real_connect(mysqladmin, cl.host, cl.admin_username, cl.admin_password, NULL, cl.admin_port, NULL, 0)) { + fprintf(stderr, "File %s, line %d, Error: %s\n", + __FILE__, __LINE__, mysql_error(mysqladmin)); + return exit_status(); + } + + + + if (run_queries_sets(queries_set1, mysqladmin, "Running on Admin")) + return exit_status(); + + + MYSQL * mysqladmin2 = mysql_init(NULL); + if (!mysqladmin2) + return exit_status(); + + mysql_ssl_set(mysqladmin2, NULL, NULL, NULL, NULL, NULL); + if (!mysql_real_connect(mysqladmin2, cl.host, cl.admin_username, cl.admin_password, NULL, cl.admin_port, NULL, 0)) { + fprintf(stderr, "File %s, line %d, Error: %s\n", + __FILE__, __LINE__, mysql_error(mysqladmin2)); + return exit_status(); + } + + { + const char * c = mysql_get_ssl_cipher(mysqladmin2); + ok(c != NULL , "Cipher in use: %s", c == NULL ? "NULL" : c); + } + + MYSQL * mysqllite3 = mysql_init(NULL); + if (!mysqllite3) + return exit_status(); + + mysql_ssl_set(mysqllite3, NULL, NULL, NULL, NULL, NULL); + if (!mysql_real_connect(mysqllite3, cl.host, username, password, NULL, 6030, NULL, 0)) { + fprintf(stderr, "File %s, line %d, Error: %s\n", + __FILE__, __LINE__, mysql_error(mysqllite3)); + return exit_status(); + } + + { + const char * c = mysql_get_ssl_cipher(mysqllite3); + ok(c != NULL , "Cipher in use: %s", c == NULL ? "NULL" : c); + } + + for (int i=1; i<=ITER; i++) { + std::string s = "SELECT ''"; + for (int j=0; j