diff options
author | Søren Sandmann <sandmann@redhat.com> | 2007-07-30 03:13:13 -0400 |
---|---|---|
committer | Søren Sandmann <sandmann@redhat.com> | 2007-07-30 03:13:13 -0400 |
commit | b97884394fd21858afbce6ef7f7e1720da1995b9 (patch) | |
tree | c7b9c9ccb83d0421ec3401c2fa9c3baeefd3f832 | |
parent | ce041173ae98ce6c3b2e2f149d6974c4f0046277 (diff) |
More TlsConnection
-rw-r--r-- | src/lac.h | 1 | ||||
-rw-r--r-- | src/lacbytequeue.c | 6 | ||||
-rw-r--r-- | src/lacconnection.c | 5 | ||||
-rw-r--r-- | src/lactlsconnection.c | 151 |
4 files changed, 139 insertions, 24 deletions
@@ -190,6 +190,7 @@ LacByteQueue *lac_byte_queue_new (void); gchar *lac_byte_queue_free (LacByteQueue *queue, gboolean free_data); gsize lac_byte_queue_get_length (LacByteQueue *queue); +gboolean lac_byte_queue_is_empty (LacByteQueue *queue); const gchar *lac_byte_queue_peek (LacByteQueue *queue, gsize *n_bytes); gchar *lac_byte_queue_steal (LacByteQueue *queue, diff --git a/src/lacbytequeue.c b/src/lacbytequeue.c index a2e37b6..075f157 100644 --- a/src/lacbytequeue.c +++ b/src/lacbytequeue.c @@ -82,8 +82,8 @@ lac_byte_queue_peek (LacByteQueue *queue, } } -static gboolean -is_empty (LacByteQueue *queue) +gboolean +lac_byte_queue_is_empty (LacByteQueue *queue) { return queue->start == queue->end; } @@ -249,7 +249,7 @@ void lac_byte_queue_transfer_data (LacByteQueue *dest, LacByteQueue *src) { - if (is_empty (dest)) + if (lac_byte_queue_is_empty (dest)) { if (dest->segment) g_free (dest->segment); diff --git a/src/lacconnection.c b/src/lacconnection.c index d96a7f4..3913a5b 100644 --- a/src/lacconnection.c +++ b/src/lacconnection.c @@ -56,7 +56,12 @@ static void event_free (LacConnectionEvent *event) { if (event->type == LAC_CONNECTION_EVENT_READ) + { + /* FIXME: at some point we should support pushing + * data back into the queue, ie., it must be kept alive + */ lac_byte_queue_free (event->read.byte_queue, TRUE); + } else if (event->type == LAC_CONNECTION_EVENT_ERROR) g_error_free ((GError *)event->error.err); diff --git a/src/lactlsconnection.c b/src/lactlsconnection.c index fb1f5a7..0be5d15 100644 --- a/src/lactlsconnection.c +++ b/src/lactlsconnection.c @@ -21,6 +21,8 @@ #include "lac.h" #include <string.h> +#include <gnutls/gnutls.h> +#include <errno.h> struct _LacTlsConnection { @@ -29,6 +31,10 @@ struct _LacTlsConnection gpointer data; LacByteQueue * buffer; + + gnutls_anon_client_credentials_t anoncred; + gnutls_session_t session; + gboolean need_handshake; }; @@ -52,40 +58,143 @@ tcp_callback (LacConnection *connection, if (tls->need_handshake) { - /* if need handshake, attempt handshake */ - /* if successful - * emit handshake - * tls->need_handshake = FALSE - */ + if (gnutls_handshake (tls->session) == 0) + { + tls->need_handshake = FALSE; + /* FIXME: emit handshake event */ + } + } + + if (!tls->need_handshake) + { + LacByteQueue *queue; + gchar *buffer; + gssize n_read; + enum { BUF_SIZE = 8192 }; + GError *err = NULL; + + queue = lac_byte_queue_new (); + + do + { + buffer = lac_byte_queue_alloc_tail (queue, BUF_SIZE); + + n_read = gnutls_record_recv (tls->session, buffer, BUF_SIZE); + + if (n_read < 0) + { + if (n_read != GNUTLS_E_INTERRUPTED && + n_read != GNUTLS_E_AGAIN) + { + err = (GError *)0x01; /* FIXME */ + } + + n_read = 0; + } + + lac_byte_queue_delete_tail (queue, BUF_SIZE - n_read); + } + while (n_read > 0); + + if (!lac_byte_queue_is_empty (queue)) + { + LacConnectionEvent read_event; + gsize n_bytes; + + read_event.type = LAC_CONNECTION_EVENT_READ; + read_event.read.byte_queue = queue; + read_event.read.data = lac_byte_queue_peek (queue, &n_bytes); + read_event.read.len = n_bytes; + + tls->callback (tls, &read_event); + } + + if (err) + { + LacConnectionEvent error_event; + + error_event.type = LAC_CONNECTION_EVENT_ERROR; + error_event.error.err = err; + + tls->callback (tls, &error_event); + + g_error_free (err); + lac_connection_close (tls->tcp_connection); + } + + lac_byte_queue_free (queue, TRUE); } - - /* attempt to read from the tls */ - /* if successful, emit read event */ - break; - - /* Connection closed */ - /* just re-emit */ break; + } +} - /* error */ - /* just re-emit */ - break; +static ssize_t +tls_push (gnutls_transport_ptr_t tptr, + const void *data, + size_t n_bytes) +{ + LacTlsConnection *tls = (LacTlsConnection *)tptr; + + lac_connection_write (tls->tcp_connection, data, n_bytes); + + return n_bytes; +} + +static ssize_t +tls_pull (gnutls_transport_ptr_t tptr, + void *data, + size_t n_bytes) +{ + LacTlsConnection *tls = (LacTlsConnection *)tptr; + const gchar *buf; + gsize n_available; + + buf = lac_byte_queue_peek (tls->buffer, &n_available); + + if (n_available > 0) + { + gsize minimum = n_bytes < n_available? n_bytes : n_available; + + memcpy (data, buf, minimum); + + errno = 0; + + return minimum; + } + else + { + errno = EAGAIN; + + return -1; } } LacTlsConnection * -lac_tls_connection_new (const LacAddress *address, - gint port, - LacTlsConnectionFunc callback, - gpointer data) +lac_tls_connection_new (const LacAddress *address, + gint port, + LacTlsConnectionFunc callback, + gpointer data) { LacTlsConnection *tls = g_new0 (LacTlsConnection, 1); + const int kx_prio[] = { GNUTLS_KX_ANON_DH, 0 }; - tls->tcp_connection = lac_connection_new ( - address, port, tcp_callback, tls); + tls->tcp_connection = lac_connection_new (address, port, tcp_callback, tls); tls->need_handshake = TRUE; tls->callback = callback; tls->data = data; + gnutls_global_init (); + gnutls_anon_allocate_client_credentials (&tls->anoncred); + gnutls_init (&tls->session, GNUTLS_CLIENT); + gnutls_set_default_priority (tls->session); + gnutls_kx_set_priority (tls->session, kx_prio); + gnutls_credentials_set (tls->session, + GNUTLS_CRD_ANON, &tls->anoncred); + + gnutls_transport_set_ptr (tls->session, (gnutls_transport_ptr_t)tls); + gnutls_transport_set_push_function (tls->session, tls_push); + gnutls_transport_set_pull_function (tls->session, tls_pull); + + return tls; } |