X-Git-Url: http://git.cascardo.eti.br/?p=cascardo%2Fgnio.git;a=blobdiff_plain;f=gnio%2Fgsocket.c;h=605f92b4ede8580cfedce1c51da780e47240a727;hp=1a095ef6cd8d725888f242014a0facb92ca71153;hb=48aa363fffb042f947130762acc7cd3c787b11d9;hpb=041acdd0edc340e7b6008b84e2ff6791c0d22713 diff --git a/gnio/gsocket.c b/gnio/gsocket.c index 1a095ef..605f92b 100644 --- a/gnio/gsocket.c +++ b/gnio/gsocket.c @@ -53,6 +53,8 @@ enum PROP_0, PROP_FD, PROP_BLOCKING, + PROP_BACKLOG, + PROP_REUSE_ADDRESS, PROP_LOCAL_ADDRESS, PROP_REMOTE_ADDRESS }; @@ -61,12 +63,17 @@ struct _GSocketPrivate { gint fd; gboolean blocking; + gint backlog; + gboolean reuse_address; GSocketAddress *local_address; GSocketAddress *remote_address; }; static void -g_socket_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +g_socket_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) { GSocket *socket = G_SOCKET (object); @@ -80,6 +87,14 @@ g_socket_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec g_value_set_boolean (value, socket->priv->blocking); break; + case PROP_BACKLOG: + g_value_set_int (value, socket->priv->backlog); + break; + + case PROP_REUSE_ADDRESS: + g_value_set_boolean (value, socket->priv->reuse_address); + break; + case PROP_LOCAL_ADDRESS: g_value_set_object (value, socket->priv->local_address); break; @@ -94,7 +109,10 @@ g_socket_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec } static void -g_socket_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +g_socket_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) { GSocket *socket = G_SOCKET (object); @@ -108,6 +126,14 @@ g_socket_set_property (GObject *object, guint prop_id, const GValue *value, GPar g_socket_set_blocking (socket, g_value_get_boolean (value)); break; + case PROP_BACKLOG: + socket->priv->backlog = g_value_get_int (value); + break; + + case PROP_REUSE_ADDRESS: + g_socket_set_reuse_address (socket, g_value_get_boolean (value)); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } @@ -116,7 +142,13 @@ g_socket_set_property (GObject *object, guint prop_id, const GValue *value, GPar static void g_socket_finalize (GObject *object) { - GSocket *socket G_GNUC_UNUSED = G_SOCKET (object); + GSocket *socket = G_SOCKET (object); + + if (socket->priv->local_address) + g_object_unref (socket->priv->local_address); + + if (socket->priv->remote_address) + g_object_unref (socket->priv->remote_address); if (G_OBJECT_CLASS (g_socket_parent_class)->finalize) (*G_OBJECT_CLASS (g_socket_parent_class)->finalize) (object); @@ -125,7 +157,9 @@ g_socket_finalize (GObject *object) static void g_socket_dispose (GObject *object) { - GSocket *socket G_GNUC_UNUSED = G_SOCKET (object);; + GSocket *socket = G_SOCKET (object); + + g_socket_close (socket); if (G_OBJECT_CLASS (g_socket_parent_class)->dispose) (*G_OBJECT_CLASS (g_socket_parent_class)->dispose) (object); @@ -161,6 +195,22 @@ g_socket_class_init (GSocketClass *klass) TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK)); + g_object_class_install_property (gobject_class, PROP_BACKLOG, + g_param_spec_int ("backlog", + "listen backlog", + "outstanding connections in the listen queue", + 0, + SOMAXCONN, + 10, + G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK)); + + g_object_class_install_property (gobject_class, PROP_REUSE_ADDRESS, + g_param_spec_boolean ("reuse-address", + "reuse address", + "allow reuse of local addresses when binding", + FALSE, + G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK)); + g_object_class_install_property (gobject_class, PROP_LOCAL_ADDRESS, g_param_spec_object ("local-address", "local address", @@ -183,6 +233,7 @@ g_socket_init (GSocket *socket) socket->priv->fd = -1; socket->priv->blocking = TRUE; + socket->priv->backlog = 10; socket->priv->remote_address = NULL; socket->priv->local_address = NULL; } @@ -255,7 +306,7 @@ g_socket_new (GSocketDomain domain, GSocketType type, const gchar *protocol, GEr return NULL; } - return G_SOCKET (g_object_new (G_TYPE_SOCKET, "fd", fd, NULL)); + return G_SOCKET (g_object_new (G_TYPE_SOCKET, "fd", fd, "blocking", TRUE, NULL)); } GSocket * @@ -267,9 +318,9 @@ g_socket_new_from_fd (gint fd) if ((arg = fcntl (fd, F_GETFL, NULL)) < 0) g_warning ("Error getting socket status flags: %s", g_strerror (errno)); - blocking = ((arg & O_NONBLOCK) != 0); + blocking = ((arg & O_NONBLOCK) == 0); - return G_SOCKET (g_object_new (G_TYPE_SOCKET, "blocking", blocking, "fd", fd, NULL)); + return G_SOCKET (g_object_new (G_TYPE_SOCKET, "fd", fd, "blocking", blocking, NULL)); } void @@ -299,12 +350,34 @@ g_socket_get_blocking (GSocket *socket) return socket->priv->blocking; } +void +g_socket_set_reuse_address (GSocket *socket, + gboolean reuse) +{ + gint value = (gint) reuse; + + g_return_if_fail (G_IS_SOCKET (socket)); + + if (setsockopt (socket->priv->fd, SOL_SOCKET, SO_REUSEADDR, (gpointer) &value, sizeof (value)) < 0) + g_warning ("error setting reuse address: %s", g_strerror (errno)); + + socket->priv->reuse_address = reuse; +} + +gboolean +g_socket_get_reuse_address (GSocket *socket) +{ + g_return_val_if_fail (G_IS_SOCKET (socket), FALSE); + + return socket->priv->reuse_address; +} + GSocketAddress * g_socket_get_local_address (GSocket *socket, GError **error) { gchar buffer[256]; - gsize len; + gsize len = 256; g_return_val_if_fail (G_IS_SOCKET (socket), NULL); @@ -325,7 +398,7 @@ g_socket_get_remote_address (GSocket *socket, GError **error) { gchar buffer[256]; - gsize len; + gsize len = 256; g_return_val_if_fail (G_IS_SOCKET (socket), NULL); @@ -341,13 +414,19 @@ g_socket_get_remote_address (GSocket *socket, return (socket->priv->remote_address = g_object_ref_sink (g_socket_address_from_native (buffer, len))); } -void -g_socket_listen (GSocket *socket, - gint backlog) +gboolean +g_socket_listen (GSocket *socket, + GError **error) { - g_return_if_fail (G_IS_SOCKET (socket)); + g_return_val_if_fail (G_IS_SOCKET (socket), FALSE); + + if (listen (socket->priv->fd, socket->priv->backlog) < 0) + { + g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno), "could not listen: %s", g_strerror (errno)); + return FALSE; + } - listen (socket->priv->fd, backlog); + return TRUE; } gboolean @@ -385,7 +464,7 @@ g_socket_accept (GSocket *socket, if ((ret = accept (socket->priv->fd, NULL, 0)) < 0) { - g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno), "error accepting connection"); + g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno), "error accepting connection: %s", g_strerror (errno)); return NULL; } @@ -416,3 +495,63 @@ g_socket_connect (GSocket *socket, return TRUE; } + +gssize +g_socket_receive (GSocket *socket, + gchar *buffer, + gsize size, + GError **error) +{ + gssize ret; + + g_return_val_if_fail (G_IS_SOCKET (socket) && buffer != NULL, FALSE); + + if ((ret = recv (socket->priv->fd, buffer, size, 0)) < 0) + { + g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno), "error receiving data: %s", g_strerror (errno)); + return -1; + } + + return ret; +} + +gssize +g_socket_send (GSocket *socket, + gchar *buffer, + gsize size, + GError **error) +{ + gssize ret; + + g_return_val_if_fail (G_IS_SOCKET (socket) && buffer != NULL, FALSE); + + if ((ret = send (socket->priv->fd, buffer, size, 0)) < 0) + { + g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno), "error sending data: %s", g_strerror (errno)); + return -1; + } + + return ret; +} + +void +g_socket_close (GSocket *socket) +{ + g_return_if_fail (G_IS_SOCKET (socket)); + +#ifdef G_OS_WIN32 + closesocket (socket->priv->fd); +#else + close (socket->priv->fd); +#endif +} + +GSource * +g_socket_create_source (GSocket *socket, + GIOCondition condition, + GCancellable *cancellable) +{ + g_return_val_if_fail (G_IS_SOCKET (socket) && (cancellable == NULL || G_IS_CANCELLABLE (cancellable)), NULL); + + return _g_fd_source_new (socket->priv->fd, G_IO_IN | G_IO_HUP | G_IO_ERR, cancellable); +}