X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gio%2Fgsocket.c;h=4d863cecdf56e8bb9b2be7ef081136746aefe909;hb=7a1aaaa1fa02679ecf335a19fffe3f55505921b5;hp=714e0b3f227ae237c0089b819e6e113f8f7e169b;hpb=5a269e5a90181a5cafce90e7e5d7bc4f42f47f52;p=platform%2Fupstream%2Fglib.git diff --git a/gio/gsocket.c b/gio/gsocket.c index 714e0b3..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 @@ -70,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. @@ -105,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 @@ -119,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 */ @@ -203,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 } @@ -278,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) @@ -330,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; @@ -593,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 @@ -786,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 @@ -1858,12 +1849,12 @@ g_socket_listen (GSocket *socket, * used to initiate connections, though this is not normally required. * * 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.) + * 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 @@ -2234,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 && @@ -2430,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: ")); @@ -2480,8 +2477,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); @@ -2492,10 +2491,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; @@ -2585,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; @@ -2675,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 @@ -2760,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; @@ -3194,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, @@ -3254,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; } @@ -3289,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 @@ -3327,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, @@ -3361,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; } @@ -3395,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. * @@ -3664,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; } @@ -3710,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(). * @@ -3756,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; @@ -4136,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; @@ -4467,6 +4472,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; @@ -4509,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 @@ -4530,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 */ @@ -4578,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 */