X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gio%2Fgsocket.c;h=97120a67d1b552e968e1f1cbd2c3687733cabb94;hb=8932a1a7a3bf1bb68c2f2762f3674a149742b1fa;hp=fb35f325e3e0c7c14a757625bb568ec25d5fa04e;hpb=5046dfc85d7df95d7f8c87e3b41d9152bc50549a;p=platform%2Fupstream%2Fglib.git diff --git a/gio/gsocket.c b/gio/gsocket.c index fb35f32..97120a6 100644 --- a/gio/gsocket.c +++ b/gio/gsocket.c @@ -26,7 +26,12 @@ */ #include "config.h" -#include "glib.h" + +#include "gsocket.h" + +#ifdef G_OS_UNIX +#include "glib-unix.h" +#endif #include #include @@ -42,7 +47,6 @@ #include #endif -#include "gsocket.h" #include "gcancellable.h" #include "gioenumtypes.h" #include "ginetaddress.h" @@ -50,13 +54,13 @@ #include "gioerror.h" #include "gioenums.h" #include "gioerror.h" +#include "gio-marshal.h" #include "gnetworkingprivate.h" #include "gsocketaddress.h" #include "gsocketcontrolmessage.h" +#include "gcredentials.h" #include "glibintl.h" -#include "gioalias.h" - /** * SECTION:gsocket * @short_description: Low-level socket object @@ -146,6 +150,7 @@ struct _GSocketPrivate gint listen_backlog; guint timeout; GError *construct_error; + GSocketAddress *remote_address; guint inited : 1; guint blocking : 1; guint keepalive : 1; @@ -153,6 +158,7 @@ struct _GSocketPrivate guint connected : 1; guint listening : 1; guint timed_out : 1; + guint connect_pending : 1; #ifdef G_OS_WIN32 WSAEVENT event; int current_events; @@ -238,22 +244,17 @@ static void set_fd_nonblocking (int fd) { #ifndef G_OS_WIN32 - glong arg; + GError *error = NULL; #else gulong arg; #endif #ifndef G_OS_WIN32 - if ((arg = fcntl (fd, F_GETFL, NULL)) < 0) + if (!g_unix_set_fd_nonblocking (fd, TRUE, &error)) { - g_warning ("Error getting socket status flags: %s", socket_strerror (errno)); - arg = 0; + g_warning ("Error setting socket nonblocking: %s", error->message); + g_clear_error (&error); } - - arg = arg | O_NONBLOCK; - - if (fcntl (fd, F_SETFL, arg) < 0) - g_warning ("Error setting socket status flags: %s", socket_strerror (errno)); #else arg = TRUE; @@ -376,13 +377,34 @@ g_socket_details_from_fd (GSocket *socket) { case G_SOCKET_FAMILY_IPV4: case G_SOCKET_FAMILY_IPV6: + socket->priv->family = address.ss_family; + switch (socket->priv->type) + { + case G_SOCKET_TYPE_STREAM: + socket->priv->protocol = G_SOCKET_PROTOCOL_TCP; + break; + + case G_SOCKET_TYPE_DATAGRAM: + socket->priv->protocol = G_SOCKET_PROTOCOL_UDP; + break; + + case G_SOCKET_TYPE_SEQPACKET: + socket->priv->protocol = G_SOCKET_PROTOCOL_SCTP; + break; + + default: + break; + } + break; + case G_SOCKET_FAMILY_UNIX: - socket->priv->family = address.ss_family; - break; + socket->priv->family = G_SOCKET_FAMILY_UNIX; + socket->priv->protocol = G_SOCKET_PROTOCOL_DEFAULT; + break; default: - socket->priv->family = G_SOCKET_FAMILY_INVALID; - break; + socket->priv->family = G_SOCKET_FAMILY_INVALID; + break; } if (socket->priv->family != G_SOCKET_FAMILY_INVALID) @@ -456,9 +478,11 @@ g_socket_create_socket (GSocketFamily family, } #ifdef SOCK_CLOEXEC - native_type |= SOCK_CLOEXEC; + fd = socket (family, native_type | SOCK_CLOEXEC, protocol); + /* It's possible that libc has SOCK_CLOEXEC but the kernel does not */ + if (fd < 0 && errno == EINVAL) #endif - fd = socket (family, native_type, protocol); + fd = socket (family, native_type, protocol); if (fd < 0) { @@ -628,6 +652,9 @@ g_socket_finalize (GObject *object) !socket->priv->closed) g_socket_close (socket, NULL); + if (socket->priv->remote_address) + g_object_unref (socket->priv->remote_address); + #ifdef G_OS_WIN32 if (socket->priv->event != WSA_INVALID_EVENT) { @@ -650,6 +677,7 @@ g_socket_class_init (GSocketClass *klass) /* Make sure winsock has been initialized */ type = g_inet_address_get_type (); + (type); /* To avoid -Wunused-but-set-variable */ #ifdef SIGPIPE /* There is no portable, thread-safe way to avoid having the process @@ -1197,7 +1225,7 @@ g_socket_get_fd (GSocket *socket) * useful if the socket has been bound to a local address, * either explicitly or implicitly when connecting. * - * Returns: a #GSocketAddress or %NULL on error. + * Returns: (transfer full): a #GSocketAddress or %NULL on error. * Free the returned object with g_object_unref(). * * Since: 2.22 @@ -1230,7 +1258,7 @@ g_socket_get_local_address (GSocket *socket, * Try to get the remove address of a connected socket. This is only * useful for connection oriented sockets that have been connected. * - * Returns: a #GSocketAddress or %NULL on error. + * Returns: (transfer full): a #GSocketAddress or %NULL on error. * Free the returned object with g_object_unref(). * * Since: 2.22 @@ -1244,15 +1272,28 @@ g_socket_get_remote_address (GSocket *socket, g_return_val_if_fail (G_IS_SOCKET (socket), NULL); - if (getpeername (socket->priv->fd, (struct sockaddr *) &buffer, &len) < 0) + if (socket->priv->connect_pending) { - int errsv = get_socket_errno (); - g_set_error (error, G_IO_ERROR, socket_io_error_from_errno (errsv), - _("could not get remote address: %s"), socket_strerror (errsv)); - return NULL; + if (!g_socket_check_connect_result (socket, error)) + return NULL; + else + socket->priv->connect_pending = FALSE; } - return g_socket_address_new_from_native (&buffer, len); + if (!socket->priv->remote_address) + { + if (getpeername (socket->priv->fd, (struct sockaddr *) &buffer, &len) < 0) + { + int errsv = get_socket_errno (); + g_set_error (error, G_IO_ERROR, socket_io_error_from_errno (errsv), + _("could not get remote address: %s"), socket_strerror (errsv)); + return NULL; + } + + socket->priv->remote_address = g_socket_address_new_from_native (&buffer, len); + } + + return g_object_ref (socket->priv->remote_address); } /** @@ -1438,7 +1479,7 @@ g_socket_speaks_ipv4 (GSocket *socket) /** * g_socket_accept: * @socket: a #GSocket. - * @cancellable: a %GCancellable or %NULL + * @cancellable: (allow-none): a %GCancellable or %NULL * @error: #GError for error reporting, or %NULL to ignore. * * Accept incoming connections on a connection-based socket. This removes @@ -1452,7 +1493,7 @@ g_socket_speaks_ipv4 (GSocket *socket) * or return %G_IO_ERROR_WOULD_BLOCK if non-blocking I/O is enabled. * To be notified of an incoming connection, wait for the %G_IO_IN condition. * - * Returns: a new #GSocket, or %NULL on error. + * Returns: (transfer full): a new #GSocket, or %NULL on error. * Free the returned object with g_object_unref(). * * Since: 2.22 @@ -1550,7 +1591,7 @@ g_socket_accept (GSocket *socket, * g_socket_connect: * @socket: a #GSocket. * @address: a #GSocketAddress specifying the remote address. - * @cancellable: a %GCancellable or %NULL + * @cancellable: (allow-none): a %GCancellable or %NULL * @error: #GError for error reporting, or %NULL to ignore. * * Connect the socket to the specified remote address. @@ -1590,6 +1631,10 @@ g_socket_connect (GSocket *socket, if (!g_socket_address_to_native (address, &buffer, sizeof buffer, error)) return FALSE; + if (socket->priv->remote_address) + g_object_unref (socket->priv->remote_address); + socket->priv->remote_address = g_object_ref (address); + while (1) { if (connect (socket->priv->fd, (struct sockaddr *) &buffer, @@ -1616,8 +1661,11 @@ g_socket_connect (GSocket *socket, g_prefix_error (error, _("Error connecting: ")); } else - g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PENDING, - _("Connection in progress")); + { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PENDING, + _("Connection in progress")); + socket->priv->connect_pending = TRUE; + } } else g_set_error (error, G_IO_ERROR, @@ -1673,6 +1721,11 @@ g_socket_check_connect_result (GSocket *socket, { g_set_error_literal (error, G_IO_ERROR, socket_io_error_from_errno (value), socket_strerror (value)); + if (socket->priv->remote_address) + { + g_object_unref (socket->priv->remote_address); + socket->priv->remote_address = NULL; + } return FALSE; } return TRUE; @@ -1684,7 +1737,7 @@ g_socket_check_connect_result (GSocket *socket, * @buffer: a buffer to read data into (which should be at least @size * bytes long). * @size: the number of bytes you want to read from the socket - * @cancellable: a %GCancellable or %NULL + * @cancellable: (allow-none): a %GCancellable or %NULL * @error: #GError for error reporting, or %NULL to ignore. * * Receive data (up to @size bytes) from a socket. This is mainly used by @@ -1702,15 +1755,17 @@ g_socket_check_connect_result (GSocket *socket, * received, the additional data will be returned in future calls to * g_socket_receive(). * - * If the socket is in blocking mode the call will block until there is - * some data to receive or there is an error. If there is no data available - * and the socket is in non-blocking mode, a %G_IO_ERROR_WOULD_BLOCK error - * will be returned. To be notified when data is available, wait for the + * If the socket is in blocking mode the call will block until there + * is some data to receive, the connection is closed, or there is an + * error. If there is no data available and the socket is in + * non-blocking mode, a %G_IO_ERROR_WOULD_BLOCK error will be + * returned. To be notified when data is available, wait for the * %G_IO_IN condition. * * On error -1 is returned and @error is set accordingly. * - * Returns: Number of bytes read, or -1 on error + * Returns: Number of bytes read, or 0 if the connection was closed by + * the peer, or -1 on error * * Since: 2.22 */ @@ -1721,6 +1776,38 @@ g_socket_receive (GSocket *socket, GCancellable *cancellable, GError **error) { + return g_socket_receive_with_blocking (socket, buffer, size, + socket->priv->blocking, + cancellable, error); +} + +/** + * g_socket_receive_with_blocking: + * @socket: a #GSocket + * @buffer: a buffer to read data into (which should be at least @size + * bytes long). + * @size: the number of bytes you want to read from the socket + * @blocking: whether to do blocking or non-blocking I/O + * @cancellable: (allow-none): a %GCancellable or %NULL + * @error: #GError for error reporting, or %NULL to ignore. + * + * This behaves exactly the same as g_socket_receive(), except that + * the choice of blocking or non-blocking behavior is determined by + * the @blocking argument rather than by @socket's properties. + * + * Returns: Number of bytes read, or 0 if the connection was closed by + * the peer, or -1 on error + * + * Since: 2.26 + */ +gssize +g_socket_receive_with_blocking (GSocket *socket, + gchar *buffer, + gsize size, + gboolean blocking, + GCancellable *cancellable, + GError **error) +{ gssize ret; g_return_val_if_fail (G_IS_SOCKET (socket) && buffer != NULL, FALSE); @@ -1733,7 +1820,7 @@ g_socket_receive (GSocket *socket, while (1) { - if (socket->priv->blocking && + if (blocking && !g_socket_condition_wait (socket, G_IO_IN, cancellable, error)) return -1; @@ -1745,7 +1832,7 @@ g_socket_receive (GSocket *socket, if (errsv == EINTR) continue; - if (socket->priv->blocking) + if (blocking) { #ifdef WSAEWOULDBLOCK if (errsv == WSAEWOULDBLOCK) @@ -1780,7 +1867,7 @@ g_socket_receive (GSocket *socket, * @buffer: a buffer to read data into (which should be at least @size * bytes long). * @size: the number of bytes you want to read from the socket - * @cancellable: a %GCancellable or %NULL + * @cancellable: (allow-none): a %GCancellable or %NULL * @error: #GError for error reporting, or %NULL to ignore. * * Receive data (up to @size bytes) from a socket. @@ -1791,7 +1878,8 @@ g_socket_receive (GSocket *socket, * * See g_socket_receive() for additional information. * - * Returns: Number of bytes read, or -1 on error + * Returns: Number of bytes read, or 0 if the connection was closed by + * the peer, or -1 on error * * Since: 2.22 */ @@ -1829,9 +1917,9 @@ g_socket_receive_from (GSocket *socket, /** * g_socket_send: * @socket: a #GSocket - * @buffer: the buffer containing the data to send. + * @buffer: (array length=size): the buffer containing the data to send. * @size: the number of bytes to send - * @cancellable: a %GCancellable or %NULL + * @cancellable: (allow-none): a %GCancellable or %NULL * @error: #GError for error reporting, or %NULL to ignore. * * Tries to send @size bytes from @buffer on the socket. This is @@ -1861,6 +1949,37 @@ g_socket_send (GSocket *socket, GCancellable *cancellable, GError **error) { + return g_socket_send_with_blocking (socket, buffer, size, + socket->priv->blocking, + cancellable, error); +} + +/** + * g_socket_send_with_blocking: + * @socket: a #GSocket + * @buffer: (array length=size): the buffer containing the data to send. + * @size: the number of bytes to send + * @blocking: whether to do blocking or non-blocking I/O + * @cancellable: (allow-none): a %GCancellable or %NULL + * @error: #GError for error reporting, or %NULL to ignore. + * + * This behaves exactly the same as g_socket_send(), except that + * the choice of blocking or non-blocking behavior is determined by + * the @blocking argument rather than by @socket's properties. + * + * Returns: Number of bytes written (which may be less than @size), or -1 + * on error + * + * Since: 2.26 + */ +gssize +g_socket_send_with_blocking (GSocket *socket, + const gchar *buffer, + gsize size, + gboolean blocking, + GCancellable *cancellable, + GError **error) +{ gssize ret; g_return_val_if_fail (G_IS_SOCKET (socket) && buffer != NULL, FALSE); @@ -1873,7 +1992,7 @@ g_socket_send (GSocket *socket, while (1) { - if (socket->priv->blocking && + if (blocking && !g_socket_condition_wait (socket, G_IO_OUT, cancellable, error)) return -1; @@ -1890,7 +2009,7 @@ g_socket_send (GSocket *socket, win32_unset_event_mask (socket, FD_WRITE); #endif - if (socket->priv->blocking) + if (blocking) { #ifdef WSAEWOULDBLOCK if (errsv == WSAEWOULDBLOCK) @@ -1917,9 +2036,9 @@ g_socket_send (GSocket *socket, * g_socket_send_to: * @socket: a #GSocket * @address: a #GSocketAddress, or %NULL - * @buffer: the buffer containing the data to send. + * @buffer: (array length=size): the buffer containing the data to send. * @size: the number of bytes to send - * @cancellable: a %GCancellable or %NULL + * @cancellable: (allow-none): a %GCancellable or %NULL * @error: #GError for error reporting, or %NULL to ignore. * * Tries to send @size bytes from @buffer to @address. If @address is @@ -2105,6 +2224,11 @@ g_socket_close (GSocket *socket, socket->priv->connected = FALSE; socket->priv->closed = TRUE; + if (socket->priv->remote_address) + { + g_object_unref (socket->priv->remote_address); + socket->priv->remote_address = NULL; + } return TRUE; } @@ -2292,7 +2416,7 @@ typedef struct { GIOCondition condition; GCancellable *cancellable; GPollFD cancel_pollfd; - GTimeVal timeout_time; + gint64 timeout_time; } GSocketSource; static gboolean @@ -2304,19 +2428,20 @@ socket_source_prepare (GSource *source, if (g_cancellable_is_cancelled (socket_source->cancellable)) return TRUE; - if (socket_source->timeout_time.tv_sec) + if (socket_source->timeout_time) { - GTimeVal now; + gint64 now; - g_source_get_current_time (source, &now); - *timeout = ((socket_source->timeout_time.tv_sec - now.tv_sec) * 1000 + - (socket_source->timeout_time.tv_usec - now.tv_usec) / 1000); + now = g_source_get_time (source); + /* Round up to ensure that we don't try again too early */ + *timeout = (socket_source->timeout_time - now + 999) / 1000; if (*timeout < 0) - { - socket_source->socket->priv->timed_out = TRUE; - socket_source->pollfd.revents = socket_source->condition & (G_IO_IN | G_IO_OUT); - return TRUE; - } + { + socket_source->socket->priv->timed_out = TRUE; + socket_source->pollfd.revents = socket_source->condition & (G_IO_IN | G_IO_OUT); + *timeout = 0; + return TRUE; + } } else *timeout = -1; @@ -2347,6 +2472,10 @@ socket_source_dispatch (GSource *source, GSocketSourceFunc func = (GSocketSourceFunc)callback; GSocketSource *socket_source = (GSocketSource *)source; +#ifdef G_OS_WIN32 + socket_source->pollfd.revents = update_condition (socket_source->socket); +#endif + return (*func) (socket_source->socket, socket_source->pollfd.revents & socket_source->condition, user_data); @@ -2373,12 +2502,42 @@ socket_source_finalize (GSource *source) } } +static gboolean +socket_source_closure_callback (GSocket *socket, + GIOCondition condition, + gpointer data) +{ + GClosure *closure = data; + + GValue params[2] = { { 0, }, { 0, } }; + GValue result_value = { 0, }; + gboolean result; + + g_value_init (&result_value, G_TYPE_BOOLEAN); + + g_value_init (¶ms[0], G_TYPE_SOCKET); + g_value_set_object (¶ms[0], socket); + g_value_init (¶ms[1], G_TYPE_IO_CONDITION); + g_value_set_flags (¶ms[1], condition); + + g_closure_invoke (closure, &result_value, 2, params, NULL); + + result = g_value_get_boolean (&result_value); + g_value_unset (&result_value); + g_value_unset (¶ms[0]); + g_value_unset (¶ms[1]); + + return result; +} + static GSourceFuncs socket_source_funcs = { socket_source_prepare, socket_source_check, socket_source_dispatch, - socket_source_finalize + socket_source_finalize, + (GSourceFunc)socket_source_closure_callback, + (GSourceDummyMarshal)_gio_marshal_BOOLEAN__FLAGS, }; static GSource * @@ -2402,6 +2561,7 @@ socket_source_new (GSocket *socket, condition |= G_IO_HUP | G_IO_ERR; source = g_source_new (&socket_source_funcs, sizeof (GSocketSource)); + g_source_set_name (source, "GSocket"); socket_source = (GSocketSource *)source; socket_source->socket = g_object_ref (socket); @@ -2426,24 +2586,20 @@ socket_source_new (GSocket *socket, g_source_add_poll (source, &socket_source->pollfd); if (socket->priv->timeout) - { - g_get_current_time (&socket_source->timeout_time); - socket_source->timeout_time.tv_sec += socket->priv->timeout; - } + socket_source->timeout_time = g_get_monotonic_time () + + socket->priv->timeout * 1000000; + else - { - socket_source->timeout_time.tv_sec = 0; - socket_source->timeout_time.tv_usec = 0; - } + socket_source->timeout_time = 0; return source; } /** - * g_socket_create_source: + * g_socket_create_source: (skip) * @socket: a #GSocket * @condition: a #GIOCondition mask to monitor - * @cancellable: a %GCancellable or %NULL + * @cancellable: (allow-none): a %GCancellable or %NULL * * Creates a %GSource that can be attached to a %GMainContext to monitor * for the availibility of the specified @condition on the socket. @@ -2465,7 +2621,7 @@ socket_source_new (GSocket *socket, * marked as having had a timeout, and so the next #GSocket I/O method * you call will then fail with a %G_IO_ERROR_TIMED_OUT. * - * Returns: a newly allocated %GSource, free with g_source_unref(). + * Returns: (transfer full): a newly allocated %GSource, free with g_source_unref(). * * Since: 2.22 */ @@ -2489,6 +2645,14 @@ g_socket_create_source (GSocket *socket, * against the currently-satisfied conditions on @socket. The result * is returned. * + * Note that on Windows, it is possible for an operation to return + * %G_IO_ERROR_WOULD_BLOCK even immediately after + * g_socket_condition_check() has claimed that the socket is ready for + * writing. Rather than calling g_socket_condition_check() and then + * writing to the socket if it succeeds, it is generally better to + * simply try writing to the socket right away, and try again later if + * the initial attempt returns %G_IO_ERROR_WOULD_BLOCK. + * * It is meaningless to specify %G_IO_ERR or %G_IO_HUP in condition; * these conditions will always be set in the output if they are true. * @@ -2536,7 +2700,7 @@ g_socket_condition_check (GSocket *socket, * g_socket_condition_wait: * @socket: a #GSocket * @condition: a #GIOCondition mask to wait for - * @cancellable: a #GCancellable, or %NULL + * @cancellable: (allow-none): a #GCancellable, or %NULL * @error: a #GError pointer, or %NULL * * Waits for @condition to become true on @socket. When the condition @@ -2663,13 +2827,13 @@ g_socket_condition_wait (GSocket *socket, * g_socket_send_message: * @socket: a #GSocket * @address: a #GSocketAddress, or %NULL - * @vectors: an array of #GOutputVector structs + * @vectors: (array length=num_vectors): an array of #GOutputVector structs * @num_vectors: the number of elements in @vectors, or -1 - * @messages: a pointer to an array of #GSocketControlMessages, or - * %NULL. + * @messages: (array length=num_messages) (allow-none): a pointer to an + * array of #GSocketControlMessages, or %NULL. * @num_messages: number of elements in @messages, or -1. * @flags: an int containing #GSocketMsgFlags flags - * @cancellable: a %GCancellable or %NULL + * @cancellable: (allow-none): a %GCancellable or %NULL * @error: #GError for error reporting, or %NULL to ignore. * * Send data to @address on @socket. This is the most complicated and @@ -2766,6 +2930,8 @@ g_socket_send_message (GSocket *socket, struct msghdr msg; gssize result; + msg.msg_flags = 0; + /* name */ if (address) { @@ -2819,7 +2985,13 @@ g_socket_send_message (GSocket *socket, for (i = 0; i < num_messages; i++) msg.msg_controllen += CMSG_SPACE (g_socket_control_message_get_size (messages[i])); - msg.msg_control = g_alloca (msg.msg_controllen); + if (msg.msg_controllen == 0) + msg.msg_control = NULL; + else + { + msg.msg_control = g_alloca (msg.msg_controllen); + memset (msg.msg_control, '\0', msg.msg_controllen); + } cmsg = CMSG_FIRSTHDR (&msg); for (i = 0; i < num_messages; i++) @@ -2953,14 +3125,14 @@ g_socket_send_message (GSocket *socket, * g_socket_receive_message: * @socket: a #GSocket * @address: a pointer to a #GSocketAddress pointer, or %NULL - * @vectors: an array of #GInputVector structs + * @vectors: (array length=num_vectors): an array of #GInputVector structs * @num_vectors: the number of elements in @vectors, or -1 - * @messages: a pointer which may be filled with an array of - * #GSocketControlMessages, or %NULL + * @messages: (array length=num_messages) (allow-none): a pointer which + * may be filled with an array of #GSocketControlMessages, or %NULL * @num_messages: a pointer which will be filled with the number of * elements in @messages, or %NULL * @flags: a pointer to an int containing #GSocketMsgFlags flags - * @cancellable: a %GCancellable or %NULL + * @cancellable: (allow-none): a %GCancellable or %NULL * @error: a #GError pointer, or %NULL * * Receive data from a socket. This is the most complicated and @@ -3013,14 +3185,16 @@ g_socket_send_message (GSocket *socket, * sufficiently-large buffer. * * If the socket is in blocking mode the call will block until there - * is some data to receive or there is an error. If there is no data - * available and the socket is in non-blocking mode, a - * %G_IO_ERROR_WOULD_BLOCK error will be returned. To be notified when - * data is available, wait for the %G_IO_IN condition. + * is some data to receive, the connection is closed, or there is an + * error. If there is no data available and the socket is in + * non-blocking mode, a %G_IO_ERROR_WOULD_BLOCK error will be + * returned. To be notified when data is available, wait for the + * %G_IO_IN condition. * * On error -1 is returned and @error is set accordingly. * - * Returns: Number of bytes read, or -1 on error + * Returns: Number of bytes read, or 0 if the connection was closed by + * the peer, or -1 on error * * Since: 2.22 */ @@ -3116,6 +3290,14 @@ g_socket_receive_message (GSocket *socket, else msg.msg_flags = 0; + /* We always set the close-on-exec flag so we don't leak file + * descriptors into child processes. Note that gunixfdmessage.c + * will later call fcntl (fd, FD_CLOEXEC), but that isn't atomic. + */ +#ifdef MSG_CMSG_CLOEXEC + msg.msg_flags |= MSG_CMSG_CLOEXEC; +#endif + /* do it */ while (1) { @@ -3125,6 +3307,14 @@ g_socket_receive_message (GSocket *socket, return -1; result = recvmsg (socket->priv->fd, &msg, msg.msg_flags); +#ifdef MSG_CMSG_CLOEXEC + if (result < 0 && get_socket_errno () == EINVAL) + { + /* We must be running on an old kernel. Call without the flag. */ + msg.msg_flags &= ~(MSG_CMSG_CLOEXEC); + result = recvmsg (socket->priv->fd, &msg, msg.msg_flags); + } +#endif if (result < 0) { @@ -3160,12 +3350,7 @@ g_socket_receive_message (GSocket *socket, /* decode control messages */ { GPtrArray *my_messages = NULL; - const gchar *scm_pointer; struct cmsghdr *cmsg; - gsize scm_size; - - scm_pointer = (const gchar *) msg.msg_control; - scm_size = msg.msg_controllen; for (cmsg = CMSG_FIRSTHDR (&msg); cmsg; cmsg = CMSG_NXTHDR (&msg, cmsg)) { @@ -3304,13 +3489,80 @@ g_socket_receive_message (GSocket *socket, if (messages != NULL) *messages = NULL; - if (n_messages != NULL) - *n_messages = 0; + if (num_messages != NULL) + *num_messages = 0; return bytes_received; } #endif } -#define __G_SOCKET_C__ -#include "gioaliasdef.c" +/** + * g_socket_get_credentials: + * @socket: a #GSocket. + * @error: #GError for error reporting, or %NULL to ignore. + * + * Returns the credentials of the foreign process connected to this + * socket, if any (e.g. it is only supported for %G_SOCKET_FAMILY_UNIX + * sockets). + * + * If this operation isn't supported on the OS, the method fails with + * the %G_IO_ERROR_NOT_SUPPORTED error. On Linux this is implemented + * by reading the %SO_PEERCRED option on the underlying socket. + * + * Other ways to obtain credentials from a foreign peer includes the + * #GUnixCredentialsMessage type and + * g_unix_connection_send_credentials() / + * g_unix_connection_receive_credentials() functions. + * + * Returns: (transfer full): %NULL if @error is set, otherwise a #GCredentials object + * that must be freed with g_object_unref(). + * + * Since: 2.26 + */ +GCredentials * +g_socket_get_credentials (GSocket *socket, + GError **error) +{ + GCredentials *ret; + + g_return_val_if_fail (G_IS_SOCKET (socket), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + ret = NULL; + +#ifdef __linux__ + { + struct ucred native_creds; + socklen_t optlen; + optlen = sizeof (struct ucred); + if (getsockopt (socket->priv->fd, + SOL_SOCKET, + SO_PEERCRED, + (void *)&native_creds, + &optlen) != 0) + { + int errsv = get_socket_errno (); + g_set_error (error, + G_IO_ERROR, + socket_io_error_from_errno (errsv), + _("Unable to get pending error: %s"), + socket_strerror (errsv)); + } + else + { + ret = g_credentials_new (); + g_credentials_set_native (ret, + G_CREDENTIALS_TYPE_LINUX_UCRED, + &native_creds); + } + } +#else + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + _("g_socket_get_credentials not implemented for this OS")); +#endif + + return ret; +}