X-Git-Url: http://git.cascardo.eti.br/?a=blobdiff_plain;f=gnio%2Fgsocket.c;h=1a095ef6cd8d725888f242014a0facb92ca71153;hb=041acdd0edc340e7b6008b84e2ff6791c0d22713;hp=3cf7534f154929e6284edbe6dc858b32aca06742;hpb=e565d23487b351658be8d8bc374d847c09b7a0cf;p=cascardo%2Fgnio.git diff --git a/gnio/gsocket.c b/gnio/gsocket.c index 3cf7534..1a095ef 100644 --- a/gnio/gsocket.c +++ b/gnio/gsocket.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #ifndef G_OS_WIN32 @@ -31,6 +32,8 @@ # include # include # include +# include +# include #else #endif @@ -48,13 +51,18 @@ G_DEFINE_TYPE (GSocket, g_socket, G_TYPE_OBJECT); enum { PROP_0, - PROP_FD + PROP_FD, + PROP_BLOCKING, + PROP_LOCAL_ADDRESS, + PROP_REMOTE_ADDRESS }; struct _GSocketPrivate { gint fd; gboolean blocking; + GSocketAddress *local_address; + GSocketAddress *remote_address; }; static void @@ -68,6 +76,18 @@ g_socket_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec g_value_set_int (value, socket->priv->fd); break; + case PROP_BLOCKING: + g_value_set_boolean (value, socket->priv->blocking); + break; + + case PROP_LOCAL_ADDRESS: + g_value_set_object (value, socket->priv->local_address); + break; + + case PROP_REMOTE_ADDRESS: + g_value_set_object (value, socket->priv->remote_address); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } @@ -84,6 +104,10 @@ g_socket_set_property (GObject *object, guint prop_id, const GValue *value, GPar socket->priv->fd = g_value_get_int (value); break; + case PROP_BLOCKING: + g_socket_set_blocking (socket, g_value_get_boolean (value)); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } @@ -112,12 +136,44 @@ g_socket_class_init (GSocketClass *klass) { GObjectClass *gobject_class G_GNUC_UNUSED = G_OBJECT_CLASS (klass); + // TODO: WSAStartup + g_type_class_add_private (klass, sizeof (GSocketPrivate)); gobject_class->finalize = g_socket_finalize; gobject_class->dispose = g_socket_dispose; gobject_class->set_property = g_socket_set_property; gobject_class->get_property = g_socket_get_property; + + g_object_class_install_property (gobject_class, PROP_FD, + g_param_spec_int ("fd", + "file descriptor", + "the socket's file descriptor", + G_MININT, + G_MAXINT, + -1, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK)); + + g_object_class_install_property (gobject_class, PROP_BLOCKING, + g_param_spec_boolean ("blocking", + "blocking", + "whether or not this socket is blocking", + TRUE, + 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", + "the local address the socket is bound to", + G_TYPE_SOCKET_ADDRESS, + G_PARAM_READABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK)); + + g_object_class_install_property (gobject_class, PROP_REMOTE_ADDRESS, + g_param_spec_object ("remote-address", + "remote address", + "the remote address the socket is connected to", + G_TYPE_SOCKET_ADDRESS, + G_PARAM_READABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK)); } static void @@ -127,25 +183,93 @@ g_socket_init (GSocket *socket) socket->priv->fd = -1; socket->priv->blocking = TRUE; + socket->priv->remote_address = NULL; + socket->priv->local_address = NULL; } GSocket * -g_socket_new (gint domain, gint type, gint protocol) +g_socket_new (GSocketDomain domain, GSocketType type, const gchar *protocol, GError **error) { - gint sock; + static GStaticMutex getprotobyname_mutex = G_STATIC_MUTEX_INIT; + gint fd, native_domain, native_type, native_protocol; + + switch (domain) + { + case G_SOCKET_DOMAIN_INET: + native_domain = PF_INET; + break; + + case G_SOCKET_DOMAIN_INET6: + native_domain = PF_INET6; + break; + + case G_SOCKET_DOMAIN_UNIX: + native_domain = PF_UNIX; + break; + + default: + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "unsupported socket domain"); + return NULL; + } + + switch (type) + { + case G_SOCKET_TYPE_STREAM: + native_type = SOCK_STREAM; + break; - sock = socket(domain, type, protocol); + case G_SOCKET_TYPE_DATAGRAM: + native_type = SOCK_DGRAM; + break; + + case G_SOCKET_TYPE_SEQPACKET: + native_type = SOCK_SEQPACKET; + break; + + default: + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "unsupported socket type"); + return NULL; + } - if (sock < 0) - return NULL; + if (protocol == NULL) + native_protocol = 0; + else + { + struct protoent *ent; + g_static_mutex_lock (&getprotobyname_mutex); + if (!(ent = getprotobyname (protocol))) + { + g_static_mutex_unlock (&getprotobyname_mutex); + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "unsupported socket protocol"); + return NULL; + } + native_protocol = ent->p_proto; + g_static_mutex_unlock (&getprotobyname_mutex); + } + + fd = socket(native_domain, native_type, native_protocol); + + if (fd < 0) + { + g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno), "unable to create socket: %s", g_strerror (errno)); + return NULL; + } - return G_SOCKET (g_object_new (G_TYPE_SOCKET, "fd", sock, NULL)); + return G_SOCKET (g_object_new (G_TYPE_SOCKET, "fd", fd, NULL)); } GSocket * g_socket_new_from_fd (gint fd) { - return G_SOCKET (g_object_new (G_TYPE_SOCKET, "fd", fd, NULL)); + glong arg; + gboolean blocking; + + if ((arg = fcntl (fd, F_GETFL, NULL)) < 0) + g_warning ("Error getting socket status flags: %s", g_strerror (errno)); + + blocking = ((arg & O_NONBLOCK) != 0); + + return G_SOCKET (g_object_new (G_TYPE_SOCKET, "blocking", blocking, "fd", fd, NULL)); } void @@ -159,10 +283,62 @@ g_socket_set_blocking (GSocket *socket, if ((arg = fcntl (socket->priv->fd, F_GETFL, NULL)) < 0) g_warning ("Error getting socket status flags: %s", g_strerror (errno)); - arg = blocking ? arg | O_NONBLOCK : arg & ~O_NONBLOCK; + arg = blocking ? arg & ~O_NONBLOCK : arg | O_NONBLOCK; if (fcntl (socket->priv->fd, F_SETFL, arg) < 0) g_warning ("Error setting socket status flags: %s", g_strerror (errno)); + + socket->priv->blocking = blocking; +} + +gboolean +g_socket_get_blocking (GSocket *socket) +{ + g_return_val_if_fail (G_IS_SOCKET (socket), FALSE); + + return socket->priv->blocking; +} + +GSocketAddress * +g_socket_get_local_address (GSocket *socket, + GError **error) +{ + gchar buffer[256]; + gsize len; + + g_return_val_if_fail (G_IS_SOCKET (socket), NULL); + + if (socket->priv->local_address) + return socket->priv->local_address; + + if (getsockname (socket->priv->fd, (struct sockaddr *) buffer, &len) < 0) + { + g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno), "could not get local address: %s", g_strerror (errno)); + return NULL; + } + + return (socket->priv->local_address = g_object_ref_sink (g_socket_address_from_native (buffer, len))); +} + +GSocketAddress * +g_socket_get_remote_address (GSocket *socket, + GError **error) +{ + gchar buffer[256]; + gsize len; + + g_return_val_if_fail (G_IS_SOCKET (socket), NULL); + + if (socket->priv->remote_address) + return socket->priv->remote_address; + + if (getpeername (socket->priv->fd, (struct sockaddr *) buffer, &len) < 0) + { + g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno), "could not get remote address: %s", g_strerror (errno)); + return NULL; + } + + return (socket->priv->remote_address = g_object_ref_sink (g_socket_address_from_native (buffer, len))); } void @@ -182,32 +358,52 @@ 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; if (bind (socket->priv->fd, (struct sockaddr *) addr, g_socket_address_native_size (address)) < 0) { - // TODO: set error + g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno), "error binding to address: %s", g_strerror (errno)); return FALSE; } - g_object_unref (address); + g_object_ref_sink (address); + + socket->priv->local_address = address; return TRUE; } } +GSocket * +g_socket_accept (GSocket *socket, + GError **error) +{ + gint ret; + + 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"); + return NULL; + } + + return g_socket_new_from_fd (ret); +} + gboolean g_socket_connect (GSocket *socket, GSocketAddress *address, - 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"); @@ -215,24 +411,8 @@ 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; -} -void -g_socket_connect_async (GSocket *socket, - GSocketAddress *address, - GCancellable *cancellable, - GAsyncReadyCallback *callback, - gpointer user_data) -{ + socket->priv->remote_address = g_object_ref_sink (address); -} - -gboolean -g_socket_connect_finish (GSocket *socket, - GAsyncResult *result, - GError **error) -{ - return FALSE; + return TRUE; }