From 5d1895561ca299efa6c2ce4173463655f7523ddc Mon Sep 17 00:00:00 2001 From: Markus Makela Date: Fri, 11 Sep 2015 14:28:39 +0300 Subject: [PATCH] Moved parts of dcb_read_SSL to separate functions. --- server/core/dcb.c | 379 +++++++++++++++++++++++----------------------- 1 file changed, 189 insertions(+), 190 deletions(-) diff --git a/server/core/dcb.c b/server/core/dcb.c index 6d0617e05..398741638 100644 --- a/server/core/dcb.c +++ b/server/core/dcb.c @@ -109,6 +109,8 @@ static inline void dcb_write_when_already_queued(DCB *dcb, GWBUF *queue); static void dcb_log_write_failure(DCB *dcb, GWBUF *queue, int eno); static inline void dcb_write_tidy_up(DCB *dcb, bool below_water); static void dcb_write_SSL_error_report (DCB *dcb, int ret, int ssl_errno); +int dcb_bytes_readable_SSL (DCB *dcb, int nread); +void dcb_log_ssl_read_error(DCB *dcb, int ssl_errno, int rc); size_t dcb_get_session_id( DCB *dcb) @@ -909,208 +911,104 @@ int dcb_read( * @return -1 on error, otherwise the number of read bytes on the last * iteration of while loop. 0 is returned if no data available. */ -int dcb_read_SSL( - DCB *dcb, - GWBUF **head) +int dcb_read_SSL(DCB *dcb, + GWBUF **head) { - GWBUF *buffer = NULL; - int b,pending; - int rc; - int n; - int nread = 0; - int ssl_errno = 0; - CHK_DCB(dcb); + GWBUF *buffer = NULL; + int b, n, nread = 0; + CHK_DCB(dcb); - if (dcb->fd <= 0) - { - LOGIF(LE, (skygw_log_write_flush( - LOGFILE_ERROR, - "Error : Read failed, dcb is %s.", - dcb->fd == DCBFD_CLOSED ? "closed" : "cloned, not readable"))); - n = 0; - goto return_n; - } + if (dcb->fd <= 0) + { + LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR, + "Error : Read failed, dcb is %s.", + dcb->fd == DCBFD_CLOSED ? "closed" : "cloned, not readable"))); + return 0; + } - while (true) + while ((b = dcb_bytes_readable_SSL(dcb, nread)) > 0) + { + dcb->last_read = hkheartbeat; + int bufsize = MIN(b, MAX_BUFFER_SIZE); + + if ((buffer = gwbuf_alloc(bufsize)) == NULL) { - int bufsize; - ssl_errno = 0; - rc = ioctl(dcb->fd, FIONREAD, &b); - pending = SSL_pending(dcb->ssl); - if (rc == -1) - { - char errbuf[STRERROR_BUFLEN]; - LOGIF(LE, (skygw_log_write_flush( - LOGFILE_ERROR, - "Error : ioctl FIONREAD for dcb %p in " - "state %s fd %d failed due error %d, %s.", - dcb, - STRDCBSTATE(dcb->state), - dcb->fd, - errno, - strerror_r(errno, errbuf, sizeof(errbuf))))); - n = -1; - goto return_n; - } + /*< + * This is a fatal error which should cause shutdown. + * Todo shutdown if memory allocation fails. + */ + char errbuf[STRERROR_BUFLEN]; + LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR, + "Error : Failed to allocate read buffer " + "for dcb %p fd %d, due %d, %s.", + dcb, + dcb->fd, + errno, + strerror_r(errno, errbuf, sizeof (errbuf))))); - if (b == 0 && pending == 0 && nread == 0) - { - /** Handle closed client socket */ - if (dcb_isclient(dcb)) - { - char c = 0; - int r = -1; + return -1; + } - /* try to read 1 byte, without consuming the socket buffer */ - r = SSL_peek(dcb->ssl, &c, sizeof(char)); - if (r <= 0) - { - ssl_errno = SSL_get_error(dcb->ssl,r); - if(ssl_errno != SSL_ERROR_WANT_READ && - ssl_errno != SSL_ERROR_WANT_WRITE && - ssl_errno != SSL_ERROR_NONE) - n = -1; - else - n = 0; - goto return_n; - } - } - n = 0; - goto return_n; - } - else if (b == 0 && pending == 0) - { - n = 0; - goto return_n; - } + n = SSL_read(dcb->ssl, GWBUF_DATA(buffer), bufsize); + dcb->stats.n_reads++; + + if (n <= 0) + { + int ssl_errno = SSL_get_error(dcb->ssl, n); + dcb_log_ssl_read_error(dcb, ssl_errno, n); + + if (ssl_errno != SSL_ERROR_WANT_READ && + ssl_errno != SSL_ERROR_WANT_WRITE && + ssl_errno != SSL_ERROR_NONE) + { + nread = -1; + gwbuf_free(buffer); + } + return nread; + } + + buffer = gwbuf_rtrim(buffer, bufsize - n); + + if (buffer) + { #ifdef SS_DEBUG - else - { - skygw_log_write_flush(LD,"Total: %d Socket: %d Pending: %d", - nread,b,pending); - } + skygw_log_write(LD, "%lu SSL: Truncated buffer from %d to %d bytes. " + "Read %d bytes, %d bytes waiting.\n", pthread_self(), + bufsize, GWBUF_LENGTH(buffer), n, b); + + if (GWBUF_LENGTH(buffer) != n) + { + skygw_log_sync_all(); + } + + ss_info_dassert((buffer->start <= buffer->end), "Buffer start has passed end."); + ss_info_dassert(GWBUF_LENGTH(buffer) == n, "Buffer size not equal to read bytes."); #endif + nread += n; - dcb->last_read = hkheartbeat; + LOGIF(LD, (skygw_log_write(LOGFILE_DEBUG, + "%lu [dcb_read_SSL] Read %d bytes from dcb %p in state %s " + "fd %d.", + pthread_self(), + n, + dcb, + STRDCBSTATE(dcb->state), + dcb->fd))); - bufsize = MIN(b, MAX_BUFFER_SIZE); + /*< Append read data to the gwbuf */ + *head = gwbuf_append(*head, buffer); + } + } - if ((buffer = gwbuf_alloc(bufsize)) == NULL) - { - /*< - * This is a fatal error which should cause shutdown. - * Todo shutdown if memory allocation fails. - */ - char errbuf[STRERROR_BUFLEN]; - LOGIF(LE, (skygw_log_write_flush( - LOGFILE_ERROR, - "Error : Failed to allocate read buffer " - "for dcb %p fd %d, due %d, %s.", - dcb, - dcb->fd, - errno, - strerror_r(errno, errbuf, sizeof(errbuf))))); + ss_dassert(gwbuf_length(*head) == nread); + LOGIF(LD, skygw_log_write(LD, "%lu Read a total of %d bytes from dcb %p in state %s fd %d.", + pthread_self(), + nread, + dcb, + STRDCBSTATE(dcb->state), + dcb->fd)); - n = -1; - goto return_n; - } - - n = SSL_read(dcb->ssl, GWBUF_DATA(buffer), bufsize); - dcb->stats.n_reads++; - - if (n < 0) - { - char errbuf[200]; - ssl_errno = SSL_get_error(dcb->ssl,n); -#ifdef SS_DEBUG - if(ssl_errno == SSL_ERROR_SSL || - ssl_errno == SSL_ERROR_SYSCALL) - { - int eno; - while((eno = ERR_get_error()) != 0) - { - ERR_error_string_n(eno,errbuf,200); - skygw_log_write(LE, - "%s", - errbuf); - } - } -#endif - if(ssl_errno == SSL_ERROR_WANT_READ || - ssl_errno == SSL_ERROR_WANT_WRITE || - ssl_errno == SSL_ERROR_NONE) - { - n = 0; - } - else - { - char errbuf[STRERROR_BUFLEN]; - LOGIF(LE, (skygw_log_write_flush( - LOGFILE_ERROR, - "Error : Read failed, dcb %p in state " - "%s fd %d, SSL error %d: %s.", - dcb, - STRDCBSTATE(dcb->state), - dcb->fd, - ssl_errno, - strerror_r(errno, errbuf, sizeof(errbuf))))); - - if(ssl_errno == SSL_ERROR_SSL || - ssl_errno == SSL_ERROR_SYSCALL) - { - while((ssl_errno = ERR_get_error()) != 0) - { - ERR_error_string_n(ssl_errno,errbuf,200); - skygw_log_write(LE, - "%s", - errbuf); - } - } - } - n = -1; - gwbuf_free(buffer); - goto return_n; - } - else if(n == 0) - { - gwbuf_free(buffer); - goto return_n; - } - - buffer = gwbuf_rtrim(buffer,bufsize - n); - if(buffer == NULL) - { - goto return_n; - } -#ifdef SS_DEBUG - skygw_log_write(LD,"%lu SSL: Truncated buffer from %d to %d bytes. " - "Read %d bytes, %d bytes waiting.\n",pthread_self(), - bufsize,GWBUF_LENGTH(buffer),n,b); - - if(GWBUF_LENGTH(buffer) != n){ - skygw_log_sync_all(); - } - - ss_info_dassert((buffer->start <= buffer->end),"Buffer start has passed end."); - ss_info_dassert(GWBUF_LENGTH(buffer) == n,"Buffer size not equal to read bytes."); -#endif - nread += n; - - LOGIF(LD, (skygw_log_write( - LOGFILE_DEBUG, - "%lu [dcb_read_SSL] Read %d bytes from dcb %p in state %s " - "fd %d.", - pthread_self(), - n, - dcb, - STRDCBSTATE(dcb->state), - dcb->fd))); - - /*< Append read data to the gwbuf */ - *head = gwbuf_append(*head, buffer); - } /*< while (true) */ -return_n: - return nread; + return nread; } /** @@ -3143,3 +3041,104 @@ char *name = NULL; } return name; } + +/** + * Check how much data is readable from an SSL enabled DCB. + * @param dcb DCB to check + * @param nread Number of bytes we have already read + * @return Number of bytes readable or -1 on error + */ +int dcb_bytes_readable_SSL (DCB *dcb, int nread) +{ + int rval = 0; + int nbytes; + int rc = ioctl (dcb->fd, FIONREAD, &nbytes); + int pending = SSL_pending (dcb->ssl); + + if (rc == -1) + { + char errbuf[STRERROR_BUFLEN]; + LOGIF (LE, (skygw_log_write_flush (LOGFILE_ERROR, + "Error : ioctl FIONREAD for dcb %p in " + "state %s fd %d failed due error %d, %s.", + dcb, + STRDCBSTATE (dcb->state), + dcb->fd, + errno, + strerror_r (errno, errbuf, sizeof (errbuf))))); + rval = -1; + } + else + { + rval = nbytes + pending; + if (rval == 0 && nread == 0) + { + /** Handle closed client socket */ + if (dcb_isclient (dcb)) + { + char c = 0; + int r = -1; + + /* try to read 1 byte, without consuming the socket buffer */ + r = SSL_peek (dcb->ssl, &c, sizeof (char)); + if (r <= 0) + { + int ssl_errno = SSL_get_error (dcb->ssl, r); + if (ssl_errno != SSL_ERROR_WANT_READ && + ssl_errno != SSL_ERROR_WANT_WRITE && + ssl_errno != SSL_ERROR_NONE) + rval = -1; + } + } + } +#ifdef SS_DEBUG + else if (nbytes != 0 || pending != 0) + { + skygw_log_write_flush (LD, "Total: %d Socket: %d Pending: %d", + nread, nbytes, pending); + } + else + { + skygw_log_write(LD, "Tried to read from socket, no data left. %d bytes read in total.", nread); + } +#endif + } + return rval; +} + +/** + * Log SSL read error messages + * @param dcb DCB from which the SSL_read was attempted + * @param ssl_errno SSL error number + * @param rc Return value of SSL_read + */ +void dcb_log_ssl_read_error(DCB *dcb, int ssl_errno, int rc) +{ + if (ssl_errno != SSL_ERROR_WANT_READ && + ssl_errno != SSL_ERROR_WANT_WRITE && + ssl_errno != SSL_ERROR_NONE) + { + + char errbuf[STRERROR_BUFLEN]; + LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR, + "Error : Read failed, dcb %p in state " + "%s fd %d, SSL error %d: %s.", + dcb, + STRDCBSTATE(dcb->state), + dcb->fd, + ssl_errno, + strerror_r(errno, errbuf, sizeof (errbuf))))); + + if (ssl_errno == SSL_ERROR_SSL || + ssl_errno == SSL_ERROR_SYSCALL) + { + while ((ssl_errno = ERR_get_error()) != 0) + { + ERR_error_string_n(ssl_errno, errbuf, 200); + skygw_log_write(LE, + "%s", + errbuf); + } + } + } +} \ No newline at end of file