From e9904ad0b8193f73258d2085864e03836b7f4b7a Mon Sep 17 00:00:00 2001 From: Samuel Cormier-Iijima Date: Wed, 27 Feb 2008 03:37:08 -0500 Subject: [PATCH] Some more socket stuff --- gnio/gsocket.c | 127 ++++++++++++++++++++++++++++++++++++++++++--- gnio/gsocket.h | 6 +-- test/Makefile.am | 1 + test/test-client.c | 43 +++++++++++++++ test/test-server.c | 1 - 5 files changed, 166 insertions(+), 12 deletions(-) create mode 100644 test/test-client.c diff --git a/gnio/gsocket.c b/gnio/gsocket.c index f6c586e..6c045c2 100644 --- a/gnio/gsocket.c +++ b/gnio/gsocket.c @@ -33,6 +33,7 @@ # include # include # include +# include #else #endif @@ -214,7 +215,7 @@ GSocketAddress * g_socket_get_peer_address (GSocket *socket, GError **error) { - gchar buffer[128]; + gchar buffer[256]; gsize len; g_return_val_if_fail (G_IS_SOCKET (socket), NULL); @@ -245,7 +246,7 @@ g_socket_bind (GSocket *socket, g_return_val_if_fail (G_IS_SOCKET (socket) && G_IS_SOCKET_ADDRESS (address), FALSE); { - gchar addr[g_socket_address_native_size (address)]; + gchar addr[256]; if (!g_socket_address_to_native (address, addr)) return FALSE; @@ -370,6 +371,8 @@ g_socket_accept_async (GSocket *socket, { result = g_simple_async_result_new (G_OBJECT (socket), callback, user_data, g_socket_accept_async); + g_simple_async_result_set_op_res_gpointer (result, g_socket_new_from_fd (ret), g_object_unref); + g_simple_async_result_complete_in_idle (result); g_object_unref (result); @@ -388,6 +391,9 @@ g_socket_accept_finish (GSocket *socket, simple = G_SIMPLE_ASYNC_RESULT (result); + if (g_simple_async_result_propagate_error (simple, error)) + return NULL; + g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_socket_accept_async); new_socket = g_object_ref (g_simple_async_result_get_op_res_gpointer (simple)); @@ -401,9 +407,13 @@ g_socket_connect (GSocket *socket, GCancellable *cancellable, GError **error) { - g_return_val_if_fail (G_IS_SOCKET (socket), FALSE); -/* - if (connect () < 0) + gchar buffer[256]; + + g_return_val_if_fail (G_IS_SOCKET (socket) && G_IS_SOCKET_ADDRESS (address), FALSE); + + g_socket_address_to_native (address, buffer); + + if (connect (socket->priv->fd, (struct sockaddr *) buffer, g_socket_address_native_size (address)) < 0) { if (errno == EINPROGRESS) g_set_error (error, G_IO_ERROR, G_IO_ERROR_PENDING, "connection in progress"); @@ -411,18 +421,108 @@ g_socket_connect (GSocket *socket, g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno), "error connecting: %s", g_strerror (errno)); return FALSE; } -*/ + return TRUE; } +typedef struct { + GAsyncReadyCallback callback; + GCancellable *cancellable; + gpointer user_data; + GSocket *socket; + gchar address_buffer[256]; + gsize address_length; +} ConnectData; + +static gboolean +connect_callback (ConnectData *data, + GIOCondition condition, + gint fd) +{ + GSocket *socket; + GSimpleAsyncResult *result = NULL; + guint sockerr; + gsize sockerr_size = 1; + + socket = data->socket; + + if (condition & G_IO_OUT) + { + result = g_simple_async_result_new (G_OBJECT (socket), data->callback, data->user_data, g_socket_connect_async); + } + else if (condition & G_IO_ERR) + { + if (getsockopt (socket->priv->fd, SOL_SOCKET, SO_ERROR, (gpointer) &sockerr, &sockerr_size) < 0) + g_warning ("getsockopt: %s", g_strerror (errno)); + + if (sockerr != 0) + result = g_simple_async_result_new_error (G_OBJECT (socket), data->callback, data->user_data, G_IO_ERROR, g_io_error_from_errno (sockerr), "error connecting: %s", g_strerror (sockerr)); + else + g_warning ("getsockopt SO_ERROR returned no error, with sockerr = %d", sockerr); + } + + g_simple_async_result_complete (result); + + g_object_unref (result); + + return FALSE; +} + void g_socket_connect_async (GSocket *socket, GSocketAddress *address, GCancellable *cancellable, - GAsyncReadyCallback *callback, + GAsyncReadyCallback callback, gpointer user_data) { + GSource *source; + GSimpleAsyncResult *result; + ConnectData *data; + gint ret; + gchar buffer[256]; + gsize len; + g_return_if_fail (G_IS_SOCKET (socket) && G_IS_SOCKET_ADDRESS (address)); + + if (g_socket_get_blocking (socket)) + g_socket_set_blocking (socket, FALSE); + + g_socket_address_to_native (address, buffer); + + len = g_socket_address_native_size (address); + + if ((ret = connect (socket->priv->fd, (struct sockaddr *) buffer, len)) < 0) + { + if (errno == EINPROGRESS) + { + source = _g_fd_source_new (socket->priv->fd, G_IO_OUT | G_IO_ERR, cancellable); + + data = g_new (ConnectData, 1); + + data->socket = socket; + data->callback = callback; + data->cancellable = cancellable; + data->user_data = user_data; + data->address_length = len; + memcpy (data->address_buffer, buffer, len); + + g_source_set_callback (source, (GSourceFunc) connect_callback, data, g_free); + + g_source_attach (source, NULL); + } + else + { + g_simple_async_report_error_in_idle (G_OBJECT (socket), callback, user_data, G_IO_ERROR, g_io_error_from_errno (errno), "error connecting: %s", g_strerror (errno)); + } + } + else + { + result = g_simple_async_result_new (G_OBJECT (socket), callback, user_data, g_socket_connect_async); + + g_simple_async_result_complete_in_idle (result); + + g_object_unref (result); + } } gboolean @@ -430,5 +530,16 @@ g_socket_connect_finish (GSocket *socket, GAsyncResult *result, GError **error) { - return FALSE; + GSimpleAsyncResult *simple; + + g_return_val_if_fail (G_IS_SOCKET (socket), FALSE); + + simple = G_SIMPLE_ASYNC_RESULT (result); + + if (g_simple_async_result_propagate_error (simple, error)) + return FALSE; + + g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_socket_connect_async); + + return TRUE; } diff --git a/gnio/gsocket.h b/gnio/gsocket.h index 678ef03..63295e1 100644 --- a/gnio/gsocket.h +++ b/gnio/gsocket.h @@ -80,7 +80,7 @@ gboolean g_socket_connect (GSocket *socket, void g_socket_connect_async (GSocket *socket, GSocketAddress *address, GCancellable *cancellable, - GAsyncReadyCallback *callback, + GAsyncReadyCallback callback, gpointer user_data); gboolean g_socket_connect_finish (GSocket *socket, @@ -113,7 +113,7 @@ void g_socket_receive_async (GSocket *socket, gchar *buffer, gsize size, GCancellable *cancellable, - GAsyncReadyCallback *callback, + GAsyncReadyCallback callback, gpointer user_data); gssize g_socket_receive_finish (GSocket *socket, @@ -130,7 +130,7 @@ void g_socket_send_async (GSocket *socket, gchar *buffer, gsize size, GCancellable *cancellable, - GAsyncReadyCallback *callback, + GAsyncReadyCallback callback, gpointer user_data); gssize g_socket_send_finish (GSocket *socket, diff --git a/test/Makefile.am b/test/Makefile.am index 8366f20..9e32d5f 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -12,6 +12,7 @@ AM_LDFLAGS = \ noinst_PROGRAMS = \ test-stuff \ test-server \ + test-client \ $(NULL) EXTRA_DIST = diff --git a/test/test-client.c b/test/test-client.c new file mode 100644 index 0000000..13a0b63 --- /dev/null +++ b/test/test-client.c @@ -0,0 +1,43 @@ +#include +#include +#include +#include +#include +#include +#include + +GMainLoop *loop; + +void +accept_callback (GSocket *socket, GAsyncResult *result, gpointer data) +{ + GError *error = NULL; + + if (!g_socket_connect_finish (socket, result, &error)) { + g_warning ("error connecting: %s", error->message); + return; + } + + g_print ("successfully connected\n"); +} + +int main (int argc, char *argv[]) +{ + GSocket *socket; + + g_thread_init (NULL); + + g_type_init (); + + loop = g_main_loop_new (NULL, FALSE); + + socket = g_socket_new (AF_INET, SOCK_STREAM, 0); + + g_printf ("connecting to 127.0.0.1:31882...\n"); + + g_socket_connect_async (socket, G_SOCKET_ADDRESS (g_inet_socket_address_new (G_INET_ADDRESS (g_inet4_address_from_string ("127.0.0.1")), 31882)), NULL, (GAsyncReadyCallback) accept_callback, NULL); + + g_main_loop_run (loop); + + return 0; +} diff --git a/test/test-server.c b/test/test-server.c index 9a7c9d6..d6d9e46 100644 --- a/test/test-server.c +++ b/test/test-server.c @@ -20,7 +20,6 @@ accept_callback (GSocket *socket, GAsyncResult *result, gpointer data) address = g_socket_get_peer_address (new_socket, NULL); g_printf ("got a new connection from %s:%d\n", g_inet_address_to_string (g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (address))), g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (address))); - } int main (int argc, char *argv[]) -- 2.20.1