X-Git-Url: http://git.cascardo.eti.br/?p=cascardo%2Fgnio.git;a=blobdiff_plain;f=gnio%2Fgtcpclient.c;h=ae8de6d785fcf115519842b1274f0c2249129fdc;hp=599358e08b5c0526050279c56fd235b03322455e;hb=48aa363fffb042f947130762acc7cd3c787b11d9;hpb=1c031c7647fc229c3be8fc40a4153aa47d3aea6b diff --git a/gnio/gtcpclient.c b/gnio/gtcpclient.c index 599358e..ae8de6d 100644 --- a/gnio/gtcpclient.c +++ b/gnio/gtcpclient.c @@ -41,12 +41,13 @@ G_DEFINE_TYPE (GTcpClient, g_tcp_client, G_TYPE_OBJECT); enum { - PROP_0 + PROP_0, + PROP_ADDRESS }; struct _GTcpClientPrivate { - + GSocketAddress *address; }; static void @@ -56,6 +57,10 @@ g_tcp_client_get_property (GObject *object, guint prop_id, GValue *value, GParam switch (prop_id) { + case PROP_ADDRESS: + g_value_set_object (value, client->priv->address); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } @@ -102,6 +107,13 @@ g_tcp_client_class_init (GTcpClientClass *klass) gobject_class->dispose = g_tcp_client_dispose; gobject_class->set_property = g_tcp_client_set_property; gobject_class->get_property = g_tcp_client_get_property; + + g_object_class_install_property (gobject_class, PROP_ADDRESS, + g_param_spec_object ("address", + "address", + "the remote address the socket will connect to", + G_TYPE_SOCKET_ADDRESS, + G_TYPE_CONSTRUCT_ONLY | G_PARAM_READABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK)); } static void @@ -117,6 +129,131 @@ g_tcp_client_new (GInetSocketAddress *address, return NULL; } +gboolean +g_tcp_client_connect (GTcpClient *client, + GError **error) +{ + return FALSE; +} + +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; + gint sockerr = 0; + 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 (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 (GTcpClient *client, + GCancellable *cancellable, + 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 +g_socket_connect_finish (GSocket *socket, + GAsyncResult *result, + GError **error) +{ + 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; +} + void g_tcp_client_close (GTcpClient *tcp_client) {