aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/ssl_client.h3
-rw-r--r--lib/ssl_gnutls.c6
-rw-r--r--lib/ssl_nss.c6
-rw-r--r--lib/ssl_openssl.c23
-rw-r--r--protocols/jabber/io.c9
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 )