From 52a1d8a8d9b1db1995e9e291f5b96f14152c0f72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Canna=C3=B2?= Date: Fri, 2 Feb 2018 08:51:18 +0100 Subject: [PATCH] Added experimental (not completed) support for SSL client side --- include/MySQL_Data_Stream.h | 12 +- include/proxysql.h | 1 + lib/MySQL_Protocol.cpp | 32 ++-- lib/MySQL_Session.cpp | 78 ++++++-- lib/mysql_data_stream.cpp | 345 +++++++++++++++++++++++++++++++++++- 5 files changed, 435 insertions(+), 33 deletions(-) diff --git a/include/MySQL_Data_Stream.h b/include/MySQL_Data_Stream.h index aef35683f..90add5008 100644 --- a/include/MySQL_Data_Stream.h +++ b/include/MySQL_Data_Stream.h @@ -5,7 +5,9 @@ #include "cpp.h" -#define QUEUE_T_DEFAULT_SIZE 32768 +//#define QUEUE_T_DEFAULT_SIZE 32768 +#define QUEUE_T_DEFAULT_SIZE 8192 +#define MY_SSL_BUFFER 8192 typedef struct _queue_t { void *buffer; @@ -43,12 +45,16 @@ class MyDS_real_query { } }; +enum sslstatus { SSLSTATUS_OK, SSLSTATUS_WANT_IO, SSLSTATUS_FAIL}; + class MySQL_Data_Stream { private: int array2buffer(); int buffer2array(); void generate_compressed_packet(); + enum sslstatus do_ssl_handshake(); + void queue_encrypted_bytes(const char *buf, size_t len); public: void * operator new(size_t); void operator delete(void *); @@ -90,6 +96,10 @@ class MySQL_Data_Stream MySQL_Session *sess; // pointer to the session using this data stream MySQL_Backend *mybe; // if this is a connection to a mysql server, this points to a backend structure SSL *ssl; + BIO *rbio_ssl; + BIO *wbio_ssl; + char *ssl_write_buf; + size_t ssl_write_len; struct sockaddr *client_addr; struct { diff --git a/include/proxysql.h b/include/proxysql.h index 7f00706ff..3c292e6c1 100644 --- a/include/proxysql.h +++ b/include/proxysql.h @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include diff --git a/lib/MySQL_Protocol.cpp b/lib/MySQL_Protocol.cpp index d69d76423..e482df72e 100644 --- a/lib/MySQL_Protocol.cpp +++ b/lib/MySQL_Protocol.cpp @@ -1329,14 +1329,21 @@ bool MySQL_Protocol::process_pkt_handshake_response(unsigned char *pkt, unsigned pkt += sizeof(uint32_t); charset = *(uint8_t *)pkt; // see bug #810 + if ( (*myds)->encrypted == false ) { // client wants to use SSL + if (len == sizeof(mysql_hdr)+32) { + (*myds)->encrypted = true; + use_ssl = true; + return false; + } + } if (charset==0) { charset=mysql_thread___default_charset; } pkt += 24; - if (len==sizeof(mysql_hdr)+32) { - (*myds)->encrypted=true; - use_ssl=true; - } else { +// if (len==sizeof(mysql_hdr)+32) { +// (*myds)->encrypted=true; +// use_ssl=true; +// } else { user = pkt; pkt += strlen((char *)user) + 1; @@ -1412,20 +1419,21 @@ bool MySQL_Protocol::process_pkt_handshake_response(unsigned char *pkt, unsigned // currently proxysql doesn't know any sha1_pass for that specific user, let's set it! GloMyAuth->set_SHA1((char *)user, USERNAME_FRONTEND,reply); } - if (userinfo->sha1_pass) free(userinfo->sha1_pass); + if (userinfo->sha1_pass) + free(userinfo->sha1_pass); userinfo->sha1_pass=sha1_pass_hex(reply); } - } } } } - if (_ret_use_ssl==true) { - // if we reached here, use_ssl is false , but _ret_use_ssl is true - // it means that a client is required to use SSL , but it is not - ret=false; - } } - proxy_debug(PROXY_DEBUG_MYSQL_PROTOCOL,1,"Handshake (%s auth) , capabilities:%u char:%u, use_ssl:%s\n", +// if (_ret_use_ssl==true) { +// // if we reached here, use_ssl is false , but _ret_use_ssl is true +// // it means that a client is required to use SSL , but it is not +// ret=false; +// } +// } + proxy_debug(PROXY_DEBUG_MYSQL_PROTOCOL,1,"Handshake (%s auth) , capabilities:%u char:%u, use_ssl:%s\n", (capabilities & CLIENT_SECURE_CONNECTION ? "new" : "old"), user, password, pass, db, max_pkt, capabilities, charset, ((*myds)->encrypted ? "yes" : "no")); assert(sess); assert(sess->client_myds); diff --git a/lib/MySQL_Session.cpp b/lib/MySQL_Session.cpp index 47a00a9a6..3802e65e0 100644 --- a/lib/MySQL_Session.cpp +++ b/lib/MySQL_Session.cpp @@ -1957,7 +1957,8 @@ __get_pkts_from_client: handler___status_CONNECTING_CLIENT___STATE_SERVER_HANDSHAKE(&pkt, &wrong_pass); break; case STATE_SSL_INIT: - handler___status_CONNECTING_CLIENT___STATE_SSL_INIT(&pkt); + handler___status_CONNECTING_CLIENT___STATE_SERVER_HANDSHAKE(&pkt, &wrong_pass); + //handler___status_CONNECTING_CLIENT___STATE_SSL_INIT(&pkt); break; default: proxy_error("Detected not valid state client state: %d\n", client_myds->DSS); @@ -3186,8 +3187,59 @@ void MySQL_Session::handler___status_CHANGING_USER_CLIENT___STATE_CLIENT_HANDSHA } void MySQL_Session::handler___status_CONNECTING_CLIENT___STATE_SERVER_HANDSHAKE(PtrSize_t *pkt, bool *wrong_pass) { + bool is_encrypted = client_myds->encrypted; + bool handshake_response_return = client_myds->myprot.process_pkt_handshake_response((unsigned char *)pkt->ptr,pkt->size); + + if ( + (is_encrypted == false) && // the connection was encrypted + (handshake_response_return == false) && // the authentication didn't complete + (client_myds->encrypted == true) // client is asking for encryption + ) { + // use SSL + client_myds->DSS=STATE_SSL_INIT; + client_myds->rbio_ssl = BIO_new(BIO_s_mem()); + client_myds->wbio_ssl = BIO_new(BIO_s_mem()); + client_myds->ssl=SSL_new(GloVars.global.ssl_ctx); + SSL_set_fd(client_myds->ssl, client_myds->fd); + SSL_set_accept_state(client_myds->ssl); + SSL_set_bio(client_myds->ssl, client_myds->rbio_ssl, client_myds->wbio_ssl); +/* + while (!SSL_is_init_finished(client_myds->ssl)) { + int ret = SSL_do_handshake(client_myds->ssl); + int ret2; + if (ret != 1) { + //ERR_print_errors_fp(stderr); + ret2 = SSL_get_error(client_myds->ssl, ret); + fprintf(stderr,"%d\n",ret2); + } + + } +*/ +// if (!SSL_is_init_finished(client_myds->ssl)) { +// int n = SSL_do_handshake(client_myds->ssl); +// +// } + //ioctl_FIONBIO(client_myds->fd,0); + +// bool connected = false; +// while (connected) { +// if (!SSL_accept(client_myds->ssl)==-1) { +// if (SSL_do_handshake(client_myds->ssl)==-1) { +// ERR_print_errors_fp(stderr); +// } else { +// connected = true; +// } +// } + //ioctl_FIONBIO(client_myds->fd,1); + //int my_ssl_error; + //int n = SSL_accept(client_myds->ssl); + //my_ssl_error = SSL_get_error(client_mmyds->ssl); + return; + } + if ( - (client_myds->myprot.process_pkt_handshake_response((unsigned char *)pkt->ptr,pkt->size)==true) + //(client_myds->myprot.process_pkt_handshake_response((unsigned char *)pkt->ptr,pkt->size)==true) + (handshake_response_return == true) && ( //(default_hostgroup<0 && ( session_type == PROXYSQL_SESSION_ADMIN || session_type == PROXYSQL_SESSION_STATS || session_type == PROXYSQL_SESSION_SQLITE) ) @@ -3213,7 +3265,7 @@ void MySQL_Session::handler___status_CONNECTING_CLIENT___STATE_SERVER_HANDSHAKE( } } l_free(pkt->size,pkt->ptr); - if (client_myds->encrypted==false) { + //if (client_myds->encrypted==false) { if (client_myds->myconn->userinfo->schemaname==NULL) { client_myds->myconn->userinfo->set_schemaname(default_schema,strlen(default_schema)); } @@ -3303,25 +3355,26 @@ void MySQL_Session::handler___status_CONNECTING_CLIENT___STATE_SERVER_HANDSHAKE( (strcmp(client_addr,(char *)"::1")==0) ) { // we are good! - client_myds->myprot.generate_pkt_OK(true,NULL,NULL,2,0,0,0,0,NULL); + client_myds->myprot.generate_pkt_OK(true,NULL,NULL, (is_encrypted ? 3 : 2), 0,0,0,0,NULL); status=WAITING_CLIENT_DATA; client_myds->DSS=STATE_CLIENT_AUTH_OK; } else { char *a=(char *)"User '%s' can only connect locally"; char *b=(char *)malloc(strlen(a)+strlen(client_myds->myconn->userinfo->username)); sprintf(b,a,client_myds->myconn->userinfo->username); - client_myds->myprot.generate_pkt_ERR(true,NULL,NULL,2,1040,(char *)"42000", b); + client_myds->myprot.generate_pkt_ERR(true,NULL,NULL, (is_encrypted ? 3 : 2), 1040,(char *)"42000", b); free(b); } free(client_addr); } else { // we are good! - client_myds->myprot.generate_pkt_OK(true,NULL,NULL,2,0,0,0,0,NULL); + client_myds->myprot.generate_pkt_OK(true,NULL,NULL, (is_encrypted ? 3 : 2), 0,0,0,0,NULL); status=WAITING_CLIENT_DATA; client_myds->DSS=STATE_CLIENT_AUTH_OK; } } - } else { +// } else { +/* // use SSL client_myds->DSS=STATE_SSL_INIT; client_myds->ssl=SSL_new(GloVars.global.ssl_ctx); @@ -3331,7 +3384,8 @@ void MySQL_Session::handler___status_CONNECTING_CLIENT___STATE_SERVER_HANDSHAKE( ERR_print_errors_fp(stderr); } ioctl_FIONBIO(client_myds->fd,1); - } +*/ +// } } else { l_free(pkt->size,pkt->ptr); proxy_debug(PROXY_DEBUG_MYSQL_CONNECTION, 5, "Wrong credentials for frontend: disconnecting\n"); @@ -3365,18 +3419,19 @@ void MySQL_Session::handler___status_CONNECTING_CLIENT___STATE_SERVER_HANDSHAKE( } else { client_addr = strdup((char *)""); } - if (client_myds->encrypted == false) { + //if (client_myds->encrypted == false) { char *_s=(char *)malloc(strlen(client_myds->myconn->userinfo->username)+100+strlen(client_addr)); sprintf(_s,"ProxySQL Error: Access denied for user '%s'@'%s' (using password: %s)", client_myds->myconn->userinfo->username, client_addr, (client_myds->myconn->userinfo->password ? "YES" : "NO")); - client_myds->myprot.generate_pkt_ERR(true,NULL,NULL,2,1045,(char *)"28000", _s); + client_myds->myprot.generate_pkt_ERR(true,NULL,NULL, (is_encrypted ? 3 : 2), 1045,(char *)"28000", _s); __sync_add_and_fetch(&MyHGM->status.client_connections_aborted,1); free(_s); client_myds->DSS=STATE_SLEEP; - } + //} } } void MySQL_Session::handler___status_CONNECTING_CLIENT___STATE_SSL_INIT(PtrSize_t *pkt) { +/* if (client_myds->myprot.process_pkt_handshake_response((unsigned char *)pkt->ptr,pkt->size)==true) { l_free(pkt->size,pkt->ptr); client_myds->myprot.generate_pkt_OK(true,NULL,NULL,3,0,0,0,0,NULL); @@ -3389,6 +3444,7 @@ void MySQL_Session::handler___status_CONNECTING_CLIENT___STATE_SSL_INIT(PtrSize_ perror("Hitting a not implemented feature: https://github.com/sysown/proxysql-0.2/issues/124"); assert(0); } +*/ } diff --git a/lib/mysql_data_stream.cpp b/lib/mysql_data_stream.cpp index ec427000c..fcabf05ec 100644 --- a/lib/mysql_data_stream.cpp +++ b/lib/mysql_data_stream.cpp @@ -72,6 +72,56 @@ static void __dump_pkt(const char *func, unsigned char *_ptr, unsigned int len) +//enum sslstatus { SSLSTATUS_OK, SSLSTATUS_WANT_IO, SSLSTATUS_FAIL}; + +static enum sslstatus get_sslstatus(SSL* ssl, int n) +{ + int err = SSL_get_error(ssl, n); + switch (err) { + case SSL_ERROR_NONE: + return SSLSTATUS_OK; + case SSL_ERROR_WANT_WRITE: + case SSL_ERROR_WANT_READ: + return SSLSTATUS_WANT_IO; + case SSL_ERROR_ZERO_RETURN: + case SSL_ERROR_SYSCALL: + default: + return SSLSTATUS_FAIL; + } +} + + +void MySQL_Data_Stream::queue_encrypted_bytes(const char *buf, size_t len) { + ssl_write_buf = (char*)realloc(ssl_write_buf, ssl_write_len + len); + memcpy(ssl_write_buf + ssl_write_len, buf, len); + ssl_write_len += len; + //proxy_info("New ssl_write_len size: %u\n", ssl_write_len); +} + +enum sslstatus MySQL_Data_Stream::do_ssl_handshake() { + char buf[MY_SSL_BUFFER]; + enum sslstatus status; + int n = SSL_do_handshake(ssl); + status = get_sslstatus(ssl, n); + //proxy_info("SSL status = %d\n", status); + /* Did SSL request to write bytes? */ + if (status == SSLSTATUS_WANT_IO) { + //proxy_info("SSL status is WANT_IO %d\n", status); + do { + n = BIO_read(wbio_ssl, buf, sizeof(buf)); + //proxy_info("BIO read = %d\n", n); + if (n > 0) { + //proxy_info("Queuing %d encrypted bytes\n", n); + queue_encrypted_bytes(buf, n); + } else if (!BIO_should_retry(wbio_ssl)) { + //proxy_info("BIO_should_retry failed\n"); + return SSLSTATUS_FAIL; + } + } while (n>0); + } + return status; +} + void * MySQL_Data_Stream::operator new(size_t size) { return l_alloc(size); } @@ -122,6 +172,10 @@ MySQL_Data_Stream::MySQL_Data_Stream() { DSS=STATE_NOT_CONNECTED; encrypted=false; ssl=NULL; + rbio_ssl = NULL; + wbio_ssl = NULL; + ssl_write_len = 0; + ssl_write_buf = NULL; net_failure=false; CompPktIN.pkt.ptr=NULL; CompPktIN.pkt.size=0; @@ -193,6 +247,15 @@ MySQL_Data_Stream::~MySQL_Data_Stream() { if ( (myconn) && (myds_type==MYDS_FRONTEND) ) { delete myconn; myconn=NULL; } if (encrypted) { 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); @@ -257,6 +320,9 @@ void MySQL_Data_Stream::shut_soft() { void MySQL_Data_Stream::shut_hard() { proxy_debug(PROXY_DEBUG_NET, 4, "Shutdown hard fd=%d. Session=%p, DataStream=%p\n", fd, sess, this); set_net_failure(); + if (encrypted) { + SSL_set_quiet_shutdown(ssl, 1); + } if (fd >= 0) { shutdown(fd, SHUT_RDWR); close(fd); @@ -287,10 +353,125 @@ void MySQL_Data_Stream::check_data_flow() { } int MySQL_Data_Stream::read_from_net() { + if (encrypted) { + //proxy_info("Entering\n"); + } if ((revents & POLLIN)==0) return 0; - int r; + int r=0; int s=queue_available(queueIN); - r = ( encrypted ? SSL_read (ssl, queue_w_ptr(queueIN), s) : recv(fd, queue_w_ptr(queueIN), s, 0) ); + if (encrypted) { + // proxy_info("Queue available of %d bytes\n", s); + } + if (encrypted == false) { + if (pkts_recv) { + r = recv(fd, queue_w_ptr(queueIN), s, 0); + } else { + if (queueIN.partial == 0) { + // we are reading the very first packet + // to avoid issue with SSL, we will only read the header and eventually the first packet + r = recv(fd, queue_w_ptr(queueIN), 4, 0); + if (r == 4) { + // let's try to read a whole packet + mysql_hdr Hdr; + memcpy(&Hdr,queueIN.buffer,sizeof(mysql_hdr)); + r += recv(fd, queue_w_ptr(queueIN)+4, Hdr.pkt_length, 0); + } + } else { + r = recv(fd, queue_w_ptr(queueIN), s, 0); + } + } + } else { +/* + if (!SSL_is_init_finished(ssl)) { + int ret = SSL_do_handshake(ssl); + int ret2; + if (ret != 1) { + //ERR_print_errors_fp(stderr); + ret2 = SSL_get_error(ssl, ret); + fprintf(stderr,"%d\n",ret2); + } + return 0; + } else { + r = SSL_read (ssl, queue_w_ptr(queueIN), s); + } +*/ + if (s < MY_SSL_BUFFER) { + return 0; // no enough space for reads + } + char buf[MY_SSL_BUFFER]; + //ssize_t n = read(fd, buf, sizeof(buf)); + int n = recv(fd, buf, sizeof(buf), 0); + //proxy_info("SSL recv of %d bytes\n", n); + if (n > 0) { + //on_read_cb(buf, (size_t)n); + + char buf2[MY_SSL_BUFFER]; + int n2; + enum sslstatus status; + char *src = buf; + int len = n; + while (len) { + n2 = BIO_write(rbio_ssl, src, len); + //proxy_info("BIO_write with len = %d and %d bytes\n", len , n2); + if (n2 <= 0) { + shut_soft(); + return -1; + } + src += n2; + len -= n2; + if (!SSL_is_init_finished(ssl)) { + //proxy_info("SSL_is_init_finished NOT completed\n"); + if (do_ssl_handshake() == SSLSTATUS_FAIL) { + //proxy_info("SSL_is_init_finished failed!!\n"); + shut_soft(); + return -1; + } + if (!SSL_is_init_finished(ssl)) { + //proxy_info("SSL_is_init_finished yet NOT completed\n"); + return 0; + } + } else { + //proxy_info("SSL_is_init_finished completed\n"); + } + } + n2 = SSL_read (ssl, queue_w_ptr(queueIN), s); + r = n2; + //proxy_info("Read %d bytes from SSL\n", r); + if (n2 > 0) { + } +/* + do { + n2 = SSL_read(ssl, buf2, sizeof(buf2)); + if (n2 > 0) { + + } + } while (n > 0); +*/ + status = get_sslstatus(ssl, n2); + //proxy_info("SSL status = %d\n", status); + if (status == SSLSTATUS_WANT_IO) { + do { + n2 = BIO_read(wbio_ssl, buf2, sizeof(buf2)); + //proxy_info("BIO_read with %d bytes\n", n2); + if (n2 > 0) { + queue_encrypted_bytes(buf2, n2); + } else if (!BIO_should_retry(wbio_ssl)) { + shut_soft(); + return -1; + } + } while (n2>0); + } + if (status == SSLSTATUS_FAIL) { + shut_soft(); + return -1; + } + } else { + r = n; + //r += SSL_read (ssl, queue_w_ptr(queueIN), s); + //proxy_info("Read %d bytes from SSL\n", r); + } + } +//__exit_read_from_next: proxy_debug(PROXY_DEBUG_NET, 5, "read %d bytes from fd %d into a buffer of %d bytes free\n", r, fd, s); //proxy_error("read %d bytes from fd %d into a buffer of %d bytes free\n", r, fd, s); if (r < 1) { @@ -314,11 +495,61 @@ int MySQL_Data_Stream::read_from_net() { int MySQL_Data_Stream::write_to_net() { int bytes_io=0; int s = queue_data(queueOUT); - if (s==0) return 0; + int n; + if (encrypted) { + //proxy_info("Data in write buffer: %d bytes\n", s); + } + if (s==0) { + if (encrypted == false) { + return 0; + } + if (ssl_write_len == 0 && wbio_ssl->num_write == wbio_ssl->num_read) { + return 0; + } + } VALGRIND_DISABLE_ERROR_REPORTING; // splitting the ternary operation in IF condition for better readability if (encrypted) { bytes_io = SSL_write (ssl, queue_r_ptr(queueOUT), s); + //proxy_info("Used SSL_write to write %d bytes\n", bytes_io); + 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_info("BIO read = %d\n", n); + if (n > 0) { + //proxy_info("Setting %d byte in queue encrypted\n", n); + queue_encrypted_bytes(buf, n); + } + else if (!BIO_should_retry(wbio_ssl)) { + //proxy_info("BIO_should_retry failed\n"); + shut_soft(); + return -1; + } + } while (n>0); + } + if (ssl_write_len) { + n = write(fd, ssl_write_buf, ssl_write_len); + //proxy_info("Calling write() on SSL: %d\n", n); + if (n>0) { + if ((size_t)n < ssl_write_len) { + memmove(ssl_write_buf, ssl_write_buf+n, ssl_write_len-n); + } + ssl_write_len -= n; + ssl_write_buf = (char*)realloc(ssl_write_buf, ssl_write_len); + //proxy_info("new ssl_write_len: %u\n", ssl_write_len); + //if (ssl_write_len) { + // return n; // stop here + //} else { + // rc = n; // and continue + //} + //bytes_io += n; + } else { + shut_soft(); + return -1; + } + } } else { #ifdef __APPLE__ bytes_io = send(fd, queue_r_ptr(queueOUT), s, 0); @@ -326,6 +557,9 @@ int MySQL_Data_Stream::write_to_net() { bytes_io = send(fd, queue_r_ptr(queueOUT), s, MSG_NOSIGNAL); #endif } + if (encrypted) { + //proxy_info("bytes_io: %d\n", bytes_io); + } VALGRIND_ENABLE_ERROR_REPORTING; if (bytes_io < 0) { if (encrypted==false) { @@ -374,10 +608,31 @@ void MySQL_Data_Stream::set_pollout() { if (DSS > STATE_MARIADB_BEGIN && DSS < STATE_MARIADB_END) { _pollfd->events = myconn->wait_events; } else { + _pollfd->events = POLLIN; + //if (PSarrayOUT->len || available_data_out() || queueOUT.partial || (encrypted && !SSL_is_init_finished(ssl))) { if (PSarrayOUT->len || available_data_out() || queueOUT.partial) { - _pollfd->events = POLLIN | POLLOUT; - } else { - _pollfd->events = POLLIN; + _pollfd->events |= POLLOUT; + } + if (encrypted) { + if (ssl_write_len || wbio_ssl->num_write > wbio_ssl->num_read) { + _pollfd->events |= POLLOUT; + } else { + if (!SSL_is_init_finished(ssl)) { + //proxy_info("SSL_is_init_finished NOT completed\n"); + if (do_ssl_handshake() == SSLSTATUS_FAIL) { + //proxy_info("SSL_is_init_finished failed!!\n"); + shut_soft(); + return; + } + if (!SSL_is_init_finished(ssl)) { + //proxy_info("SSL_is_init_finished yet NOT completed\n"); + return; + } + } else { + //proxy_info("SSL_is_init_finished completed\n"); + } + _pollfd->events |= POLLOUT; + } } } proxy_debug(PROXY_DEBUG_NET,1,"Session=%p, DataStream=%p -- Setting poll events %d for FD %d , DSS=%d , myconn=%p\n", sess, this, _pollfd->events , fd, DSS, myconn); @@ -386,18 +641,87 @@ void MySQL_Data_Stream::set_pollout() { int MySQL_Data_Stream::write_to_net_poll() { int rc=0; if (active==0) return rc; +/* + if (encrypted && !SSL_is_init_finished(ssl)) { + int ret = SSL_do_handshake(ssl); + int ret2; + if (ret != 1) { + //ERR_print_errors_fp(stderr); + ret2 = SSL_get_error(ssl, ret); + fprintf(stderr,"%d\n",ret2); + } + return 0; + } +*/ + if (encrypted) { + if (!SSL_is_init_finished(ssl)) { + //proxy_info("SSL_is_init_finished completed: NO!\n"); + if (do_ssl_handshake() == SSLSTATUS_FAIL) { + //proxy_info("SSL_is_init_finished failed!!\n"); + shut_soft(); + return -1; + } + } else { + //proxy_info("SSL_is_init_finished completed: YES\n"); + } +/* + if (!SSL_is_init_finished(ssl)) { + proxy_info("SSL_is_init_finished completed: NO!\n"); + if (fd>0 && sess->session_type == PROXYSQL_SESSION_MYSQL) { + set_pollout(); + return 0; + } + } +*/ + //proxy_info("ssl_write_len: %u\n", ssl_write_len); + if (ssl_write_len) { + int n = write(fd, ssl_write_buf, ssl_write_len); + //proxy_info("Calling write() on SSL: %d\n", n); + if (n>0) { + if ((size_t)n < ssl_write_len) { + memmove(ssl_write_buf, ssl_write_buf+n, ssl_write_len-n); + } + ssl_write_len -= n; + ssl_write_buf = (char*)realloc(ssl_write_buf, ssl_write_len); + //proxy_info("new ssl_write_len: %u\n", ssl_write_len); + if (ssl_write_len) { + return n; // stop here + } else { + rc = n; // and continue + } + } else { + shut_soft(); + return -1; + } + } + } proxy_debug(PROXY_DEBUG_NET,1,"Session=%p, DataStream=%p --\n", sess, this); + bool call_write_to_net = false; if (queue_data(queueOUT)) { + call_write_to_net = true; + } + if (call_write_to_net == false) { + if (encrypted) { + if (ssl_write_len || wbio_ssl->num_write > wbio_ssl->num_read) { + call_write_to_net = true; + } + } + } + if (call_write_to_net) { if (sess->session_type == PROXYSQL_SESSION_MYSQL) { if (poll_fds_idx>-1) { // NOTE: attempt to force writes if (net_failure==false) - rc=write_to_net(); + rc += write_to_net(); } } else { - rc=write_to_net(); + rc += write_to_net(); } } - if (fd>0 && sess->session_type == PROXYSQL_SESSION_MYSQL) set_pollout(); + if (fd>0 && sess->session_type == PROXYSQL_SESSION_MYSQL) { + // PROXYSQL_SESSION_MYSQL is a requirement, because it uses threads pool + // the other session types do not + set_pollout(); + } return rc; } @@ -463,6 +787,9 @@ int MySQL_Data_Stream::buffer2array() { memcpy((unsigned char *)queueIN.pkt.ptr + queueIN.partial, queue_r_ptr(queueIN),b); queue_r(queueIN,b); queueIN.partial+=b; + if (queueIN.partial == 80) { + proxy_info("Breakpoint\n"); + } ret+=b; } if ((queueIN.pkt.size>0) && (queueIN.pkt.size==queueIN.partial) ) {