X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gio%2Fgsocket.c;h=4d863cecdf56e8bb9b2be7ef081136746aefe909;hb=c8d10470939847069b1a346d4c44f2adde3469f6;hp=7c1422b03decc01d604f42cc156e8e9cb20d1697;hpb=8f80fbb2a7bbd140657247b328d6f010ed4d9157;p=platform%2Fupstream%2Fglib.git diff --git a/gio/gsocket.c b/gio/gsocket.c index 7c1422b..4d863ce 100644 --- a/gio/gsocket.c +++ b/gio/gsocket.c @@ -15,9 +15,7 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General - * Public License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA. + * Public License along with this library; if not, see . * * Authors: Christian Kellner * Samuel Cormier-Iijima @@ -48,7 +46,7 @@ # include #endif -#ifdef HAVE_SYS_UIO_H +#ifdef G_OS_UNIX #include #endif @@ -63,13 +61,14 @@ #include "gsocketaddress.h" #include "gsocketcontrolmessage.h" #include "gcredentials.h" +#include "gcredentialsprivate.h" #include "glibintl.h" /** * SECTION:gsocket * @short_description: Low-level socket object * @include: gio/gio.h - * @see_also: #GInitable, gnetworking.h + * @see_also: #GInitable, [][gio-gnetworking.h] * * A #GSocket is a low-level networking primitive. It is a more or less * direct mapping of the BSD socket API in a portable GObject based API. @@ -104,7 +103,7 @@ * reasons. For instance, on Windows a socket is always seen as writable * until a write returns %G_IO_ERROR_WOULD_BLOCK. * - * #GSockets can be either connection oriented or datagram based. + * #GSockets can be either connection oriented or datagram based. * For connection oriented types you must first establish a connection by * either connecting to an address or accepting a connection from another * address. For connectionless socket types the target/source address is @@ -118,6 +117,10 @@ * account the fact that your program will not automatically be killed * if it tries to write to %stdout after it has been closed. * + * Like most other APIs in GLib, #GSocket is not inherently thread safe. To use + * a #GSocket concurrently from multiple threads, you must implement your own + * locking. + * * Since: 2.22 */ @@ -172,6 +175,7 @@ struct _GSocketPrivate int current_errors; int selected_events; GList *requested_conditions; /* list of requested GIOCondition * */ + GMutex win32_source_lock; #endif struct { @@ -201,34 +205,10 @@ get_socket_errno (void) static GIOErrorEnum socket_io_error_from_errno (int err) { -#ifndef G_OS_WIN32 - return g_io_error_from_errno (err); +#ifdef G_OS_WIN32 + return g_io_error_from_win32_error (err); #else - switch (err) - { - case WSAEADDRINUSE: - return G_IO_ERROR_ADDRESS_IN_USE; - case WSAEWOULDBLOCK: - return G_IO_ERROR_WOULD_BLOCK; - case WSAEACCES: - return G_IO_ERROR_PERMISSION_DENIED; - case WSA_INVALID_HANDLE: - case WSA_INVALID_PARAMETER: - case WSAEBADF: - case WSAENOTSOCK: - return G_IO_ERROR_INVALID_ARGUMENT; - case WSAEPROTONOSUPPORT: - return G_IO_ERROR_NOT_SUPPORTED; - case WSAECANCELLED: - return G_IO_ERROR_CANCELLED; - case WSAESOCKTNOSUPPORT: - case WSAEOPNOTSUPP: - case WSAEPFNOSUPPORT: - case WSAEAFNOSUPPORT: - return G_IO_ERROR_NOT_SUPPORTED; - default: - return G_IO_ERROR_FAILED; - } + return g_io_error_from_errno (err); #endif } @@ -276,32 +256,6 @@ _win32_unset_event_mask (GSocket *socket, int mask) recv (sockfd, (gpointer)buf, len, flags) #endif -static void -set_fd_nonblocking (int fd) -{ -#ifndef G_OS_WIN32 - GError *error = NULL; -#else - gulong arg; -#endif - -#ifndef G_OS_WIN32 - if (!g_unix_set_fd_nonblocking (fd, TRUE, &error)) - { - g_warning ("Error setting socket nonblocking: %s", error->message); - g_clear_error (&error); - } -#else - arg = TRUE; - - if (ioctlsocket (fd, FIONBIO, &arg) == SOCKET_ERROR) - { - int errsv = get_socket_errno (); - g_warning ("Error setting socket status flags: %s", socket_strerror (errsv)); - } -#endif -} - static gboolean check_socket (GSocket *socket, GError **error) @@ -328,6 +282,13 @@ check_socket (GSocket *socket, return FALSE; } + return TRUE; +} + +static gboolean +check_timeout (GSocket *socket, + GError **error) +{ if (socket->priv->timed_out) { socket->priv->timed_out = FALSE; @@ -498,7 +459,7 @@ g_socket (gint domain, return fd; /* It's possible that libc has SOCK_CLOEXEC but the kernel does not */ - if (fd < 0 && errno == EINVAL) + if (fd < 0 && (errno == EINVAL || errno == EPROTOTYPE)) #endif fd = socket (domain, type, protocol); @@ -591,12 +552,39 @@ g_socket_constructed (GObject *object) socket->priv->protocol, &socket->priv->construct_error); - /* Always use native nonblocking sockets, as - windows sets sockets to nonblocking automatically - in certain operations. This way we make things work - the same on all platforms */ if (socket->priv->fd != -1) - set_fd_nonblocking (socket->priv->fd); + { +#ifndef G_OS_WIN32 + GError *error = NULL; +#else + gulong arg; +#endif + + /* Always use native nonblocking sockets, as Windows sets sockets to + * nonblocking automatically in certain operations. This way we make + * things work the same on all platforms. + */ +#ifndef G_OS_WIN32 + if (!g_unix_set_fd_nonblocking (socket->priv->fd, TRUE, &error)) + { + g_warning ("Error setting socket nonblocking: %s", error->message); + g_clear_error (&error); + } +#else + arg = TRUE; + + if (ioctlsocket (socket->priv->fd, FIONBIO, &arg) == SOCKET_ERROR) + { + int errsv = get_socket_errno (); + g_warning ("Error setting socket status flags: %s", socket_strerror (errsv)); + } +#endif + +#ifdef SO_NOSIGPIPE + /* See note about SIGPIPE below. */ + g_socket_set_option (socket, SOL_SOCKET, SO_NOSIGPIPE, TRUE, NULL); +#endif + } } static void @@ -759,6 +747,7 @@ g_socket_finalize (GObject *object) } g_assert (socket->priv->requested_conditions == NULL); + g_mutex_clear (&socket->priv->win32_source_lock); #endif for (i = 0; i < RECV_ADDR_CACHE_SIZE; i++) @@ -783,6 +772,11 @@ g_socket_class_init (GSocketClass *klass) /* There is no portable, thread-safe way to avoid having the process * be killed by SIGPIPE when calling send() or sendmsg(), so we are * forced to simply ignore the signal process-wide. + * + * Even if we ignore it though, gdb will still stop if the app + * receives a SIGPIPE, which can be confusing and annoying. So when + * possible, we also use MSG_NOSIGNAL / SO_NOSIGPIPE elsewhere to + * prevent the signal from occurring at all. */ signal (SIGPIPE, SIG_IGN); #endif @@ -895,14 +889,14 @@ g_socket_class_init (GSocketClass *klass) /** * GSocket:broadcast: * - * Whether the socket should allow sending to and receiving from broadcast addresses. + * Whether the socket should allow sending to broadcast addresses. * * Since: 2.32 */ g_object_class_install_property (gobject_class, PROP_BROADCAST, g_param_spec_boolean ("broadcast", P_("Broadcast"), - P_("Whether to allow sending to and receiving from broadcast addresses"), + P_("Whether to allow sending to broadcast addresses"), FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); @@ -970,6 +964,7 @@ g_socket_init (GSocket *socket) socket->priv->construct_error = NULL; #ifdef G_OS_WIN32 socket->priv->event = WSA_INVALID_EVENT; + g_mutex_init (&socket->priv->win32_source_lock); #endif } @@ -1387,7 +1382,7 @@ g_socket_set_ttl (GSocket *socket, * * Gets the broadcast setting on @socket; if %TRUE, * it is possible to send packets to broadcast - * addresses or receive from broadcast addresses. + * addresses. * * Returns: the broadcast setting on @socket * @@ -1415,11 +1410,11 @@ g_socket_get_broadcast (GSocket *socket) /** * g_socket_set_broadcast: * @socket: a #GSocket. - * @broadcast: whether @socket should allow sending to and receiving - * from broadcast addresses + * @broadcast: whether @socket should allow sending to broadcast + * addresses * - * Sets whether @socket should allow sending to and receiving from - * broadcast addresses. This is %FALSE by default. + * Sets whether @socket should allow sending to broadcast addresses. + * This is %FALSE by default. * * Since: 2.32 */ @@ -1853,14 +1848,20 @@ g_socket_listen (GSocket *socket, * In certain situations, you may also want to bind a socket that will be * used to initiate connections, though this is not normally required. * - * @allow_reuse should be %TRUE for server sockets (sockets that you will - * eventually call g_socket_accept() on), and %FALSE for client sockets. - * (Specifically, if it is %TRUE, then g_socket_bind() will set the - * %SO_REUSEADDR flag on the socket, allowing it to bind @address even if - * that address was previously used by another socket that has not yet been - * fully cleaned-up by the kernel. Failing to set this flag on a server - * socket may cause the bind call to return %G_IO_ERROR_ADDRESS_IN_USE if - * the server program is stopped and then immediately restarted.) + * If @socket is a TCP socket, then @allow_reuse controls the setting + * of the `SO_REUSEADDR` socket option; normally it should be %TRUE for + * server sockets (sockets that you will eventually call + * g_socket_accept() on), and %FALSE for client sockets. (Failing to + * set this flag on a server socket may cause g_socket_bind() to return + * %G_IO_ERROR_ADDRESS_IN_USE if the server program is stopped and then + * immediately restarted.) + * + * If @socket is a UDP socket, then @allow_reuse determines whether or + * not other UDP sockets can be bound to the same address at the same + * time. In particular, you can have several UDP sockets bound to the + * same address, and they will all receive all of the multicast and + * broadcast packets sent to that address. (The behavior of unicast + * UDP packets to an address with multiple listeners is not defined.) * * Returns: %TRUE on success, %FALSE on error. * @@ -1873,27 +1874,48 @@ g_socket_bind (GSocket *socket, GError **error) { struct sockaddr_storage addr; + gboolean so_reuseaddr; +#ifdef SO_REUSEPORT + gboolean so_reuseport; +#endif g_return_val_if_fail (G_IS_SOCKET (socket) && G_IS_SOCKET_ADDRESS (address), FALSE); if (!check_socket (socket, error)) return FALSE; - /* SO_REUSEADDR on Windows means something else and is not what we want. - It always allows the unix variant of SO_REUSEADDR anyway */ -#ifndef G_OS_WIN32 - { - reuse_address = !!reuse_address; - /* Ignore errors here, the only likely error is "not supported", and - this is a "best effort" thing mainly */ - g_socket_set_option (socket, SOL_SOCKET, SO_REUSEADDR, - reuse_address, NULL); - } -#endif - if (!g_socket_address_to_native (address, &addr, sizeof addr, error)) return FALSE; + /* On Windows, SO_REUSEADDR has the semantics we want for UDP + * sockets, but has nasty side effects we don't want for TCP + * sockets. + * + * On other platforms, we set SO_REUSEPORT, if it exists, for + * UDP sockets, and SO_REUSEADDR for all sockets, hoping that + * if SO_REUSEPORT doesn't exist, then SO_REUSEADDR will have + * the desired semantics on UDP (as it does on Linux, although + * Linux has SO_REUSEPORT too as of 3.9). + */ + +#ifdef G_OS_WIN32 + so_reuseaddr = reuse_address && (socket->priv->type == G_SOCKET_TYPE_DATAGRAM); +#else + so_reuseaddr = !!reuse_address; +#endif + +#ifdef SO_REUSEPORT + so_reuseport = reuse_address && (socket->priv->type == G_SOCKET_TYPE_DATAGRAM); +#endif + + /* Ignore errors here, the only likely error is "not supported", and + * this is a "best effort" thing mainly. + */ + g_socket_set_option (socket, SOL_SOCKET, SO_REUSEADDR, so_reuseaddr, NULL); +#ifdef SO_REUSEPORT + g_socket_set_option (socket, SOL_SOCKET, SO_REUSEPORT, so_reuseport, NULL); +#endif + if (bind (socket->priv->fd, (struct sockaddr *) &addr, g_socket_address_get_native_size (address)) < 0) { @@ -1907,6 +1929,60 @@ g_socket_bind (GSocket *socket, return TRUE; } +#if !defined(HAVE_IF_NAMETOINDEX) && defined(G_OS_WIN32) +static guint +if_nametoindex (const gchar *iface) +{ + PIP_ADAPTER_ADDRESSES addresses = NULL, p; + gulong addresses_len = 0; + guint idx = 0; + DWORD res; + + res = GetAdaptersAddresses (AF_UNSPEC, 0, NULL, NULL, &addresses_len); + if (res != NO_ERROR && res != ERROR_BUFFER_OVERFLOW) + { + if (res == ERROR_NO_DATA) + errno = ENXIO; + else + errno = EINVAL; + return 0; + } + + addresses = g_malloc (addresses_len); + res = GetAdaptersAddresses (AF_UNSPEC, 0, NULL, addresses, &addresses_len); + + if (res != NO_ERROR) + { + g_free (addresses); + if (res == ERROR_NO_DATA) + errno = ENXIO; + else + errno = EINVAL; + return 0; + } + + p = addresses; + while (p) + { + if (strcmp (p->AdapterName, iface) == 0) + { + idx = p->IfIndex; + break; + } + p = p->Next; + } + + if (p == NULL) + errno = ENXIO; + + g_free (addresses); + + return idx; +} + +#define HAVE_IF_NAMETOINDEX 1 +#endif + static gboolean g_socket_multicast_group_operation (GSocket *socket, GInetAddress *group, @@ -1942,6 +2018,11 @@ g_socket_multicast_group_operation (GSocket *socket, mc_req.imr_ifindex = if_nametoindex (iface); else mc_req.imr_ifindex = 0; /* Pick any. */ +#elif defined(G_OS_WIN32) + if (iface) + mc_req.imr_interface.s_addr = g_htonl (if_nametoindex (iface)); + else + mc_req.imr_interface.s_addr = g_htonl (INADDR_ANY); #else mc_req.imr_interface.s_addr = g_htonl (INADDR_ANY); #endif @@ -2144,6 +2225,9 @@ g_socket_accept (GSocket *socket, if (!check_socket (socket, error)) return NULL; + if (!check_timeout (socket, error)) + return NULL; + while (TRUE) { if (socket->priv->blocking && @@ -2340,6 +2424,9 @@ g_socket_check_connect_result (GSocket *socket, if (!check_socket (socket, error)) return FALSE; + if (!check_timeout (socket, error)) + return FALSE; + if (!g_socket_get_option (socket, SOL_SOCKET, SO_ERROR, &value, error)) { g_prefix_error (error, _("Unable to get pending error: ")); @@ -2368,24 +2455,56 @@ g_socket_check_connect_result (GSocket *socket, * * Get the amount of data pending in the OS input buffer. * + * If @socket is a UDP or SCTP socket, this will return the size of + * just the next packet, even if additional packets are buffered after + * that one. + * + * Note that on Windows, this function is rather inefficient in the + * UDP case, and so if you know any plausible upper bound on the size + * of the incoming packet, it is better to just do a + * g_socket_receive() with a buffer of that size, rather than calling + * g_socket_get_available_bytes() first and then doing a receive of + * exactly the right size. + * * Returns: the number of bytes that can be read from the socket - * without blocking or -1 on error. + * without blocking or truncating, or -1 on error. * * Since: 2.32 */ gssize g_socket_get_available_bytes (GSocket *socket) { - gulong avail = 0; +#ifdef G_OS_WIN32 + const gint bufsize = 64 * 1024; + static guchar *buf = NULL; + u_long avail; +#else + gint avail; +#endif g_return_val_if_fail (G_IS_SOCKET (socket), -1); -#ifndef G_OS_WIN32 +#if defined (SO_NREAD) + if (!g_socket_get_option (socket, SOL_SOCKET, SO_NREAD, &avail, NULL)) + return -1; +#elif !defined (G_OS_WIN32) if (ioctl (socket->priv->fd, FIONREAD, &avail) < 0) - return -1; + avail = -1; #else - if (ioctlsocket (socket->priv->fd, FIONREAD, &avail) == SOCKET_ERROR) - return -1; + if (socket->priv->type == G_SOCKET_TYPE_DATAGRAM) + { + if (G_UNLIKELY (g_once_init_enter (&buf))) + g_once_init_leave (&buf, g_malloc (bufsize)); + + avail = recv (socket->priv->fd, buf, bufsize, MSG_PEEK); + if (avail == -1 && get_socket_errno () == WSAEWOULDBLOCK) + avail = 0; + } + else + { + if (ioctlsocket (socket->priv->fd, FIONREAD, &avail) < 0) + avail = -1; + } #endif return avail; @@ -2475,6 +2594,9 @@ g_socket_receive_with_blocking (GSocket *socket, if (!check_socket (socket, error)) return -1; + if (!check_timeout (socket, error)) + return -1; + if (g_cancellable_set_error_if_cancelled (cancellable, error)) return -1; @@ -2565,10 +2687,7 @@ g_socket_receive_from (GSocket *socket, error); } -/* Although we ignore SIGPIPE, gdb will still stop if the app receives - * one, which can be confusing and annoying. So if possible, we want - * to suppress the signal entirely. - */ +/* See the comment about SIGPIPE above. */ #ifdef MSG_NOSIGNAL #define G_SOCKET_DEFAULT_SEND_FLAGS MSG_NOSIGNAL #else @@ -2650,6 +2769,9 @@ g_socket_send_with_blocking (GSocket *socket, if (!check_socket (socket, error)) return -1; + if (!check_timeout (socket, error)) + return -1; + if (g_cancellable_set_error_if_cancelled (cancellable, error)) return -1; @@ -2988,24 +3110,28 @@ static void add_condition_watch (GSocket *socket, GIOCondition *condition) { + g_mutex_lock (&socket->priv->win32_source_lock); g_assert (g_list_find (socket->priv->requested_conditions, condition) == NULL); socket->priv->requested_conditions = g_list_prepend (socket->priv->requested_conditions, condition); update_select_events (socket); + g_mutex_unlock (&socket->priv->win32_source_lock); } static void remove_condition_watch (GSocket *socket, GIOCondition *condition) { + g_mutex_lock (&socket->priv->win32_source_lock); g_assert (g_list_find (socket->priv->requested_conditions, condition) != NULL); socket->priv->requested_conditions = g_list_remove (socket->priv->requested_conditions, condition); update_select_events (socket); + g_mutex_unlock (&socket->priv->win32_source_lock); } static GIOCondition @@ -3080,57 +3206,35 @@ update_condition (GSocket *socket) typedef struct { GSource source; +#ifdef G_OS_WIN32 GPollFD pollfd; +#else + gpointer fd_tag; +#endif GSocket *socket; GIOCondition condition; - GCancellable *cancellable; - GPollFD cancel_pollfd; - gint64 timeout_time; } GSocketSource; +#ifdef G_OS_WIN32 static gboolean -socket_source_prepare (GSource *source, - gint *timeout) +socket_source_prepare_win32 (GSource *source, + gint *timeout) { GSocketSource *socket_source = (GSocketSource *)source; - if (g_cancellable_is_cancelled (socket_source->cancellable)) - return TRUE; - - if (socket_source->timeout_time) - { - gint64 now; - - 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; - *timeout = 0; - return TRUE; - } - } - else - *timeout = -1; + *timeout = -1; -#ifdef G_OS_WIN32 - socket_source->pollfd.revents = update_condition (socket_source->socket); -#endif - - if ((socket_source->condition & socket_source->pollfd.revents) != 0) - return TRUE; - - return FALSE; + return (update_condition (socket_source->socket) & socket_source->condition) != 0; } static gboolean -socket_source_check (GSource *source) +socket_source_check_win32 (GSource *source) { int timeout; - return socket_source_prepare (source, &timeout); + return socket_source_prepare_win32 (source, &timeout); } +#endif static gboolean socket_source_dispatch (GSource *source, @@ -3140,24 +3244,29 @@ socket_source_dispatch (GSource *source, GSocketSourceFunc func = (GSocketSourceFunc)callback; GSocketSource *socket_source = (GSocketSource *)source; GSocket *socket = socket_source->socket; + gint64 timeout; + guint events; gboolean ret; #ifdef G_OS_WIN32 - socket_source->pollfd.revents = update_condition (socket_source->socket); + events = update_condition (socket_source->socket); +#else + events = g_source_query_unix_fd (source, socket_source->fd_tag); #endif - if (socket_source->socket->priv->timed_out) - socket_source->pollfd.revents |= socket_source->condition & (G_IO_IN | G_IO_OUT); - ret = (*func) (socket, - socket_source->pollfd.revents & socket_source->condition, - user_data); + timeout = g_source_get_ready_time (source); + if (timeout >= 0 && timeout < g_source_get_time (source)) + { + socket->priv->timed_out = TRUE; + events |= (G_IO_IN | G_IO_OUT); + } - if (socket->priv->timeout) - socket_source->timeout_time = g_get_monotonic_time () + - socket->priv->timeout * 1000000; + ret = (*func) (socket, events & socket_source->condition, user_data); + if (socket->priv->timeout) + g_source_set_ready_time (source, g_get_monotonic_time () + socket->priv->timeout * 1000000); else - socket_source->timeout_time = 0; + g_source_set_ready_time (source, -1); return ret; } @@ -3175,12 +3284,6 @@ socket_source_finalize (GSource *source) #endif g_object_unref (socket); - - if (socket_source->cancellable) - { - g_cancellable_release_fd (socket_source->cancellable); - g_object_unref (socket_source->cancellable); - } } static gboolean @@ -3213,8 +3316,12 @@ socket_source_closure_callback (GSocket *socket, static GSourceFuncs socket_source_funcs = { - socket_source_prepare, - socket_source_check, +#ifdef G_OS_WIN32 + socket_source_prepare_win32, + socket_source_check_win32, +#else + NULL, NULL, /* check, prepare */ +#endif socket_source_dispatch, socket_source_finalize, (GSourceFunc)socket_source_closure_callback, @@ -3238,7 +3345,7 @@ socket_source_new (GSocket *socket, } #endif - condition |= G_IO_HUP | G_IO_ERR; + condition |= G_IO_HUP | G_IO_ERR | G_IO_NVAL; source = g_source_new (&socket_source_funcs, sizeof (GSocketSource)); g_source_set_name (source, "GSocket"); @@ -3247,30 +3354,30 @@ socket_source_new (GSocket *socket, socket_source->socket = g_object_ref (socket); socket_source->condition = condition; - if (g_cancellable_make_pollfd (cancellable, - &socket_source->cancel_pollfd)) + if (cancellable) { - socket_source->cancellable = g_object_ref (cancellable); - g_source_add_poll (source, &socket_source->cancel_pollfd); + GSource *cancellable_source; + + cancellable_source = g_cancellable_source_new (cancellable); + g_source_add_child_source (source, cancellable_source); + g_source_set_dummy_callback (cancellable_source); + g_source_unref (cancellable_source); } #ifdef G_OS_WIN32 add_condition_watch (socket, &socket_source->condition); socket_source->pollfd.fd = (gintptr) socket->priv->event; -#else - socket_source->pollfd.fd = socket->priv->fd; -#endif - socket_source->pollfd.events = condition; socket_source->pollfd.revents = 0; g_source_add_poll (source, &socket_source->pollfd); +#else + socket_source->fd_tag = g_source_add_unix_fd (source, socket->priv->fd, condition); +#endif if (socket->priv->timeout) - socket_source->timeout_time = g_get_monotonic_time () + - socket->priv->timeout * 1000000; - + g_source_set_ready_time (source, g_get_monotonic_time () + socket->priv->timeout * 1000000); else - socket_source->timeout_time = 0; + g_source_set_ready_time (source, -1); return source; } @@ -3281,8 +3388,9 @@ socket_source_new (GSocket *socket, * @condition: a #GIOCondition mask to monitor * @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. + * Creates a #GSource that can be attached to a %GMainContext to monitor + * for the availability of the specified @condition on the socket. The #GSource + * keeps a reference to the @socket. * * The callback on the source is of the #GSocketSourceFunc type. * @@ -3550,7 +3658,7 @@ g_socket_condition_timed_wait (GSocket *socket, if (timeout != -1) { - timeout -= (g_get_monotonic_time () - start_time) * 1000; + timeout -= (g_get_monotonic_time () - start_time) / 1000; if (timeout < 0) timeout = 0; } @@ -3596,7 +3704,7 @@ g_socket_condition_timed_wait (GSocket *socket, * then @vectors is assumed to be terminated by a #GOutputVector with a * %NULL buffer pointer.) The #GOutputVector structs describe the buffers * that the sent data will be gathered from. Using multiple - * #GOutputVectors is more memory-efficient than manually copying + * #GOutputVectors is more memory-efficient than manually copying * data from multiple sources into a single buffer, and more * network-efficient than making multiple calls to g_socket_send(). * @@ -3642,10 +3750,18 @@ g_socket_send_message (GSocket *socket, char zero; g_return_val_if_fail (G_IS_SOCKET (socket), -1); + g_return_val_if_fail (address == NULL || G_IS_SOCKET_ADDRESS (address), -1); + g_return_val_if_fail (num_vectors == 0 || vectors != NULL, -1); + g_return_val_if_fail (num_messages == 0 || messages != NULL, -1); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), -1); + g_return_val_if_fail (error == NULL || *error == NULL, -1); if (!check_socket (socket, error)) return -1; + if (!check_timeout (socket, error)) + return -1; + if (g_cancellable_set_error_if_cancelled (cancellable, error)) return -1; @@ -4022,6 +4138,9 @@ g_socket_receive_message (GSocket *socket, if (!check_socket (socket, error)) return -1; + if (!check_timeout (socket, error)) + return -1; + if (g_cancellable_set_error_if_cancelled (cancellable, error)) return -1; @@ -4334,42 +4453,72 @@ g_socket_get_credentials (GSocket *socket, ret = NULL; -#if defined(__linux__) || defined(__OpenBSD__) +#if G_CREDENTIALS_SOCKET_GET_CREDENTIALS_SUPPORTED + +#ifdef SO_PEERCRED { - socklen_t optlen; -#if defined(__linux__) - struct ucred native_creds; - optlen = sizeof (struct ucred); -#elif defined(__OpenBSD__) - struct sockpeercred native_creds; - optlen = sizeof (struct sockpeercred); -#endif + guint8 native_creds_buf[G_CREDENTIALS_NATIVE_SIZE]; + socklen_t optlen = sizeof (native_creds_buf); + if (getsockopt (socket->priv->fd, SOL_SOCKET, SO_PEERCRED, - (void *)&native_creds, - &optlen) != 0) + native_creds_buf, + &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)); + ret = g_credentials_new (); + g_credentials_set_native (ret, + G_CREDENTIALS_NATIVE_TYPE, + native_creds_buf); } - else + } +#elif G_CREDENTIALS_USE_NETBSD_UNPCBID + { + struct unpcbid cred; + socklen_t optlen = sizeof (cred); + + if (getsockopt (socket->priv->fd, + 0, + LOCAL_PEEREID, + &cred, + &optlen) == 0) { ret = g_credentials_new (); g_credentials_set_native (ret, -#if defined(__linux__) - G_CREDENTIALS_TYPE_LINUX_UCRED, -#elif defined(__OpenBSD__) - G_CREDENTIALS_TYPE_OPENBSD_SOCKPEERCRED, -#endif - &native_creds); + G_CREDENTIALS_NATIVE_TYPE, + &cred); + } + } +#elif G_CREDENTIALS_USE_SOLARIS_UCRED + { + ucred_t *ucred = NULL; + + if (getpeerucred (socket->priv->fd, &ucred) == 0) + { + ret = g_credentials_new (); + g_credentials_set_native (ret, + G_CREDENTIALS_TYPE_SOLARIS_UCRED, + ucred); + ucred_free (ucred); } } #else + #error "G_CREDENTIALS_SOCKET_GET_CREDENTIALS_SUPPORTED is set but this is no code for this platform" +#endif + + if (!ret) + { + int errsv = get_socket_errno (); + + g_set_error (error, + G_IO_ERROR, + socket_io_error_from_errno (errsv), + _("Unable to read socket credentials: %s"), + socket_strerror (errsv)); + } + +#else + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, @@ -4382,17 +4531,16 @@ g_socket_get_credentials (GSocket *socket, /** * g_socket_get_option: * @socket: a #GSocket - * @level: the "API level" of the option (eg, SOL_SOCKET) - * @optname: the "name" of the option (eg, SO_BROADCAST) + * @level: the "API level" of the option (eg, `SOL_SOCKET`) + * @optname: the "name" of the option (eg, `SO_BROADCAST`) * @value: (out): return location for the option value * @error: #GError for error reporting, or %NULL to ignore. * * Gets the value of an integer-valued option on @socket, as with - * getsockopt (). (If you need to fetch a - * non-integer-valued option, you will need to call - * getsockopt () directly.) + * getsockopt(). (If you need to fetch a non-integer-valued option, + * you will need to call getsockopt() directly.) * - * The <gio/gnetworking.h> + * The [][gio-gnetworking.h] * header pulls in system headers that will define most of the * standard/portable socket options. For unusual socket protocols or * platform-dependent options, you may need to include additional @@ -4403,9 +4551,8 @@ g_socket_get_credentials (GSocket *socket, * g_socket_get_option() will handle the conversion internally. * * Returns: success or failure. On failure, @error will be set, and - * the system error value (errno or - * WSAGetLastError ()) will still be set to the - * result of the getsockopt () call. + * the system error value (`errno` or WSAGetLastError()) will still + * be set to the result of the getsockopt() call. * * Since: 2.36 */ @@ -4451,26 +4598,24 @@ g_socket_get_option (GSocket *socket, /** * g_socket_set_option: * @socket: a #GSocket - * @level: the "API level" of the option (eg, SOL_SOCKET) - * @optname: the "name" of the option (eg, SO_BROADCAST) + * @level: the "API level" of the option (eg, `SOL_SOCKET`) + * @optname: the "name" of the option (eg, `SO_BROADCAST`) * @value: the value to set the option to * @error: #GError for error reporting, or %NULL to ignore. * * Sets the value of an integer-valued option on @socket, as with - * setsockopt (). (If you need to set a - * non-integer-valued option, you will need to call - * setsockopt () directly.) + * setsockopt(). (If you need to set a non-integer-valued option, + * you will need to call setsockopt() directly.) * - * The <gio/gnetworking.h> + * The [][gio-gnetworking.h] * header pulls in system headers that will define most of the * standard/portable socket options. For unusual socket protocols or * platform-dependent options, you may need to include additional * headers. * * Returns: success or failure. On failure, @error will be set, and - * the system error value (errno or - * WSAGetLastError ()) will still be set to the - * result of the setsockopt () call. + * the system error value (`errno` or WSAGetLastError()) will still + * be set to the result of the setsockopt() call. * * Since: 2.36 */