summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsandmann <sandmann>2007-01-12 04:58:47 +0000
committersandmann <sandmann>2007-01-12 04:58:47 +0000
commit81d6c3f502b896123a28e1daa4a891b69e8e1e71 (patch)
treed88710ece378c079ba86257ebc575c11cdfee0a7
parent629038b8dbafaaa92478b78694da32789050c3c5 (diff)
*** empty log message ***
-rwxr-xr-xconfigure.in12
-rw-r--r--src/Makefile.am4
-rw-r--r--src/lac.h111
-rw-r--r--src/lacbytequeue.c230
-rw-r--r--src/lacconnection.c294
-rw-r--r--src/lacdebug.c3
-rw-r--r--src/lachttp.c4
-rw-r--r--src/lacinternals.h25
-rw-r--r--src/lacprimitives.c225
-rw-r--r--src/lactls.c267
10 files changed, 711 insertions, 464 deletions
diff --git a/configure.in b/configure.in
index f523151..c52175d 100755
--- a/configure.in
+++ b/configure.in
@@ -38,7 +38,7 @@ if test "x$GCC" = "xyes"; then
fi
#LIBS="$LIBS `glib-config --libs`"
-CFLAGS="$CFLAGS -D_REENTRANT"
+#CFLAGS="$CFLAGS -D_REENTRANT"
AC_CHECK_FUNC(connect,,AC_CHECK_LIB(socket, connect))
AC_CHECK_FUNC(inet_aton,,AC_CHECK_LIB(resolv, inet_aton))
@@ -140,12 +140,10 @@ AC_CHECK_FUNC(gethostbyname_r,
])
dnl Checks for libraries.
-AM_PATH_GLIB_2_0(2.0.0,
- [LIBS="$LIBS $GLIB_LIBS" CFLAGS="$CFLAGS $GLIB_CFLAGS"],
- AC_MSG_ERROR([
-*** GLIB 1.3.1 or better is required. The latest version of GLIB
-*** is always available from ftp://ftp.gtk.org/.]),
-)
+PKG_CHECK_MODULES(DEP, glib-2.0 gnutls >= 1.4)
+
+LIBS="$LIBS $DEP_LIBS"
+CFLAGS="$CFLAGS $DEP_CFLAGS"
dnl Checks for header files.
AC_HEADER_STDC
diff --git a/src/Makefile.am b/src/Makefile.am
index 5364b72..3307a06 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -8,19 +8,19 @@ lacinclude_HEADERS= \
lac.h
liblac_1_la_SOURCES = \
+ lacaddress.c \
lacprimitives.c \
lacwatch.c \
+ lacbytequeue.c \
lacdebug.c \
lacdns-config.c \
lacdns-query.c \
lacdns-messages.c \
lacdns-cache.c \
lacdns-nameserver.c \
- lacaddress.c \
lacuri.c \
lacconnection.c \
lachttp.c \
- lactls.c \
\
lacinternals.h \
lacdns-messages.h \
diff --git a/src/lac.h b/src/lac.h
index 4f96105..00f436d 100644
--- a/src/lac.h
+++ b/src/lac.h
@@ -1,7 +1,8 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- */
/* Lac - Library for asynchronous communication
- * Copyright (C) 2000, 2001, 2002, 2003 Søren Sandmann (sandmann@daimi.au.dk)
+ * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+ * Søren Sandmann (sandmann@daimi.au.dk)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -110,10 +111,10 @@ typedef enum
LAC_SOCKET_ERROR_NET_UNREACHABLE,
LAC_SOCKET_ERROR_TIMEOUT,
LAC_SOCKET_ERROR_CONNECTION_RESET,
-
+
LAC_SOCKET_ERROR_NO_RESOURCES,
LAC_SOCKET_ERROR_AGAIN, /* also known as WOULDBLOCK */
-
+
LAC_SOCKET_ERROR_FAILED
} LacError;
@@ -182,6 +183,58 @@ gboolean lac_getpeername (gint fd,
GError **err);
gchar * lac_gethostname (void);
+/* LacByteQueue */
+typedef struct LacByteQueue LacByteQueue;
+
+LacByteQueue *lac_byte_queue_new (void);
+guint8 *lac_byte_queue_free (LacByteQueue *queue,
+ gboolean free_data);
+gsize lac_byte_queue_get_length (LacByteQueue *queue);
+const guint8 *lac_byte_queue_get_data (LacByteQueue *queue,
+ gsize *n_bytes);
+void lac_byte_queue_put_back (LacByteQueue *queue,
+ const guint8 *bytes,
+ gsize n_bytes);
+void lac_byte_queue_append (LacByteQueue *queue,
+ const guint8 *bytes,
+ gsize n_bytes);
+guint8 *lac_byte_queue_alloc_tail (LacByteQueue *queue,
+ gsize size);
+void lac_byte_queue_delete_tail (LacByteQueue *queue,
+ gsize size);
+void lac_byte_queue_steal_data (LacByteQueue *dest,
+ LacByteQueue *src);
+
+
+/* TLS */
+typedef struct LacTLS LacTLS;
+
+typedef int (* LacTLSSendFunc) (LacTLS *tls,
+ const guint8 *data,
+ gsize len,
+ GError **err);
+typedef int (* LacTLSRecvFunc) (LacTLS *tls,
+ guint8 *data,
+ gsize buf_size,
+ GError **err);
+LacTLS *lac_tls_new (int fd);
+LacTLS *lac_tls_new2 (LacTLSSendFunc send_func,
+ LacTLSRecvFunc recv_func,
+ gpointer data);
+gpointer lac_tls_get_data (LacTLS *tls);
+gboolean lac_tls_handshake (LacTLS *tls,
+ GError **err);
+gint lac_tls_recv (LacTLS *tls,
+ gchar *buf,
+ guint len,
+ GError **err);
+gint lac_tls_send (LacTLS *tls,
+ gchar *buf,
+ guint len,
+ GError **err);
+gboolean lac_tls_needs_write (LacTLS *tls);
+void lac_tls_free (LacTLS *tls);
+
/*
* Watching file descriptors
@@ -203,35 +256,6 @@ void lac_fd_set_priority_callback (gint fd,
void lac_fd_remove_watch (gint fd);
gboolean lac_fd_is_watched (gint fd);
-
-/*
- * TLS
- */
-typedef struct LacTLS LacTLS;
-
-LacTLS * lac_tls_new (GError **err);
-void lac_tls_connect (LacTLS *tls);
-void lac_tls_set_read_callback (LacTLS *tls,
- LacWatchCallback read_cb);
-void lac_tls_set_write_callback (LacTLS *tls,
- LacWatchCallback write_cb);
-void lac_tls_set_hangup_callback (LacTLS *tls,
- LacWatchCallback hangup_cb);
-void lac_tls_set_error_callback (LacTLS *tls,
- LacWatchCallback error_cb);
-void lac_tls_set_priority_callback (LacTLS *tls,
- LacWatchCallback priority_cb);
-int lac_tls_send (LacTLS *tls,
- char *msg,
- guint len,
- GError **err);
-int lac_tls_recv (LacTLS *tls,
- char *buf,
- guint size,
- GError **err);
-gboolean lac_tls_free (LacTLS *tls,
- GError **err);
-
/*
* Connection
*/
@@ -342,7 +366,7 @@ struct _LacUri {
} ftp;
} u;
gchar *fragment;
-
+
guint checksum; /* used internally */
};
@@ -477,29 +501,8 @@ union _LacHttpEvent {
LacHttpErrorEvent error;
};
-
-/*
- * Debug spew
- */
-#define lac_debug_out(format,args...) G_STMT_START{ \
- char *lac_debug_temp_pointer; \
- if (lac_is_verbose()) \
- { \
- lac_debug_temp_pointer = g_strdup_printf (format, args); \
- g_log ("lac-debug", \
- G_LOG_LEVEL_MESSAGE, \
- "file %s: line %d (%s): %s", \
- __FILE__, \
- __LINE__, \
- __PRETTY_FUNCTION__, \
- lac_debug_temp_pointer); \
- g_free (lac_debug_temp_pointer); \
- } \
-} G_STMT_END
-
/* make LAC write lots of spam to stdout */
void lac_set_verbose (gboolean verbose);
-gboolean lac_is_verbose (void);
#define lac_debug_checkpoint() lac_debug_out ("reached%s", "")
diff --git a/src/lacbytequeue.c b/src/lacbytequeue.c
index b8965db..16eaa6a 100644
--- a/src/lacbytequeue.c
+++ b/src/lacbytequeue.c
@@ -1,91 +1,215 @@
-struct _LacByteQueue
-{
- guint allocated;
-
- guint8 * data;
- guint8 * head;
- guint8 * tail;
-};
+#include <string.h>
+#include "lac.h"
-enum {
- INITIAL_SIZE = 256
+struct LacByteQueue
+{
+ gsize segment_size;
+ guint8 * segment;
+ guint8 * start;
+ guint8 * end;
};
LacByteQueue *
lac_byte_queue_new (void)
{
- LacByteQueue *byte_queue = g_new (LacByteQueue, 1);
-
- byte_queue->allocated = INITIAL_SIZE;
-
- byte_queue->data = g_new (guint8, INITIAL_SIZE);
- byte_queue->head = byte_queue->data;
- byte_queue->tail = byte_queue->data;
+ LacByteQueue *queue = g_new0 (LacByteQueue, 1);
+
+ queue->segment_size = 0;
+ queue->segment = NULL;
+ queue->start = NULL;
+ queue->end = NULL;
+
+ return queue;
+}
- return byte_queue;
+guint8 *
+lac_byte_queue_free (LacByteQueue *queue,
+ gboolean free_data)
+{
+ guint8 *result;
+
+ if (free_data)
+ {
+ g_free (queue->segment);
+
+ result = NULL;
+ }
+ else
+ {
+ memmove (queue->segment, queue->start, queue->end - queue->start);
+
+ result = queue->segment;
+ }
+
+ g_free (queue);
+
+ return result;
}
-guint
-lac_byte_queue_get_length (LacByteQueue *byte_queue)
+/* The data returned is owned by the byte queue and becomes invalid
+ * as soon as any method is called on the queue. It is explicitly
+ * allowed to push the returned data back into the queue, and indeed
+ * in that case the queue will avoid copying if it can. The push
+ * must be the first method called on the queue after the read.
+ */
+const guint8 *
+lac_byte_queue_get_data (LacByteQueue *queue,
+ gsize *n_bytes)
{
- return byte_queue->tail - byte_queue->head;
+ guint8 *result;
+
+ if (n_bytes)
+ *n_bytes = queue->end - queue->start;
+
+ result = queue->start;
+
+ queue->start = queue->segment;
+ queue->end = queue->segment;
+
+ return result;
}
-static guint
-lac_byte_queue_get_capacity (LacByteQueue *byte_queue)
+static gboolean
+in_segment (LacByteQueue *queue,
+ const guint8 *bytes,
+ gsize n_bytes)
{
- return byte_queue->allocated - lac_byte_queue_get_length (byte_queue);
+ return bytes >= queue->segment && bytes + n_bytes < queue->end;
}
-static guint
-power_of_two_bigger_than (guint n)
+static gboolean
+is_empty (LacByteQueue *queue)
{
- guint result = 1;
+ return queue->start == queue->end;
+}
+static gsize
+power_of_two_bigger_than (gsize n)
+{
+ gsize result = 1;
+
while (result <= n)
result *= 2;
-
+
return result;
}
static void
-lac_byte_queue_ensure_capacity (LacByteQueue *byte_queue, guint needed)
+ensure_room (LacByteQueue *queue,
+ gsize extra)
{
- guint new_size;
+ gsize old_data_size = queue->end - queue->start;
+ gsize new_data_size = old_data_size + extra;
- if (needed <= lac_byte_queue_get_capacity (byte_queue))
- return;
+ if (queue->end + new_data_size > queue->segment + queue->segment_size)
+ {
+ gsize new_segment_size = power_of_two_bigger_than (2 * new_data_size);
+
+ memmove (queue->start, queue->segment, old_data_size);
+
+ if (new_segment_size > queue->segment_size)
+ {
+ queue->segment_size = new_segment_size;
+ queue->segment = g_realloc (queue->segment, new_segment_size);
+ }
+
+ queue->start = queue->segment;
+ queue->end = queue->start + new_data_size;
+ }
+}
- new_size = power_of_two_bigger_than (needed);
+/* This function appends uninitialized data of length @size
+ * to the queue, then returns a pointer to the added data.
+ * The intention is that the app can read() into this
+ * memory, then use lac_byte_queue_pop_tail() to delete the
+ * area that wasn't read into. Example
+ *
+ * guint8 *area = lac_byte_queue_alloc_tail (queue, 8192);
+ *
+ * n_read = read (fd, area, 8192);
+ *
+ * lac_byte_queue_delete_tail (queue, 8192 - (n_read < 0)? 0 : n_read);
+ *
+ * if (n_read < 0)
+ * {
+ * lac_byte_queue_delete_tail (queue, 8192);
+ * handle_error();
+ * n_read = 0;
+ * }
+ * else
+ * {
+ * lac_byte_queue_delete_tail (8192 - n_read);
+ *
+ * // enjoy the new data in the queue
+ * }
+ */
+guint8 *
+lac_byte_queue_alloc_tail (LacByteQueue *queue,
+ gsize size)
+{
+ ensure_room (queue, size);
+
+ queue->end += size;
+
+ return queue->end - size;
}
void
-lac_byte_queue_append (LacByteQueue *byte_queue, guint8 *data, guint length)
+lac_byte_queue_delete_tail (LacByteQueue *queue,
+ gsize size)
{
- guint needed_capacity = lac_byte_queue_get_length (byte_queue) + length;
-
- lac_byte_queue_ensure_capacity (byte_queue, needed_capacity);
+ if (queue->end - queue->start < size)
+ queue->end = queue->start;
+ else
+ queue->end -= size;
+}
- if (byte_queue->head >= byte_queue->tail)
+void
+lac_byte_queue_append (LacByteQueue *queue,
+ const guint8 *bytes,
+ gsize n_bytes)
+{
+ if (in_segment (queue, bytes, n_bytes) && is_empty (queue))
{
- guint bytes_to_copy = MIN (
- byte_queue->data + byte_queue->allocated - byte_queue->head,
- length);
-
- memcpy (byte_queue->head, data, bytes_to_copy);
-
- byte_queue->head += bytes_to_copy;
- length -= bytes_to_copy;
- data += bytes_to_copy;
+ queue->start = (guint8 *)bytes;
+ queue->end = (guint8 *)bytes + n_bytes;
+ }
+ else
+ {
+ guint8 *tail = lac_byte_queue_alloc_tail (queue, n_bytes);
- if (byte_queue->head == byte_queue->data + byte_queue->allocated)
- byte_queue->head = byte_queue->data;
+ memcpy (tail, bytes, n_bytes);
}
+}
- if (length > 0)
+/* Transfer data from @src to @dest, if possible without copying.
+ * The data is appended to @dest's data if @dest is not empty
+ */
+void
+lac_byte_queue_steal_data (LacByteQueue *dest,
+ LacByteQueue *src)
+{
+ if (is_empty (dest))
{
- memcpy (byte_queue->head, data, length);
-
- byte_queue->head += length;
+ if (dest->segment)
+ g_free (dest->segment);
+
+ dest->segment_size = src->segment_size;
+ dest->segment = src->segment;
+ dest->start = src->start;
+ dest->end = src->end;
+
+ src->segment_size = 0;
+ src->segment = NULL;
+ src->start = NULL;
+ src->end = NULL;
+ }
+ else
+ {
+ const guint8 *data;
+ gsize size;
+
+ data = lac_byte_queue_get_data (src, &size);
+ lac_byte_queue_append (dest, data, size);
}
}
diff --git a/src/lacconnection.c b/src/lacconnection.c
index 8ec0a6a..d65c5a5 100644
--- a/src/lacconnection.c
+++ b/src/lacconnection.c
@@ -40,10 +40,12 @@ static gint socket_send (Socket *socket,
guint len,
GError **err);
static gint socket_recv (Socket *socket,
- gchar *buf,
+ guint8 *buf,
guint size,
GError **err);
+#if 0
static int socket_get_fd (Socket *socket);
+#endif
static void socket_flush (Socket *socket);
static gboolean socket_shutdown (Socket *socket,
LacShutdownMethod how,
@@ -53,7 +55,13 @@ static gboolean socket_set_blocking (Socket *socket,
GError **err);
static gboolean socket_close (Socket *socket,
GError **err);
-
+static void socket_add_watch (Socket *socket,
+ gpointer data);
+static void socket_remove_watch (Socket *socket);
+static void socket_set_read_cb (Socket *socket,
+ LacWatchCallback read_cb);
+static void socket_set_write_cb (Socket *socket,
+ LacWatchCallback write_cb);
typedef enum {
@@ -160,7 +168,7 @@ emit_events (LacConnection *connection)
if (connection->has_fd)
{
- lac_fd_remove_watch (socket_get_fd (connection->socket));
+ socket_remove_watch (connection->socket);
socket_close (connection->socket, NULL);
connection->has_fd = FALSE;
}
@@ -244,8 +252,7 @@ lac_connection_do_writes (LacConnection *connection)
{
if (connection->state != CONNECTED)
{
- lac_fd_set_write_callback (
- socket_get_fd (connection->socket), lac_connection_writable);
+ socket_set_write_cb (connection->socket, lac_connection_writable);
return;
}
@@ -262,9 +269,8 @@ lac_connection_do_writes (LacConnection *connection)
if (g_error_matches (
err, LAC_SOCKET_ERROR, LAC_SOCKET_ERROR_AGAIN))
{
- lac_fd_set_write_callback (
- socket_get_fd (connection->socket),
- lac_connection_writable);
+ socket_set_write_cb (
+ connection->socket, lac_connection_writable);
}
else
{
@@ -279,15 +285,11 @@ lac_connection_do_writes (LacConnection *connection)
/* FIXME check that we haven't used too much time? */
}
-
- lac_fd_set_write_callback (socket_get_fd (connection->socket), NULL);
+
+ socket_set_write_cb (connection->socket, NULL);
if (connection->need_flush)
{
- /* Turn Nagle off, then on, to make the kernel send everything it
- * has queued up.
- */
-
socket_flush (connection->socket);
connection->need_flush = FALSE;
@@ -376,14 +378,10 @@ lac_connection_discard_pending_events (LacConnection *connection)
static void
lac_connection_add_watch (LacConnection *connection)
{
- int fd = socket_get_fd (connection->socket);
-
- lac_fd_add_watch (fd, connection);
+ socket_add_watch (connection->socket, connection);
- lac_fd_set_read_callback (fd, lac_connection_readable);
- lac_fd_set_hangup_callback (fd, lac_connection_readable);
- lac_fd_set_error_callback (fd, lac_connection_readable);
- lac_fd_set_write_callback (fd, lac_connection_writable);
+ socket_set_read_cb (connection->socket, lac_connection_readable);
+ socket_set_write_cb (connection->socket, lac_connection_writable);
}
LacConnection *
@@ -471,7 +469,7 @@ lac_connection_write (LacConnection *connection,
do_writes = (connection->unwritten->len == 0);
- g_string_append_len (connection->unwritten, data, len);
+ g_string_append_len (connection->unwritten, (gchar *)data, len);
if (do_writes)
{
@@ -479,6 +477,7 @@ lac_connection_write (LacConnection *connection,
emit_events (connection);
}
}
+
void
lac_connection_write_cstr (LacConnection *connection,
const gchar *data)
@@ -539,7 +538,7 @@ lac_connection_unref (LacConnection *connection)
if (connection->has_fd)
{
- lac_fd_remove_watch (socket_get_fd (connection->socket));
+ socket_remove_watch (connection->socket);
socket_close (connection->socket, NULL);
}
@@ -580,7 +579,25 @@ lac_connection_flush (LacConnection *connection)
*/
struct Socket
{
- int fd;
+ gboolean ssl;
+
+ union
+ {
+ struct
+ {
+ int fd;
+ } tcp;
+
+ struct
+ {
+ int fd;
+ LacTLS *tls;
+ gboolean override;
+ gpointer data;
+ LacWatchCallback read_cb;
+ LacWatchCallback write_cb;
+ } ssl;
+ } u;
};
static Socket *
@@ -595,7 +612,29 @@ socket_new_tcp (GError **err)
return NULL;
socket = g_new0 (Socket, 1);
- socket->fd = fd;
+ socket->u.ssl.tls = FALSE;
+ socket->u.ssl.fd = fd;
+ socket->u.ssl.override = FALSE;
+ socket->u.ssl.read_cb = NULL;
+ socket->u.ssl.write_cb = NULL;
+
+ return socket;
+}
+
+static Socket *
+socket_new_ssl (GError **err)
+{
+ Socket *socket;
+ int fd;
+
+ fd = lac_socket_tcp (err);
+ if (fd < 0)
+ return NULL;
+
+ socket = g_new0 (Socket, 1);
+ socket->ssl = TRUE;
+ socket->u.ssl.fd = fd;
+ socket->u.ssl.tls = NULL; // lac_tls
return socket;
}
@@ -606,7 +645,15 @@ socket_connect (Socket *socket,
gint port,
GError **err)
{
- return lac_connect (socket->fd, address, port, err);
+ if (socket->ssl)
+ {
+ lac_connect (socket->u.ssl.fd, address, port, err);
+
+ }
+ else
+ {
+ return lac_connect (socket->u.tcp.fd, address, port, err);
+ }
}
static gboolean
@@ -618,42 +665,129 @@ socket_is_connected (Socket *socket)
return TRUE;
}
-static gint
-socket_send (Socket *socket,
- const gchar *msg,
- guint len,
- GError **err)
+static void
+set_normal_callbacks (Socket *socket)
+{
+ g_assert (socket->ssl);
+
+ lac_fd_set_read_callback (socket->u.ssl.fd, socket->u.ssl.read_cb);
+ lac_fd_set_write_callback (socket->u.ssl.fd, socket->u.ssl.write_cb);
+
+ socket->u.ssl.override = FALSE;
+}
+
+static void
+override_readable (gpointer data)
+{
+ Socket *socket = data;
+
+ if (socket->u.ssl.read_cb)
+ socket->u.ssl.read_cb (socket->u.ssl.data);
+
+ set_normal_callbacks (socket);
+}
+
+static void
+override_writable (gpointer data)
+{
+ Socket *socket = data;
+
+ if (socket->u.ssl.write_cb)
+ socket->u.ssl.write_cb (socket->u.ssl.data);
+
+ set_normal_callbacks (socket);
+}
+
+static void
+override_callbacks (Socket *socket,
+ LacWatchCallback func)
{
- return lac_send (socket->fd, msg, len, err);
+ gboolean needs_write;
+
+ g_assert (socket->ssl);
+
+ needs_write = lactls_needs_write (socket->u.ssl.tls);
+
+ lac_fd_set_write_callback (socket->u.ssl.fd, needs_write? func : NULL);
+ lac_fd_set_read_callback (socket->u.ssl.fd, needs_write? NULL : func);
+
+#if 0
+ socket->u.ssl.overridden = TRUE;
+#endif
}
static gint
-socket_recv (Socket *socket,
- gchar *buf,
- guint size,
- GError **err)
+socket_send (Socket *socket,
+ const gchar *msg,
+ guint len,
+ GError **err)
{
- return lac_recv (socket->fd, buf, size, err);
+ if (socket->ssl)
+ {
+ GError *err = NULL;
+
+#if 0
+ lac_tls_send (socket->u.ssl.tls, msg, len, &err);
+#endif
+
+ if (err)
+ {
+#if 0
+ if (AGAIN)
+ override_callbacks (socket, override_writable);
+#endif
+ }
+ }
+ else
+ {
+ return lac_send (socket->u.tcp.fd, msg, len, err);
+ }
}
-static int
-socket_get_fd (Socket *socket)
+static gint
+socket_recv (Socket *socket,
+ guint8 *buf,
+ guint size,
+ GError **err)
{
- return socket->fd;
+ if (socket->ssl)
+ {
+ }
+ else
+ {
+ return lac_recv (socket->u.tcp.fd, (gchar *)buf, size, err);
+ }
}
static gboolean
socket_close (Socket *socket,
GError **err)
{
- return lac_close (socket->fd, err);
+ if (socket->ssl)
+ {
+ }
+ else
+ {
+ return lac_close (socket->u.tcp.fd, err);
+ }
}
static void
socket_flush (Socket *socket)
{
- lac_set_nagle (socket->fd, FALSE, NULL);
- lac_set_nagle (socket->fd, TRUE, NULL);
+ if (socket->ssl)
+ {
+ }
+ else
+ {
+ /* Turn Nagle off, then on, to make the kernel send everything it
+ * has queued up.
+ */
+
+ lac_set_nagle (socket->u.tcp.fd, FALSE, NULL);
+ lac_set_nagle (socket->u.tcp.fd, TRUE, NULL);
+ }
+
}
static gboolean
@@ -661,7 +795,13 @@ socket_set_blocking (Socket *socket,
gboolean blocking,
GError **err)
{
- return lac_set_blocking (socket->fd, blocking, err);
+ if (socket->ssl)
+ {
+ }
+ else
+ {
+ return lac_set_blocking (socket->u.tcp.fd, blocking, err);
+ }
}
static gboolean
@@ -669,5 +809,69 @@ socket_shutdown (Socket *socket,
LacShutdownMethod how,
GError **err)
{
- return lac_shutdown (socket->fd, how, err);
+ if (socket->ssl)
+ {
+ }
+ else
+ {
+ return lac_shutdown (socket->u.tcp.fd, how, err);
+ }
+}
+
+static void
+socket_add_watch (Socket *socket,
+ gpointer data)
+{
+ if (socket->ssl)
+ {
+ socket->u.ssl.data = data;
+ lac_fd_add_watch (socket->u.ssl.fd, data);
+ }
+ else
+ {
+ lac_fd_add_watch (socket->u.tcp.fd, data);
+ }
+}
+
+static void
+socket_remove_watch (Socket *socket)
+{
+ if (socket->ssl)
+ {
+ socket->u.ssl.data = NULL;
+ lac_fd_remove_watch (socket->u.ssl.fd);
+ }
+ else
+ {
+ lac_fd_remove_watch (socket->u.tcp.fd);
+ }
+}
+
+static void
+socket_set_read_cb (Socket *socket,
+ LacWatchCallback read_cb)
+{
+ if (socket->ssl)
+ {
+ }
+ else
+ {
+ lac_fd_set_read_callback (socket->u.tcp.fd, read_cb);
+ lac_fd_set_hangup_callback (socket->u.tcp.fd, read_cb);
+ lac_fd_set_error_callback (socket->u.tcp.fd, read_cb);
+ lac_fd_set_write_callback (socket->u.tcp.fd, read_cb);
+ }
+}
+
+static void
+socket_set_write_cb (Socket *socket,
+ LacWatchCallback write_cb)
+{
+ if (socket->ssl)
+ {
+ }
+ else
+ {
+ lac_fd_set_write_callback (socket->u.tcp.fd, write_cb);
+ }
}
diff --git a/src/lacdebug.c b/src/lacdebug.c
index 94ce8b0..0bd87cf 100644
--- a/src/lacdebug.c
+++ b/src/lacdebug.c
@@ -1,7 +1,7 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- */
/* Lac - Library for asynchronous communication
- * Copyright (C) 2000, 2001 Søren Sandmann
+ * Copyright (C) 2000, 2001, 2007 Søren Sandmann
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -20,6 +20,7 @@
*/
#include "lac.h"
+#include "lacinternals.h"
static gboolean lac_verbose = FALSE;
diff --git a/src/lachttp.c b/src/lachttp.c
index ede15ec..60f10c3 100644
--- a/src/lachttp.c
+++ b/src/lachttp.c
@@ -1928,7 +1928,9 @@ server_choked_on_pipeline (HttpTransport *transport, guint recover_time)
* giving up on pipelining completely)
*
* The alternative: report back to the user that the data
- * he already received was useless, is not nice.
+ * he already received was useless, is not nice. FIXME:
+ * hmm, why not? Just tell the application that the request
+ * failed and it should retry. Seems a lot simpler to me ...
*/
LacHttpRequest *request = transport->current;
gsize n_bytes;
diff --git a/src/lacinternals.h b/src/lacinternals.h
index 52fea0b..6953391 100644
--- a/src/lacinternals.h
+++ b/src/lacinternals.h
@@ -1,7 +1,7 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- */
/* Lac - Library for asynchronous communication
- * Copyright (C) 2002 Søren Sandmann (sandmann@daimi.au.dk)
+ * Copyright (C) 2002, 2007 Søren Sandmann (sandmann@daimi.au.dk)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -49,4 +49,27 @@ void lac_address_get_in_addr (const LacAddress *addr,
struct in_addr *in_addr);
void lac_address_set_in_addr (LacAddress *addr,
struct in_addr *in_addr);
+
+
+/*
+ * Debug spew
+ */
+#define lac_debug_out(format,args...) G_STMT_START{ \
+ char *lac_debug_temp_pointer; \
+ if (lac_is_verbose()) \
+ { \
+ lac_debug_temp_pointer = g_strdup_printf (format, args); \
+ g_log ("lac-debug", \
+ G_LOG_LEVEL_MESSAGE, \
+ "file %s: line %d (%s): %s", \
+ __FILE__, \
+ __LINE__, \
+ __PRETTY_FUNCTION__, \
+ lac_debug_temp_pointer); \
+ g_free (lac_debug_temp_pointer); \
+ } \
+ } G_STMT_END
+
+gboolean lac_is_verbose (void);
+
#endif /* LAC_INTERNALS_H */
diff --git a/src/lacprimitives.c b/src/lacprimitives.c
index d75b2ae..4ffb122 100644
--- a/src/lacprimitives.c
+++ b/src/lacprimitives.c
@@ -67,9 +67,15 @@ extern gint h_errno;
#include "lacinternals.h"
-static void lac_set_error_from_errno (GError **err,
- gint eno,
- const gchar *msg);
+#include <gnutls/gnutls.h>
+
+static void set_error_from_errno (GError **err,
+ gint eno,
+ const gchar *msg);
+static void set_error_from_gnutls_error (GError **err,
+ int gnutls_err,
+ const gchar *msg);
+
GQuark
lac_socket_error_quark (void)
@@ -151,7 +157,7 @@ lac_socket_tcp (GError **err)
if (fd < 0)
{
- lac_set_error_from_errno (err, errno, "socket() failed %s");
+ set_error_from_errno (err, errno, "socket() failed %s");
return -1;
}
@@ -174,7 +180,7 @@ lac_socket_udp (GError **err)
if (fd < 0)
{
- lac_set_error_from_errno (err, errno, "socket() failed: %d");
+ set_error_from_errno (err, errno, "socket() failed: %d");
return -1;
}
@@ -211,7 +217,7 @@ lac_connect (gint fd,
if (res < 0)
{
- lac_set_error_from_errno (err, errno, "connect() failed: %s");
+ set_error_from_errno (err, errno, "connect() failed: %s");
return FALSE;
}
@@ -249,7 +255,7 @@ lac_bind (gint fd,
if (ret < 0)
{
- lac_set_error_from_errno (err, errno, "bind() failed: %s");
+ set_error_from_errno (err, errno, "bind() failed: %s");
return FALSE;
}
@@ -276,9 +282,10 @@ lac_listen (gint fd,
if (ret < 0)
{
- lac_set_error_from_errno (err, errno, "listen() failed: %s");
+ set_error_from_errno (err, errno, "listen() failed: %s");
return FALSE;
}
+
return TRUE;
}
@@ -291,7 +298,7 @@ lac_accept (gint fd,
guint addr_len = sizeof (struct sockaddr_in);
struct sockaddr_in host_addr;
gint ret;
-
+
g_return_val_if_fail (fd > 0, FALSE);
g_return_val_if_fail (err == NULL || *err == NULL, FALSE);
@@ -304,16 +311,16 @@ lac_accept (gint fd,
if (ret < 0)
{
- lac_set_error_from_errno (err, errno, "accept() failed: %s");
+ set_error_from_errno (err, errno, "accept() failed: %s");
return -1;
}
-
+
if (address)
{
*address = lac_address_allocate ();
lac_address_set_in_addr (*address, &host_addr.sin_addr);
}
-
+
if (port)
*port = g_ntohs (host_addr.sin_port);
@@ -340,7 +347,7 @@ lac_send (gint fd,
if (res < 0)
{
- lac_set_error_from_errno (err, errno, "send() failed: %s:");
+ set_error_from_errno (err, errno, "send() failed: %s:");
return -1;
}
if (res == 0)
@@ -370,10 +377,10 @@ lac_recv (gint fd,
if (res < 0)
{
- lac_set_error_from_errno (err, errno, "recv() failed: %s");
+ set_error_from_errno (err, errno, "recv() failed: %s");
return -1;
}
-
+
return res;
}
@@ -408,10 +415,10 @@ lac_sendto (gint fd,
if (res < 0)
{
- lac_set_error_from_errno (err, errno, "sendto() failed: %s");
+ set_error_from_errno (err, errno, "sendto() failed: %s");
return FALSE;
}
-
+
return res;
}
@@ -430,7 +437,7 @@ lac_recvfrom (gint fd,
g_return_val_if_fail (fd > 0, -1);
g_return_val_if_fail (buf != NULL, -1);
g_return_val_if_fail (err == NULL || *err == NULL, -1);
-
+
errno = 0;
do
{
@@ -442,10 +449,10 @@ lac_recvfrom (gint fd,
if (res < 0)
{
- lac_set_error_from_errno (err, errno, "sendto() failed: %s");
+ set_error_from_errno (err, errno, "sendto() failed: %s");
return -1;
}
-
+
if (address)
{
*address = lac_address_allocate ();
@@ -453,10 +460,10 @@ lac_recvfrom (gint fd,
}
if (port)
*port = host_addr.sin_port;
-
+
return res;
}
-
+
gboolean
lac_getpeername (gint fd,
LacAddress **addr,
@@ -479,7 +486,7 @@ lac_getpeername (gint fd,
if (res < 0)
{
- lac_set_error_from_errno (err, errno, "getpeername() failed: %s");
+ set_error_from_errno (err, errno, "getpeername() failed: %s");
if (addr)
*addr = NULL;
if (port)
@@ -517,7 +524,7 @@ lac_shutdown (gint fd,
if (res < 0)
{
- lac_set_error_from_errno (err, errno, "shutdown() failed: %s");
+ set_error_from_errno (err, errno, "shutdown() failed: %s");
return FALSE;
}
@@ -535,14 +542,14 @@ lac_close (gint fd,
g_warning ("Closing a filedescriptor with a watch attached");
errno = 0;
-
+
/* It is actually not right to retry the close if we get EINTR.
* If a signal arrives, the file descriptor is left in an indeterminate
* state. The best we can do is leak it and return an error
*/
if (close (fd) < 0)
{
- lac_set_error_from_errno (err, errno, "close() failed: %s");
+ set_error_from_errno (err, errno, "close() failed: %s");
return FALSE;
}
@@ -569,7 +576,7 @@ lac_set_blocking (gint fd,
if (flags == -1)
{
- lac_set_error_from_errno (err, errno, "fcntl() failed: %s");
+ set_error_from_errno (err, errno, "fcntl() failed: %s");
return FALSE;
}
@@ -593,7 +600,7 @@ lac_set_blocking (gint fd,
if (ret == -1)
{
- lac_set_error_from_errno (err, errno, "fcntl() failed: %s");
+ set_error_from_errno (err, errno, "fcntl() failed: %s");
return FALSE;
}
@@ -612,13 +619,165 @@ lac_set_nagle (gint fd,
if (setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, &op, sizeof (op)) < 0)
{
- lac_set_error_from_errno (err, errno, "setsockopt() failed: %s");
+ set_error_from_errno (err, errno, "setsockopt() failed: %s");
return FALSE;
}
return TRUE;
}
+struct LacTLS
+{
+ gnutls_anon_client_credentials_t anoncred;
+ gnutls_session_t session;
+
+};
+
+static void
+init (void)
+{
+ static gboolean initialized;
+
+ if (!initialized)
+ gnutls_global_init ();
+}
+
+LacTLS *
+lac_tls_new (int fd)
+{
+ LacTLS *tls;
+ const int kx_prio[] = { GNUTLS_KX_ANON_DH, 0 };
+
+ init ();
+
+ tls = g_new0 (LacTLS, 1);
+
+ 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) fd);
+
+ return tls;
+}
+
+gboolean
+lac_tls_handshake (LacTLS *tls,
+ GError **err)
+{
+ gint res;
+
+ g_return_val_if_fail (tls != NULL, FALSE);
+ g_return_val_if_fail (err == NULL || *err == NULL, -1);
+
+ errno = 0;
+
+ do
+ {
+ res = gnutls_handshake (tls->session);
+ }
+ while (res == GNUTLS_E_INTERRUPTED);
+
+ if (res < 0)
+ {
+ set_error_from_gnutls_error (err, res, "gnutls_handshake");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+gint
+lac_tls_recv (LacTLS *tls,
+ gchar *buf,
+ guint len,
+ GError **err)
+{
+ gint res;
+
+ g_return_val_if_fail (tls != NULL, -1);
+ g_return_val_if_fail (buf != 0, -1);
+ g_return_val_if_fail (err == NULL || *err == NULL, -1);
+
+ errno = 0;
+
+ do
+ {
+ res = gnutls_record_recv (tls->session, buf, len);
+ }
+ while (res == GNUTLS_E_INTERRUPTED);
+
+ if (res < 0)
+ {
+ set_error_from_gnutls_error (err, res, "gnutls_record_recv() failed:");
+ return -1;
+ }
+
+ return res;
+}
+
+gint
+lac_tls_send (LacTLS *tls,
+ gchar *buf,
+ guint len,
+ GError **err)
+{
+ gint res;
+
+ g_return_val_if_fail (tls != NULL, -1);
+ g_return_val_if_fail (buf != 0, -1);
+ g_return_val_if_fail (err == NULL || *err == NULL, -1);
+
+ errno = 0;
+ do
+ {
+ res = gnutls_record_recv (tls->session, buf, len);
+ }
+ while (res != GNUTLS_E_INTERRUPTED);
+
+ if (res < 0)
+ {
+ set_error_from_gnutls_error (err, res, "gnutls_record_send() failed:");
+ return -1;
+ }
+
+ return res;
+}
+
+gboolean
+lac_tls_needs_write (LacTLS *tls)
+{
+ g_return_val_if_fail (tls != NULL, FALSE);
+
+ if (gnutls_record_get_direction (tls->session))
+ return TRUE;
+ else
+ return FALSE;
+}
+
+void
+lac_tls_free (LacTLS *tls)
+{
+ gnutls_deinit (tls->session);
+
+ gnutls_anon_free_client_credentials (tls->anoncred);
+
+ g_free (tls);
+}
+
+static void
+set_error_from_gnutls_error (GError **err,
+ int gnutls_err,
+ const gchar *msg)
+{
+ /* FIXME */
+
+ g_set_error (err, LAC_SOCKET_ERROR, LAC_SOCKET_ERROR_FAILED, msg);
+}
+
static LacError
lac_error_from_errno (int eno)
{
@@ -635,7 +794,7 @@ lac_error_from_errno (int eno)
return LAC_SOCKET_ERROR_TIMEOUT;
break;
#endif
-
+
#ifdef ECONNRESET
case ECONNRESET:
return LAC_SOCKET_ERROR_CONNECTION_RESET;
@@ -685,9 +844,9 @@ lac_error_from_errno (int eno)
}
static void
-lac_set_error_from_errno (GError **err,
- int eno,
- const gchar *msg)
+set_error_from_errno (GError **err,
+ int eno,
+ const gchar *msg)
{
g_set_error (err,
LAC_SOCKET_ERROR,
diff --git a/src/lactls.c b/src/lactls.c
deleted file mode 100644
index 6689674..0000000
--- a/src/lactls.c
+++ /dev/null
@@ -1,267 +0,0 @@
-#include "lac.h"
-
-#include <gnutls/gnutls.h>
-
-struct LacTLS
-{
- int fd;
-
- LacWatchCallback read_cb;
- LacWatchCallback write_cb;
- LacWatchCallback hangup_cb;
- LacWatchCallback error_cb;
- LacWatchCallback priority_cb;
-
-};
-
-LacTLS *
-lac_tls_new (GError **err)
-{
- int fd;
- LacTLS *tls;
-
- fd = lac_socket_tcp (err);
-
- if (fd < 0)
- return NULL;
-
- tls = g_new0 (LacTLS, 1);
- tls->fd = fd;
-
- return tls;
-}
-
-static void
-on_writable (LacTLS *tls)
-{
-
-}
-
-static void
-on_readable (LacTLS *tls)
-{
-
-}
-
-void
-lac_tls_connect (LacTLS *tls)
-{
-
-}
-
-void
-lac_tls_set_read_callback (LacTLS *tls,
- LacWatchCallback read_cb)
-{
-}
-
-void
-lac_tls_set_write_callback (LacTLS *tls,
- LacWatchCallback write_cb)
-{
-}
-
-void
-lac_tls_set_hangup_callback (LacTLS *tls,
- LacWatchCallback hangup_cb)
-{
-}
-
-void
-lac_tls_set_error_callback (LacTLS *tls,
- LacWatchCallback error_cb)
-{
-}
-
-void
-lac_tls_set_priority_callback (LacTLS *tls,
- LacWatchCallback priority_cb)
-{
-}
-
-int
-lac_tls_send (LacTLS *tls,
- char *msg,
- guint len,
- GError **err)
-{
-}
-
-int
-lac_tls_recv (LacTLS *tls,
- char *buf,
- guint size,
- GError **err)
-{
-}
-
-gboolean
-lac_tls_free (LacTLS *tls,
- GError **err)
-{
-}
-
-#if 0
-LacTLS * lac_tls_new (GError *err);
-gboolean lac_tls_connect (LacTLS *tls,
- LacAddress *addr,
- int port,
- GError **err);
-void lac_tls_set_read_callback (LacTLS *tls,
- LacReadCallback cb,
- gpointer data);
-void lac_tls_set_write_callback (LacTLS *tls);
-void lac_tls_set_hangup_callback (LacTLS *tls);
-void lac_tls_send (LacTLS *tls);
-void lac_tls_read (LacTLS *tls);
-
-
-struct LacTLS
-{
- int fd;
-
- /* tls */
- gnutls_anon_client_credentials_t anoncred;
- gnutls_session_t session;
-};
-
-
-static Socket *
-socket_new_tcp (GError **err)
-{
- Socket *socket;
- int fd;
-
- fd = lac_socket_tcp (err);
-
- if (fd < 0)
- return NULL;
-
- socket = g_new0 (Socket, 1);
- socket->fd = fd;
-
- return socket;
-}
-
-static Socket *
-socket_new_ssl (GError **err)
-{
- const int kx_prio[] = { GNUTLS_KX_ANON_DH, 0 };
-
- fd = lac_socket_tcp (err);
- if (fd < 0)
- return NULL;
-
- socket = g_new0 (Socket, 1);
-
- socket->is_tls = TRUE;
-
- gnutls_global_init ();
- gnutls_anon_allocate_client_credentials (&socket->anoncred);
- gnutls_init (&socket->session, GNUTLS_CLIENT);
- gnutls_set_default_priority (socket->session);
- gnutls_kx_set_priority (socket->session, kx_prio);
- gnutls_credentials_set (socket->session,
- GNUTLS_CRD_ANON, &socket->anoncred);
-
- gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) socket->fd);
-}
-
-static gboolean
-socket_connect (Socket *socket,
- LacAddress *address,
- gint port,
- GError **err)
-{
- return lac_connect (socket->fd, address, port, err);
-}
-
-static gboolean
-socket_is_connected (Socket *socket,
- GError **err)
-{
- if (socket->is_tls)
- {
- /* We only get called when the fd is writable, which
- * for TCP sockets means it's connected
- */
- return TRUE;
- }
- else
- {
- int ret;
-
- do
- {
- ret = gnutls_handshake (socket->session);
- } while (ret == GNUTLS_E_INTR);
-
- if (ret >= 0)
- return TRUE;
-
- if (ret != GNUTLS_E_AGAIN)
- {
- /* FIXME: set error */
- g_warning ("err\n");
- }
-
- return FALSE;
- }
-}
-
-static gint
-socket_send (Socket *socket,
- const gchar *msg,
- guint len,
- GError **err)
-{
- return lac_send (socket->fd, msg, len, err);
-}
-
-static gint
-socket_recv (Socket *socket,
- gchar *buf,
- guint size,
- GError **err)
-{
- return lac_recv (socket->fd, buf, size, err);
-}
-
-static int
-socket_get_fd (Socket *socket)
-{
- return socket->fd;
-}
-
-static gboolean
-socket_close (Socket *socket,
- GError **err)
-{
- return lac_close (socket->fd, err);
-}
-
-static void
-socket_flush (Socket *socket)
-{
- lac_set_nagle (socket->fd, FALSE, NULL);
- lac_set_nagle (socket->fd, TRUE, NULL);
-}
-
-static gboolean
-socket_set_blocking (Socket *socket,
- gboolean blocking,
- GError **err)
-{
- return lac_set_blocking (socket->fd, blocking, err);
-}
-
-static gboolean
-socket_shutdown (Socket *socket,
- LacShutdownMethod how,
- GError **err)
-{
- return lac_shutdown (socket->fd, how, err);
-}
-
-
-#endif