aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWilmer van der Gaast <wilmer@gaast.net>2005-12-16 18:58:00 +0100
committerWilmer van der Gaast <wilmer@gaast.net>2005-12-16 18:58:00 +0100
commit701acdd41542656493d753a75480bc0594ea74b9 (patch)
tree6c744a64385511df327f9fa8c3081d81d18b4770
parentc4168f4cfe553d111941ee385a94facb5449652d (diff)
Non-blocking SSL handshakes for GnuTLS. The rest might come later, but is
slightly less important.
-rw-r--r--protocols/oscar/conn.c4
-rw-r--r--protocols/proxy.c14
-rw-r--r--protocols/ssl_bogus.c2
-rw-r--r--protocols/ssl_client.h6
-rw-r--r--protocols/ssl_gnutls.c81
-rw-r--r--protocols/ssl_nss.c2
-rw-r--r--protocols/ssl_openssl.c2
-rw-r--r--sock.h2
8 files changed, 84 insertions, 29 deletions
diff --git a/protocols/oscar/conn.c b/protocols/oscar/conn.c
index 0155e5bc..77ffd50f 100644
--- a/protocols/oscar/conn.c
+++ b/protocols/oscar/conn.c
@@ -626,9 +626,7 @@ int aim_conn_completeconnect(aim_session_t *sess, aim_conn_t *conn)
return -1;
}
-#ifndef _WIN32
- fcntl(conn->fd, F_SETFL, 0); /* XXX should restore original flags */
-#endif
+ sock_make_blocking(conn->fd);
conn->status &= ~AIM_CONN_STATUS_INPROGRESS;
diff --git a/protocols/proxy.c b/protocols/proxy.c
index 0546f2d7..c658a163 100644
--- a/protocols/proxy.c
+++ b/protocols/proxy.c
@@ -132,8 +132,8 @@ static void gaim_io_connected(gpointer data, gint source, GaimInputCondition con
}
return;
}
- fcntl(source, F_SETFL, 0);
#endif
+ sock_make_blocking(source);
gaim_input_remove(phb->inpa);
if( phb->proxy_func )
phb->proxy_func(phb->proxy_data, source, GAIM_INPUT_READ);
@@ -228,9 +228,7 @@ static void http_canwrite(gpointer data, gint source, GaimInputCondition cond)
g_free(phb);
return;
}
-#ifdef F_SETFL
- fcntl(source, F_SETFL, 0);
-#endif
+ sock_make_blocking(source);
g_snprintf(cmd, sizeof(cmd), "CONNECT %s:%d HTTP/1.1\r\nHost: %s:%d\r\n", phb->host, phb->port,
phb->host, phb->port);
@@ -321,9 +319,7 @@ static void s4_canwrite(gpointer data, gint source, GaimInputCondition cond)
g_free(phb);
return;
}
-#ifdef F_SETFL
- fcntl(source, F_SETFL, 0);
-#endif
+ sock_make_blocking(source);
/* XXX does socks4 not support host name lookups by the proxy? */
if (!(hp = gethostbyname(phb->host))) {
@@ -508,9 +504,7 @@ static void s5_canwrite(gpointer data, gint source, GaimInputCondition cond)
g_free(phb);
return;
}
-#ifdef F_SETFL
- fcntl(source, F_SETFL, 0);
-#endif
+ sock_make_blocking(source);
i = 0;
buf[0] = 0x05; /* SOCKS version 5 */
diff --git a/protocols/ssl_bogus.c b/protocols/ssl_bogus.c
index 226997db..1ee0df4c 100644
--- a/protocols/ssl_bogus.c
+++ b/protocols/ssl_bogus.c
@@ -25,6 +25,8 @@
#include "ssl_client.h"
+int ssl_errno;
+
void *ssl_connect( char *host, int port, SslInputFunction func, gpointer data )
{
return( NULL );
diff --git a/protocols/ssl_client.h b/protocols/ssl_client.h
index a829a7b1..719cd0c4 100644
--- a/protocols/ssl_client.h
+++ b/protocols/ssl_client.h
@@ -26,6 +26,12 @@
#include <glib.h>
#include "proxy.h"
+#define SSL_OK 0
+#define SSL_NOHANDSHAKE 1
+#define SSL_AGAIN 2
+
+extern int ssl_errno;
+
typedef void (*SslInputFunction)(gpointer, void*, GaimInputCondition);
G_MODULE_EXPORT void *ssl_connect( char *host, int port, SslInputFunction func, gpointer data );
diff --git a/protocols/ssl_gnutls.c b/protocols/ssl_gnutls.c
index 535d126e..c2eb6906 100644
--- a/protocols/ssl_gnutls.c
+++ b/protocols/ssl_gnutls.c
@@ -24,11 +24,15 @@
*/
#include <gnutls/gnutls.h>
+#include <fcntl.h>
+#include <unistd.h>
#include "proxy.h"
#include "ssl_client.h"
#include "sock.h"
#include "stdlib.h"
+int ssl_errno = 0;
+
static gboolean initialized = FALSE;
struct scd
@@ -37,6 +41,7 @@ struct scd
gpointer data;
int fd;
gboolean established;
+ int inpa;
gnutls_session session;
gnutls_certificate_credentials xcred;
@@ -45,7 +50,6 @@ struct scd
static void ssl_connected( gpointer data, gint source, GaimInputCondition cond );
-
void *ssl_connect( char *host, int port, SslInputFunction func, gpointer data )
{
struct scd *conn = g_new0( struct scd, 1 );
@@ -53,6 +57,7 @@ void *ssl_connect( char *host, int port, SslInputFunction func, gpointer data )
conn->fd = proxy_connect( host, port, ssl_connected, conn );
conn->func = func;
conn->data = data;
+ conn->inpa = -1;
if( conn->fd < 0 )
{
@@ -75,43 +80,87 @@ void *ssl_connect( char *host, int port, SslInputFunction func, gpointer data )
return( conn );
}
+static void ssl_handshake( gpointer data, gint source, GaimInputCondition cond );
+
static void ssl_connected( gpointer data, gint source, GaimInputCondition cond )
{
struct scd *conn = data;
if( source == -1 )
- goto ssl_connected_failure;
+ {
+ conn->func( conn->data, NULL, cond );
+
+ gnutls_deinit( conn->session );
+ gnutls_certificate_free_credentials( conn->xcred );
+
+ g_free( conn );
+
+ return;
+ }
+ sock_make_nonblocking( conn->fd );
gnutls_transport_set_ptr( conn->session, (gnutls_transport_ptr) conn->fd );
- if( gnutls_handshake( conn->session ) < 0 )
- goto ssl_connected_failure;
-
- conn->established = TRUE;
- conn->func( conn->data, conn, cond );
- return;
+ ssl_handshake( data, source, cond );
+}
+
+static void ssl_handshake( gpointer data, gint source, GaimInputCondition cond )
+{
+ struct scd *conn = data;
+ int st;
-ssl_connected_failure:
- conn->func( conn->data, NULL, cond );
+ if( conn->inpa != -1 )
+ gaim_input_remove( conn->inpa );
- gnutls_deinit( conn->session );
- gnutls_certificate_free_credentials( conn->xcred );
- if( source >= 0 ) closesocket( source );
- g_free( conn );
+ if( ( st = gnutls_handshake( conn->session ) ) < 0 )
+ {
+ if( st == GNUTLS_E_AGAIN || st == GNUTLS_E_INTERRUPTED )
+ {
+ conn->inpa = gaim_input_add( conn->fd,
+ gnutls_record_get_direction( conn->session ) ?
+ GAIM_INPUT_WRITE : GAIM_INPUT_READ,
+ ssl_handshake, data );
+ }
+ else
+ {
+ conn->func( conn->data, NULL, cond );
+
+ gnutls_deinit( conn->session );
+ gnutls_certificate_free_credentials( conn->xcred );
+ closesocket( conn->fd );
+
+ g_free( conn );
+ }
+ }
+ else
+ {
+ /* For now we can't handle non-blocking perfectly everywhere... */
+ sock_make_blocking( conn->fd );
+
+ conn->established = TRUE;
+ conn->func( conn->data, conn, cond );
+ }
}
int ssl_read( void *conn, char *buf, int len )
{
if( !((struct scd*)conn)->established )
- return( 0 );
+ {
+ ssl_errno = SSL_NOHANDSHAKE;
+ return( -1 );
+ }
return( gnutls_record_recv( ((struct scd*)conn)->session, buf, len ) );
+
}
int ssl_write( void *conn, const char *buf, int len )
{
if( !((struct scd*)conn)->established )
- return( 0 );
+ {
+ ssl_errno = SSL_NOHANDSHAKE;
+ return( -1 );
+ }
return( gnutls_record_send( ((struct scd*)conn)->session, buf, len ) );
}
diff --git a/protocols/ssl_nss.c b/protocols/ssl_nss.c
index 7c5f5637..d28983fc 100644
--- a/protocols/ssl_nss.c
+++ b/protocols/ssl_nss.c
@@ -38,6 +38,8 @@
#include <secerr.h>
#include <sslerr.h>
+int ssl_errno = 0;
+
static gboolean initialized = FALSE;
struct scd
diff --git a/protocols/ssl_openssl.c b/protocols/ssl_openssl.c
index d2a7e1fe..bf87ab73 100644
--- a/protocols/ssl_openssl.c
+++ b/protocols/ssl_openssl.c
@@ -34,6 +34,8 @@
#include "ssl_client.h"
#include "sock.h"
+int ssl_errno = 0;
+
static gboolean initialized = FALSE;
struct scd
diff --git a/sock.h b/sock.h
index 3e74bf96..9a9cc223 100644
--- a/sock.h
+++ b/sock.h
@@ -5,6 +5,7 @@
#include <arpa/inet.h>
#include <netdb.h>
#define sock_make_nonblocking(fd) fcntl(fd, F_SETFL, O_NONBLOCK)
+#define sock_make_blocking(fd) fcntl(fd, F_SETFL, 0)
#define sockerr_again() (errno == EINPROGRESS || errno == EINTR)
#define closesocket(a) close(a)
#else
@@ -21,6 +22,7 @@
# define umask _umask
# define mode_t int
# define sock_make_nonblocking(fd) { int non_block = 1; ioctlsocket(fd, FIONBIO, &non_block); }
+# define sock_make_blocking(fd) { int non_block = 0; ioctlsocket(fd, FIONBIO, &non_block); }
# define sockerr_again() (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEINPROGRESS || WSAGetLastError() == WSAEWOULDBLOCK)
# define ETIMEDOUT WSAETIMEDOUT
# define sleep(a) Sleep(a*1000)