diff options
-rw-r--r-- | lib/ssl_client.h | 3 | ||||
-rw-r--r-- | lib/ssl_gnutls.c | 6 | ||||
-rw-r--r-- | lib/ssl_nss.c | 6 | ||||
-rw-r--r-- | lib/ssl_openssl.c | 23 | ||||
-rw-r--r-- | protocols/jabber/io.c | 9 |
5 files changed, 41 insertions, 6 deletions
diff --git a/lib/ssl_client.h b/lib/ssl_client.h index dcbf9a01..f91d0d70 100644 --- a/lib/ssl_client.h +++ b/lib/ssl_client.h @@ -59,6 +59,9 @@ G_MODULE_EXPORT void *ssl_starttls( int fd, ssl_input_function func, gpointer da G_MODULE_EXPORT int ssl_read( void *conn, char *buf, int len ); G_MODULE_EXPORT int ssl_write( void *conn, const char *buf, int len ); +/* See ssl_openssl.c for an explanation. */ +G_MODULE_EXPORT int ssl_pending( void *conn ); + /* Abort the SSL connection and disconnect the socket. Do not use close() directly, both the SSL library and the peer will be unhappy! */ G_MODULE_EXPORT void ssl_disconnect( void *conn_ ); diff --git a/lib/ssl_gnutls.c b/lib/ssl_gnutls.c index b964ab49..f5945442 100644 --- a/lib/ssl_gnutls.c +++ b/lib/ssl_gnutls.c @@ -210,6 +210,12 @@ int ssl_write( void *conn, const char *buf, int len ) return st; } +/* See ssl_openssl.c for an explanation. */ +int ssl_pending( void *conn ) +{ + return 0; +} + void ssl_disconnect( void *conn_ ) { struct scd *conn = conn_; diff --git a/lib/ssl_nss.c b/lib/ssl_nss.c index 218b3a80..eba3c441 100644 --- a/lib/ssl_nss.c +++ b/lib/ssl_nss.c @@ -168,6 +168,12 @@ int ssl_write( void *conn, const char *buf, int len ) return( PR_Write ( ((struct scd*)conn)->prfd, buf, len ) ); } +/* See ssl_openssl.c for an explanation. */ +int ssl_pending( void *conn ) +{ + return 0; +} + void ssl_disconnect( void *conn_ ) { struct scd *conn = conn_; diff --git a/lib/ssl_openssl.c b/lib/ssl_openssl.c index b1ba1db9..fc6d433e 100644 --- a/lib/ssl_openssl.c +++ b/lib/ssl_openssl.c @@ -61,16 +61,16 @@ void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data struct scd *conn = g_new0( struct scd, 1 ); conn->fd = proxy_connect( host, port, ssl_connected, conn ); - conn->func = func; - conn->data = data; - conn->inpa = -1; - if( conn->fd < 0 ) { g_free( conn ); return NULL; } + conn->func = func; + conn->data = data; + conn->inpa = -1; + return conn; } @@ -230,6 +230,21 @@ int ssl_write( void *conn, const char *buf, int len ) return st; } +/* Only OpenSSL *really* needs this (and well, maybe NSS). See for more info: + http://www.gnu.org/software/gnutls/manual/gnutls.html#index-gnutls_005frecord_005fcheck_005fpending-209 + http://www.openssl.org/docs/ssl/SSL_pending.html + + Required because OpenSSL empties the TCP buffer completely but doesn't + necessarily give us all the unencrypted data. + + Returns 0 if there's nothing left or if we don't have to care (GnuTLS), + 1 if there's more data. */ +int ssl_pending( void *conn ) +{ + return ( ((struct scd*)conn) && ((struct scd*)conn)->established ) ? + SSL_pending( ((struct scd*)conn)->ssl ) > 0 : 0; +} + void ssl_disconnect( void *conn_ ) { struct scd *conn = conn_; diff --git a/protocols/jabber/io.c b/protocols/jabber/io.c index 9980dc8e..10efad37 100644 --- a/protocols/jabber/io.c +++ b/protocols/jabber/io.c @@ -240,8 +240,13 @@ static gboolean jabber_read_callback( gpointer data, gint fd, b_input_condition return FALSE; } - /* EAGAIN/etc or a successful read. */ - return TRUE; + if( ssl_pending( jd->ssl ) ) + /* OpenSSL empties the TCP buffers completely but may keep some + data in its internap buffers. select() won't see that, but + ssl_pending() does. */ + return jabber_read_callback( data, fd, cond ); + else + return TRUE; } gboolean jabber_connected_plain( gpointer data, gint source, b_input_condition cond ) |