X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gio%2Fgsocket.c;h=f06e49bccda6b683a75493a9c7756b76779de149;hb=ffe286e647ce9ba9bb8e1631ba3cf0194038f438;hp=7664f61d280dcf3bdf5817a94468c4211ca62ecc;hpb=323242578524a1b6355d8451015b14ca75aa0afa;p=platform%2Fupstream%2Fglib.git diff --git a/gio/gsocket.c b/gio/gsocket.c index 7664f61..f06e49b 100644 --- a/gio/gsocket.c +++ b/gio/gsocket.c @@ -68,7 +68,7 @@ * 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. @@ -117,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 */ @@ -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 } @@ -328,6 +308,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; @@ -2232,6 +2219,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 && @@ -2428,6 +2418,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: ")); @@ -2478,8 +2471,10 @@ g_socket_get_available_bytes (GSocket *socket) #ifdef G_OS_WIN32 const gint bufsize = 64 * 1024; static guchar *buf = NULL; -#endif + u_long avail; +#else gint avail; +#endif g_return_val_if_fail (G_IS_SOCKET (socket), -1); @@ -2490,10 +2485,20 @@ g_socket_get_available_bytes (GSocket *socket) if (ioctl (socket->priv->fd, FIONREAD, &avail) < 0) avail = -1; #else - if (G_UNLIKELY (g_once_init_enter (&buf))) - g_once_init_leave (&buf, g_malloc (bufsize)); + 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); + 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; @@ -2583,6 +2588,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; @@ -2758,6 +2766,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; @@ -3192,57 +3203,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, @@ -3252,24 +3241,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); + } + + ret = (*func) (socket, events & socket_source->condition, user_data); 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 ret; } @@ -3287,12 +3281,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 @@ -3325,8 +3313,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, @@ -3359,30 +3351,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; } @@ -3393,8 +3385,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. * @@ -3662,7 +3655,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; } @@ -3754,10 +3747,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; @@ -4134,6 +4135,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; @@ -4465,6 +4469,23 @@ g_socket_get_credentials (GSocket *socket, native_creds_buf); } } +#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, + G_CREDENTIALS_NATIVE_TYPE, + &cred); + } + } #elif G_CREDENTIALS_USE_SOLARIS_UCRED { ucred_t *ucred = NULL; @@ -4516,7 +4537,7 @@ g_socket_get_credentials (GSocket *socket, * 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 @@ -4583,7 +4604,7 @@ g_socket_get_option (GSocket *socket, * 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