X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gio%2Fgsocket.c;h=aa0a39cc853483d2640c3618db1883ef45462be1;hb=0729260141bb585943ad1c6efa8ab7ee9058b0aa;hp=a10a92b9ffe901346b2e14e42a43f018354f7db3;hpb=14d53dcfa8a781a79bd61f50bb73c4a1b3b7857e;p=platform%2Fupstream%2Fglib.git diff --git a/gio/gsocket.c b/gio/gsocket.c index a10a92b..aa0a39c 100644 --- a/gio/gsocket.c +++ b/gio/gsocket.c @@ -26,7 +26,8 @@ */ #include "config.h" -#include "glib.h" + +#include "gsocket.h" #include #include @@ -34,29 +35,28 @@ #include #ifndef G_OS_WIN32 -# include -# include -# include # include # include -# include -#else -# include -# include #endif -#include "gsocket.h" +#ifdef HAVE_SYS_UIO_H +#include +#endif + #include "gcancellable.h" #include "gioenumtypes.h" +#include "ginetaddress.h" #include "ginitable.h" -#include "gasynchelper.h" #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 @@ -65,7 +65,7 @@ * * 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. - * It supports both the unix socket implementations and winsock2 on Windows. + * It supports both the UNIX socket implementations and winsock2 on Windows. * * #GSocket is the platform independent base upon which the higher level * network primitives are based. Applications are not typically meant to @@ -111,7 +111,7 @@ * if it tries to write to %stdout after it has been closed. * * Since: 2.22 - **/ + */ static void g_socket_initable_iface_init (GInitableIface *iface); static gboolean g_socket_initable_init (GInitable *initable, @@ -133,7 +133,8 @@ enum PROP_LISTEN_BACKLOG, PROP_KEEPALIVE, PROP_LOCAL_ADDRESS, - PROP_REMOTE_ADDRESS + PROP_REMOTE_ADDRESS, + PROP_TIMEOUT }; struct _GSocketPrivate @@ -143,13 +144,17 @@ struct _GSocketPrivate GSocketProtocol protocol; gint fd; gint listen_backlog; + guint timeout; GError *construct_error; + GSocketAddress *remote_address; guint inited : 1; guint blocking : 1; guint keepalive : 1; guint closed : 1; guint connected : 1; guint listening : 1; + guint timed_out : 1; + guint connect_pending : 1; #ifdef G_OS_WIN32 WSAEVENT event; int current_events; @@ -209,20 +214,13 @@ socket_strerror (int err) #ifndef G_OS_WIN32 return g_strerror (err); #else - static GStaticPrivate msg_private = G_STATIC_PRIVATE_INIT; - char *buf, *msg; - - buf = g_static_private_get (&msg_private); - if (!buf) - { - buf = g_new (gchar, 128); - g_static_private_set (&msg_private, buf, g_free); - } + static GStaticPrivate last_msg = G_STATIC_PRIVATE_INIT; + char *msg; msg = g_win32_error_message (err); - strncpy (buf, msg, 128); - g_free (msg); - return buf; + g_static_private_set (&last_msg, msg, g_free); + + return msg; #endif } @@ -294,6 +292,15 @@ check_socket (GSocket *socket, _("Socket is already closed")); return FALSE; } + + if (socket->priv->timed_out) + { + socket->priv->timed_out = FALSE; + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT, + _("Socket I/O timed out")); + return FALSE; + } + return TRUE; } @@ -307,7 +314,8 @@ g_socket_details_from_fd (GSocket *socket) int value; int errsv; #ifdef G_OS_WIN32 - BOOL bool_val; + /* See bug #611756 */ + BOOL bool_val = FALSE; #else int bool_val; #endif @@ -370,13 +378,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) @@ -390,7 +419,14 @@ g_socket_details_from_fd (GSocket *socket) if (getsockopt (fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&bool_val, &optlen) == 0) { +#ifndef G_OS_WIN32 + /* Experimentation indicates that the SO_KEEPALIVE value is + * actually a char on Windows, even if documentation claims it + * to be a BOOL which is a typedef for int. So this g_assert() + * fails. See bug #611756. + */ g_assert (optlen == sizeof bool_val); +#endif socket->priv->keepalive = !!bool_val; } else @@ -443,9 +479,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) { @@ -548,6 +586,10 @@ g_socket_get_property (GObject *object, g_value_take_object (value, address); break; + case PROP_TIMEOUT: + g_value_set_uint (value, socket->priv->timeout); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } @@ -591,6 +633,10 @@ g_socket_set_property (GObject *object, g_socket_set_keepalive (socket, g_value_get_boolean (value)); break; + case PROP_TIMEOUT: + g_socket_set_timeout (socket, g_value_get_uint (value)); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } @@ -607,7 +653,16 @@ 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) + { + WSACloseEvent (socket->priv->event); + socket->priv->event = WSA_INVALID_EVENT; + } + g_assert (socket->priv->requested_conditions == NULL); #endif @@ -623,6 +678,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 @@ -645,7 +701,9 @@ g_socket_class_init (GSocketClass *klass) P_("The sockets address family"), G_TYPE_SOCKET_FAMILY, G_SOCKET_FAMILY_INVALID, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_TYPE, g_param_spec_enum ("type", @@ -653,15 +711,19 @@ g_socket_class_init (GSocketClass *klass) P_("The sockets type"), G_TYPE_SOCKET_TYPE, G_SOCKET_TYPE_STREAM, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_PROTOCOL, g_param_spec_enum ("protocol", - P_("Socket protocol"), - P_("The id of the protocol to use, or -1 for unknown"), + P_("Socket protocol"), + P_("The id of the protocol to use, or -1 for unknown"), G_TYPE_SOCKET_PROTOCOL, G_SOCKET_PROTOCOL_UNKNOWN, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_FD, g_param_spec_int ("fd", @@ -670,44 +732,68 @@ g_socket_class_init (GSocketClass *klass) G_MININT, G_MAXINT, -1, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_BLOCKING, g_param_spec_boolean ("blocking", P_("blocking"), P_("Whether or not I/O on this socket is blocking"), TRUE, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_LISTEN_BACKLOG, g_param_spec_int ("listen-backlog", P_("Listen backlog"), - P_("outstanding connections in the listen queue"), + P_("Outstanding connections in the listen queue"), 0, SOMAXCONN, 10, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_KEEPALIVE, g_param_spec_boolean ("keepalive", P_("Keep connection alive"), P_("Keep connection alive by sending periodic pings"), FALSE, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_LOCAL_ADDRESS, g_param_spec_object ("local-address", P_("Local address"), P_("The local address the socket is bound to"), G_TYPE_SOCKET_ADDRESS, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_REMOTE_ADDRESS, g_param_spec_object ("remote-address", P_("Remote address"), P_("The remote address the socket is connected to"), G_TYPE_SOCKET_ADDRESS, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + /** + * GSocket:timeout: + * + * The timeout in seconds on socket I/O + * + * Since: 2.26 + */ + g_object_class_install_property (gobject_class, PROP_TIMEOUT, + g_param_spec_uint ("timeout", + P_("Timeout"), + P_("The timeout in seconds on socket I/O"), + 0, + G_MAXUINT, + 0, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); } static void @@ -786,12 +872,12 @@ g_socket_initable_init (GInitable *initable, * Free the returned object with g_object_unref(). * * Since: 2.22 - **/ + */ GSocket * -g_socket_new (GSocketFamily family, - GSocketType type, - GSocketProtocol protocol, - GError **error) +g_socket_new (GSocketFamily family, + GSocketType type, + GSocketProtocol protocol, + GError **error) { return G_SOCKET (g_initable_new (G_TYPE_SOCKET, NULL, error, @@ -818,9 +904,9 @@ g_socket_new (GSocketFamily family, * Free the returned object with g_object_unref(). * * Since: 2.22 - **/ + */ GSocket * -g_socket_new_from_fd (gint fd, +g_socket_new_from_fd (gint fd, GError **error) { return G_SOCKET (g_initable_new (G_TYPE_SOCKET, @@ -844,7 +930,7 @@ g_socket_new_from_fd (gint fd, * is a GSocket level feature. * * Since: 2.22 - **/ + */ void g_socket_set_blocking (GSocket *socket, gboolean blocking) @@ -870,7 +956,7 @@ g_socket_set_blocking (GSocket *socket, * Returns: %TRUE if blocking I/O is used, %FALSE otherwise. * * Since: 2.22 - **/ + */ gboolean g_socket_get_blocking (GSocket *socket) { @@ -882,26 +968,29 @@ g_socket_get_blocking (GSocket *socket) /** * g_socket_set_keepalive: * @socket: a #GSocket. - * @keepalive: Whether to use try to keep the connection alive or not. + * @keepalive: Value for the keepalive flag + * + * Sets or unsets the %SO_KEEPALIVE flag on the underlying socket. When + * this flag is set on a socket, the system will attempt to verify that the + * remote socket endpoint is still present if a sufficiently long period of + * time passes with no data being exchanged. If the system is unable to + * verify the presence of the remote endpoint, it will automatically close + * the connection. * - * Setting @keepalive to %TRUE enables the sending of periodic ping requests - * on idle connections in order to keep the connection alive. This is only - * useful for connection oriented sockets. The exact period used between - * each ping is system and protocol dependent. + * This option is only functional on certain kinds of sockets. (Notably, + * %G_SOCKET_PROTOCOL_TCP sockets.) * - * Sending keepalive requests like this has a few disadvantages. For instance, - * it uses more network bandwidth, and it makes your application more sensitive - * to temporary outages in the network (i.e. if a cable is pulled your otherwise - * idle connection could be terminated, whereas otherwise it would survive unless - * actually used before the cable was reinserted). However, it is sometimes - * useful to ensure that connections are eventually terminated if e.g. the - * remote side is disconnected, so as to avoid leaking resources forever. + * The exact time between pings is system- and protocol-dependent, but will + * normally be at least two hours. Most commonly, you would set this flag + * on a server socket if you want to allow clients to remain idle for long + * periods of time, but also want to ensure that connections are eventually + * garbage-collected if clients crash or become unreachable. * * Since: 2.22 - **/ + */ void -g_socket_set_keepalive (GSocket *socket, - gboolean keepalive) +g_socket_set_keepalive (GSocket *socket, + gboolean keepalive) { int value; @@ -934,7 +1023,7 @@ g_socket_set_keepalive (GSocket *socket, * Returns: %TRUE if keepalive is active, %FALSE otherwise. * * Since: 2.22 - **/ + */ gboolean g_socket_get_keepalive (GSocket *socket) { @@ -953,9 +1042,9 @@ g_socket_get_keepalive (GSocket *socket) * Returns: the maximum number of pending connections. * * Since: 2.22 - **/ + */ gint -g_socket_get_listen_backlog (GSocket *socket) +g_socket_get_listen_backlog (GSocket *socket) { g_return_val_if_fail (G_IS_SOCKET (socket), 0); @@ -976,10 +1065,10 @@ g_socket_get_listen_backlog (GSocket *socket) * effect if called after that. * * Since: 2.22 - **/ + */ void g_socket_set_listen_backlog (GSocket *socket, - gint backlog) + gint backlog) { g_return_if_fail (G_IS_SOCKET (socket)); g_return_if_fail (!socket->priv->listening); @@ -992,6 +1081,66 @@ g_socket_set_listen_backlog (GSocket *socket, } /** + * g_socket_get_timeout: + * @socket: a #GSocket. + * + * Gets the timeout setting of the socket. For details on this, see + * g_socket_set_timeout(). + * + * Returns: the timeout in seconds + * + * Since: 2.26 + */ +guint +g_socket_get_timeout (GSocket *socket) +{ + g_return_val_if_fail (G_IS_SOCKET (socket), 0); + + return socket->priv->timeout; +} + +/** + * g_socket_set_timeout: + * @socket: a #GSocket. + * @timeout: the timeout for @socket, in seconds, or 0 for none + * + * Sets the time in seconds after which I/O operations on @socket will + * time out if they have not yet completed. + * + * On a blocking socket, this means that any blocking #GSocket + * operation will time out after @timeout seconds of inactivity, + * returning %G_IO_ERROR_TIMED_OUT. + * + * On a non-blocking socket, calls to g_socket_condition_wait() will + * also fail with %G_IO_ERROR_TIMED_OUT after the given time. Sources + * created with g_socket_create_source() will trigger after + * @timeout seconds of inactivity, with the requested condition + * set, at which point calling g_socket_receive(), g_socket_send(), + * g_socket_check_connect_result(), etc, will fail with + * %G_IO_ERROR_TIMED_OUT. + * + * If @timeout is 0 (the default), operations will never time out + * on their own. + * + * Note that if an I/O operation is interrupted by a signal, this may + * cause the timeout to be reset. + * + * Since: 2.26 + */ +void +g_socket_set_timeout (GSocket *socket, + guint timeout) +{ + g_return_if_fail (G_IS_SOCKET (socket)); + + if (timeout != socket->priv->timeout) + { + socket->priv->timeout = timeout; + g_object_notify (G_OBJECT (socket), "timeout"); + } +} + +/** * g_socket_get_family: * @socket: a #GSocket. * @@ -1000,7 +1149,7 @@ g_socket_set_listen_backlog (GSocket *socket, * Returns: a #GSocketFamily * * Since: 2.22 - **/ + */ GSocketFamily g_socket_get_family (GSocket *socket) { @@ -1018,7 +1167,7 @@ g_socket_get_family (GSocket *socket) * Returns: a #GSocketType * * Since: 2.22 - **/ + */ GSocketType g_socket_get_socket_type (GSocket *socket) { @@ -1037,7 +1186,7 @@ g_socket_get_socket_type (GSocket *socket) * Returns: a protocol id, or -1 if unknown * * Since: 2.22 - **/ + */ GSocketProtocol g_socket_get_protocol (GSocket *socket) { @@ -1059,7 +1208,7 @@ g_socket_get_protocol (GSocket *socket) * Returns: the file descriptor of the socket. * * Since: 2.22 - **/ + */ int g_socket_get_fd (GSocket *socket) { @@ -1077,11 +1226,11 @@ 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 - **/ + */ GSocketAddress * g_socket_get_local_address (GSocket *socket, GError **error) @@ -1110,11 +1259,11 @@ 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 - **/ + */ GSocketAddress * g_socket_get_remote_address (GSocket *socket, GError **error) @@ -1124,15 +1273,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); } /** @@ -1145,7 +1307,7 @@ g_socket_get_remote_address (GSocket *socket, * Returns: %TRUE if socket is connected, %FALSE otherwise. * * Since: 2.22 - **/ + */ gboolean g_socket_is_connected (GSocket *socket) { @@ -1171,7 +1333,7 @@ g_socket_is_connected (GSocket *socket) * Returns: %TRUE on success, %FALSE on error. * * Since: 2.22 - **/ + */ gboolean g_socket_listen (GSocket *socket, GError **error) @@ -1208,21 +1370,22 @@ g_socket_listen (GSocket *socket, * * It is generally required to bind to a local address before you can * receive connections. (See g_socket_listen() and g_socket_accept() ). - * - * If @allow_reuse is %TRUE this allows the bind call to succeed in some - * situation where it would otherwise return a %G_IO_ERROR_ADDRESS_IN_USE - * error. The main example is for a TCP server socket where there are - * outstanding connections in the WAIT state, which are generally safe - * to ignore. However, setting it to %TRUE doesn't mean the call will - * succeed if there is a socket actively bound to the address. - * - * In general, pass %TRUE if the socket will be used to accept connections, - * otherwise pass %FALSE. + * 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.) * * Returns: %TRUE on success, %FALSE on error. * * Since: 2.22 - **/ + */ gboolean g_socket_bind (GSocket *socket, GSocketAddress *address, @@ -1267,8 +1430,57 @@ g_socket_bind (GSocket *socket, } /** + * g_socket_speaks_ipv4: + * @socket: a #GSocket + * + * Checks if a socket is capable of speaking IPv4. + * + * IPv4 sockets are capable of speaking IPv4. On some operating systems + * and under some combinations of circumstances IPv6 sockets are also + * capable of speaking IPv4. See RFC 3493 section 3.7 for more + * information. + * + * No other types of sockets are currently considered as being capable + * of speaking IPv4. + * + * Returns: %TRUE if this socket can be used with IPv4. + * + * Since: 2.22 + **/ +gboolean +g_socket_speaks_ipv4 (GSocket *socket) +{ + switch (socket->priv->family) + { + case G_SOCKET_FAMILY_IPV4: + return TRUE; + + case G_SOCKET_FAMILY_IPV6: +#if defined (IPPROTO_IPV6) && defined (IPV6_V6ONLY) + { + guint sizeof_int = sizeof (int); + gint v6_only; + + if (getsockopt (socket->priv->fd, + IPPROTO_IPV6, IPV6_V6ONLY, + &v6_only, &sizeof_int) != 0) + return FALSE; + + return !v6_only; + } +#else + return FALSE; +#endif + + default: + return FALSE; + } +} + +/** * g_socket_accept: * @socket: a #GSocket. + * @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 @@ -1282,13 +1494,14 @@ g_socket_bind (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 - **/ + */ GSocket * g_socket_accept (GSocket *socket, + GCancellable *cancellable, GError **error) { GSocket *new_socket; @@ -1299,11 +1512,11 @@ g_socket_accept (GSocket *socket, if (!check_socket (socket, error)) return NULL; - while (1) + while (TRUE) { if (socket->priv->blocking && !g_socket_condition_wait (socket, - G_IO_IN, NULL, error)) + G_IO_IN, cancellable, error)) return NULL; if ((ret = accept (socket->priv->fd, NULL, 0)) < 0) @@ -1379,6 +1592,7 @@ g_socket_accept (GSocket *socket, * g_socket_connect: * @socket: a #GSocket. * @address: a #GSocketAddress specifying the remote address. + * @cancellable: (allow-none): a %GCancellable or %NULL * @error: #GError for error reporting, or %NULL to ignore. * * Connect the socket to the specified remote address. @@ -1388,8 +1602,9 @@ g_socket_accept (GSocket *socket, * the default address for g_socket_send() and discards all incoming datagrams * from other sources. * - * Generally connection oriented sockets can only connect once, but connection-less - * sockets can connect multiple times to change the default address. + * Generally connection oriented sockets can only connect once, but + * connection-less sockets can connect multiple times to change the + * default address. * * If the connect call needs to do network I/O it will block, unless * non-blocking I/O is enabled. Then %G_IO_ERROR_PENDING is returned @@ -1400,10 +1615,11 @@ g_socket_accept (GSocket *socket, * Returns: %TRUE if connected, %FALSE on error. * * Since: 2.22 - **/ + */ gboolean g_socket_connect (GSocket *socket, GSocketAddress *address, + GCancellable *cancellable, GError **error) { struct sockaddr_storage buffer; @@ -1416,6 +1632,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, @@ -1434,15 +1654,19 @@ g_socket_connect (GSocket *socket, { if (socket->priv->blocking) { - g_socket_condition_wait (socket, G_IO_OUT, NULL, NULL); - if (g_socket_check_connect_result (socket, error)) - break; - else - g_prefix_error (error, _("Error connecting: ")); + if (g_socket_condition_wait (socket, G_IO_OUT, cancellable, error)) + { + if (g_socket_check_connect_result (socket, error)) + break; + } + 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, @@ -1466,13 +1690,14 @@ g_socket_connect (GSocket *socket, * @socket: a #GSocket * @error: #GError for error reporting, or %NULL to ignore. * - * Checks and resets the pending connect error for the socket. This is - * used to check for errors when g_socket_connect() is used in non-blocking mode. + * Checks and resets the pending connect error for the socket. + * This is used to check for errors when g_socket_connect() is + * used in non-blocking mode. * * Returns: %TRUE if no error, %FALSE otherwise, setting @error to the error * * Since: 2.22 - **/ + */ gboolean g_socket_check_connect_result (GSocket *socket, GError **error) @@ -1480,6 +1705,9 @@ g_socket_check_connect_result (GSocket *socket, guint optlen; int value; + if (!check_socket (socket, error)) + return FALSE; + optlen = sizeof (value); if (getsockopt (socket->priv->fd, SOL_SOCKET, SO_ERROR, (void *)&value, &optlen) != 0) { @@ -1494,6 +1722,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; @@ -1502,35 +1735,77 @@ g_socket_check_connect_result (GSocket *socket, /** * g_socket_receive: * @socket: a #GSocket - * @buffer: a buffer to read data into (which should be at least count bytes long). - * @size: the number of bytes that will be read from the stream + * @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: (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 - * connection oriented sockets, it is identical to g_socket_receive_from() + * connection-oriented sockets; it is identical to g_socket_receive_from() * with @address set to %NULL. * - * If a message is too long to fit in @buffer, excess bytes may be discarded - * depending on the type of socket the message is received from. + * For %G_SOCKET_TYPE_DATAGRAM and %G_SOCKET_TYPE_SEQPACKET sockets, + * g_socket_receive() will always read either 0 or 1 complete messages from + * the socket. If the received message is too large to fit in @buffer, then + * the data beyond @size bytes will be discarded, without any explicit + * indication that this has occurred. + * + * For %G_SOCKET_TYPE_STREAM sockets, g_socket_receive() can return any + * number of bytes, up to @size. If more than @size bytes have been + * 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 of available data, wait for the %G_IO_IN - * condition. + * 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 * * Since: 2.22 - **/ + */ gssize g_socket_receive (GSocket *socket, gchar *buffer, gsize size, + 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 -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); @@ -1538,11 +1813,14 @@ g_socket_receive (GSocket *socket, if (!check_socket (socket, error)) return -1; + if (g_cancellable_set_error_if_cancelled (cancellable, error)) + return -1; + while (1) { - if (socket->priv->blocking && + if (blocking && !g_socket_condition_wait (socket, - G_IO_IN, NULL, error)) + G_IO_IN, cancellable, error)) return -1; if ((ret = recv (socket->priv->fd, buffer, size, 0)) < 0) @@ -1552,7 +1830,7 @@ g_socket_receive (GSocket *socket, if (errsv == EINTR) continue; - if (socket->priv->blocking) + if (blocking) { #ifdef WSAEWOULDBLOCK if (errsv == WSAEWOULDBLOCK) @@ -1584,8 +1862,10 @@ g_socket_receive (GSocket *socket, * g_socket_receive_from: * @socket: a #GSocket * @address: a pointer to a #GSocketAddress pointer, or %NULL - * @buffer: a buffer to read data into (which should be at least count bytes long). - * @size: the number of bytes that will be read from the stream + * @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: (allow-none): a %GCancellable or %NULL * @error: #GError for error reporting, or %NULL to ignore. * * Receive data (up to @size bytes) from a socket. @@ -1594,24 +1874,19 @@ g_socket_receive (GSocket *socket, * source address of the received packet. * @address is owned by the caller. * - * 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 of available data, wait for the %G_IO_IN - * condition. - * - * On error -1 is returned and @error is set accordingly. + * See g_socket_receive() for additional information. * * Returns: Number of bytes read, or -1 on error * * Since: 2.22 - **/ + */ gssize -g_socket_receive_from (GSocket *socket, - GSocketAddress **address, - gchar *buffer, - gsize size, - GError **error) +g_socket_receive_from (GSocket *socket, + GSocketAddress **address, + gchar *buffer, + gsize size, + GCancellable *cancellable, + GError **error) { GInputVector v; @@ -1622,42 +1897,85 @@ g_socket_receive_from (GSocket *socket, address, &v, 1, NULL, 0, NULL, + cancellable, 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. + */ +#ifdef MSG_NOSIGNAL +#define G_SOCKET_DEFAULT_SEND_FLAGS MSG_NOSIGNAL +#else +#define G_SOCKET_DEFAULT_SEND_FLAGS 0 +#endif + /** * 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: (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 mainly used by - * connection oriented sockets, it is identical to g_socket_send_to() - * with @address set to %NULL. + * Tries to send @size bytes from @buffer on the socket. This is + * mainly used by connection-oriented sockets; it is identical to + * g_socket_send_to() with @address set to %NULL. * * If the socket is in blocking mode the call will block until there is * space for the data in the socket queue. If there is no space available * and the socket is in non-blocking mode a %G_IO_ERROR_WOULD_BLOCK error - * will be returned. To be notified of available space, wait for the %G_IO_OUT - * condition. - * - * Note that on Windows you can't rely on a %G_IO_OUT condition - * not producing a %G_IO_ERROR_WOULD_BLOCK error, as this is how Winsock - * write notification works. However, robust apps should always be able to - * handle this since it can easily appear in other cases too. + * will be returned. To be notified when space is available, wait for the + * %G_IO_OUT condition. Note though that you may still receive + * %G_IO_ERROR_WOULD_BLOCK from g_socket_send() even if you were previously + * notified of a %G_IO_OUT condition. (On Windows in particular, this is + * very common due to the way the underlying APIs work.) * * On error -1 is returned and @error is set accordingly. * - * Returns: Number of bytes read, or -1 on error + * Returns: Number of bytes written (which may be less than @size), or -1 + * on error * * Since: 2.22 - **/ + */ +gssize +g_socket_send (GSocket *socket, + const gchar *buffer, + gsize size, + 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 (GSocket *socket, - const gchar *buffer, - gsize size, - GError **error) +g_socket_send_with_blocking (GSocket *socket, + const gchar *buffer, + gsize size, + gboolean blocking, + GCancellable *cancellable, + GError **error) { gssize ret; @@ -1666,14 +1984,17 @@ g_socket_send (GSocket *socket, if (!check_socket (socket, error)) return -1; + if (g_cancellable_set_error_if_cancelled (cancellable, error)) + return -1; + while (1) { - if (socket->priv->blocking && + if (blocking && !g_socket_condition_wait (socket, - G_IO_OUT, NULL, error)) + G_IO_OUT, cancellable, error)) return -1; - if ((ret = send (socket->priv->fd, buffer, size, 0)) < 0) + if ((ret = send (socket->priv->fd, buffer, size, G_SOCKET_DEFAULT_SEND_FLAGS)) < 0) { int errsv = get_socket_errno (); @@ -1685,7 +2006,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) @@ -1712,37 +2033,29 @@ 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: (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 * %NULL then the message is sent to the default receiver (set by * g_socket_connect()). * - * If the socket is in blocking mode the call will block until there is - * space for the data in the socket queue. If there is no space available - * and the socket is in non-blocking mode a %G_IO_ERROR_WOULD_BLOCK error - * will be returned. To be notified of available space, wait for the %G_IO_OUT - * condition. - * - * Note that on Windows you can't rely on a %G_IO_OUT condition - * not producing a %G_IO_ERROR_WOULD_BLOCK error, as this is how Winsock - * write notification works. However, robust apps should always be able to - * handle this since it can easily appear in other cases too. - * - * On error -1 is returned and @error is set accordingly. + * See g_socket_send() for additional information. * - * Returns: Number of bytes read, or -1 on error + * Returns: Number of bytes written (which may be less than @size), or -1 + * on error * * Since: 2.22 - **/ + */ gssize -g_socket_send_to (GSocket *socket, - GSocketAddress *address, - const gchar *buffer, - gsize size, - GError **error) +g_socket_send_to (GSocket *socket, + GSocketAddress *address, + const gchar *buffer, + gsize size, + GCancellable *cancellable, + GError **error) { GOutputVector v; @@ -1753,7 +2066,9 @@ g_socket_send_to (GSocket *socket, address, &v, 1, NULL, 0, - 0, error); + 0, + cancellable, + error); } /** @@ -1780,12 +2095,12 @@ g_socket_send_to (GSocket *socket, * Returns: %TRUE on success, %FALSE on error * * Since: 2.22 - **/ + */ gboolean -g_socket_shutdown (GSocket *socket, - gboolean shutdown_read, - gboolean shutdown_write, - GError **error) +g_socket_shutdown (GSocket *socket, + gboolean shutdown_read, + gboolean shutdown_write, + GError **error) { int how; @@ -1835,24 +2150,41 @@ g_socket_shutdown (GSocket *socket, * * Closes the socket, shutting down any active connection. * - * Closing a socket does not wait for all outstanding I/O operations to finish, - * so the caller should not rely on them to be guaranteed to complete even - * if the close returns with no error. + * Closing a socket does not wait for all outstanding I/O operations + * to finish, so the caller should not rely on them to be guaranteed + * to complete even if the close returns with no error. * - * Once the socket is closed, all other operations will return %G_IO_ERROR_CLOSED. - * Closing a stream multiple times will not return an error. + * Once the socket is closed, all other operations will return + * %G_IO_ERROR_CLOSED. Closing a socket multiple times will not + * return an error. * * Sockets will be automatically closed when the last reference * is dropped, but you might want to call this function to make sure * resources are released as early as possible. * + * Beware that due to the way that TCP works, it is possible for + * recently-sent data to be lost if either you close a socket while the + * %G_IO_IN condition is set, or else if the remote connection tries to + * send something to you after you close the socket but before it has + * finished reading all of the data you sent. There is no easy generic + * way to avoid this problem; the easiest fix is to design the network + * protocol such that the client will never send data "out of turn". + * Another solution is for the server to half-close the connection by + * calling g_socket_shutdown() with only the @shutdown_write flag set, + * and then wait for the client to notice this and close its side of the + * connection, after which the server can safely call g_socket_close(). + * (This is what #GTcpConnection does if you call + * g_tcp_connection_set_graceful_disconnect(). But of course, this + * only works if the client will close its connection after the server + * does.) + * * Returns: %TRUE on success, %FALSE on error * * Since: 2.22 - **/ + */ gboolean -g_socket_close (GSocket *socket, - GError **error) +g_socket_close (GSocket *socket, + GError **error) { int res; @@ -1887,16 +2219,13 @@ g_socket_close (GSocket *socket, break; } -#ifdef G_OS_WIN32 - if (socket->priv->event != WSA_INVALID_EVENT) - { - WSACloseEvent (socket->priv->event); - socket->priv->event = WSA_INVALID_EVENT; - } -#endif - 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; } @@ -1910,7 +2239,7 @@ g_socket_close (GSocket *socket, * Returns: %TRUE if socket is closed, %FALSE otherwise * * Since: 2.22 - **/ + */ gboolean g_socket_is_closed (GSocket *socket) { @@ -1920,22 +2249,22 @@ g_socket_is_closed (GSocket *socket) #ifdef G_OS_WIN32 /* Broken source, used on errors */ static gboolean -broken_prepare (GSource *source, - gint *timeout) +broken_prepare (GSource *source, + gint *timeout) { return FALSE; } static gboolean -broken_check (GSource *source) +broken_check (GSource *source) { return FALSE; } static gboolean -broken_dispatch (GSource *source, - GSourceFunc callback, - gpointer user_data) +broken_dispatch (GSource *source, + GSourceFunc callback, + gpointer user_data) { return TRUE; } @@ -2002,7 +2331,7 @@ update_select_events (GSocket *socket) } static void -add_condition_watch (GSocket *socket, +add_condition_watch (GSocket *socket, GIOCondition *condition) { g_assert (g_list_find (socket->priv->requested_conditions, condition) == NULL); @@ -2014,7 +2343,7 @@ add_condition_watch (GSocket *socket, } static void -remove_condition_watch (GSocket *socket, +remove_condition_watch (GSocket *socket, GIOCondition *condition) { g_assert (g_list_find (socket->priv->requested_conditions, condition) != NULL); @@ -2075,6 +2404,7 @@ update_condition (GSocket *socket) return condition; } +#endif typedef struct { GSource source; @@ -2083,100 +2413,139 @@ typedef struct { GIOCondition condition; GCancellable *cancellable; GPollFD cancel_pollfd; - GIOCondition result_condition; -} GWinsockSource; + gint64 timeout_time; +} GSocketSource; static gboolean -winsock_prepare (GSource *source, - gint *timeout) +socket_source_prepare (GSource *source, + gint *timeout) { - GWinsockSource *winsock_source = (GWinsockSource *)source; - GIOCondition current_condition; + GSocketSource *socket_source = (GSocketSource *)source; - current_condition = update_condition (winsock_source->socket); + if (g_cancellable_is_cancelled (socket_source->cancellable)) + return TRUE; - if (g_cancellable_is_cancelled (winsock_source->cancellable)) + if (socket_source->timeout_time) { - winsock_source->result_condition = current_condition; - return TRUE; + 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; + socket_source->pollfd.revents = socket_source->condition & (G_IO_IN | G_IO_OUT); + *timeout = 0; + return TRUE; + } } + else + *timeout = -1; - if ((winsock_source->condition & current_condition) != 0) - { - winsock_source->result_condition = current_condition; - return TRUE; - } +#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; } static gboolean -winsock_check (GSource *source) +socket_source_check (GSource *source) { - GWinsockSource *winsock_source = (GWinsockSource *)source; - GIOCondition current_condition; - - current_condition = update_condition (winsock_source->socket); - - if (g_cancellable_is_cancelled (winsock_source->cancellable)) - { - winsock_source->result_condition = current_condition; - return TRUE; - } + int timeout; - if ((winsock_source->condition & current_condition) != 0) - { - winsock_source->result_condition = current_condition; - return TRUE; - } - - return FALSE; + return socket_source_prepare (source, &timeout); } static gboolean -winsock_dispatch (GSource *source, - GSourceFunc callback, - gpointer user_data) +socket_source_dispatch (GSource *source, + GSourceFunc callback, + gpointer user_data) { GSocketSourceFunc func = (GSocketSourceFunc)callback; - GWinsockSource *winsock_source = (GWinsockSource *)source; + GSocketSource *socket_source = (GSocketSource *)source; + +#ifdef G_OS_WIN32 + socket_source->pollfd.revents = update_condition (socket_source->socket); +#endif - return (*func) (winsock_source->socket, - winsock_source->result_condition & winsock_source->condition, + return (*func) (socket_source->socket, + socket_source->pollfd.revents & socket_source->condition, user_data); } static void -winsock_finalize (GSource *source) +socket_source_finalize (GSource *source) { - GWinsockSource *winsock_source = (GWinsockSource *)source; + GSocketSource *socket_source = (GSocketSource *)source; GSocket *socket; - socket = winsock_source->socket; + socket = socket_source->socket; + +#ifdef G_OS_WIN32 + remove_condition_watch (socket, &socket_source->condition); +#endif - remove_condition_watch (socket, &winsock_source->condition); g_object_unref (socket); - if (winsock_source->cancellable) - g_object_unref (winsock_source->cancellable); + if (socket_source->cancellable) + { + g_cancellable_release_fd (socket_source->cancellable); + g_object_unref (socket_source->cancellable); + } +} + +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 winsock_funcs = +static GSourceFuncs socket_source_funcs = { - winsock_prepare, - winsock_check, - winsock_dispatch, - winsock_finalize + socket_source_prepare, + socket_source_check, + socket_source_dispatch, + socket_source_finalize, + (GSourceFunc)socket_source_closure_callback, + (GSourceDummyMarshal)_gio_marshal_BOOLEAN__FLAGS, }; static GSource * -winsock_source_new (GSocket *socket, - GIOCondition condition, - GCancellable *cancellable) +socket_source_new (GSocket *socket, + GIOCondition condition, + GCancellable *cancellable) { GSource *source; - GWinsockSource *winsock_source; + GSocketSource *socket_source; +#ifdef G_OS_WIN32 ensure_event (socket); if (socket->priv->event == WSA_INVALID_EVENT) @@ -2184,44 +2553,57 @@ winsock_source_new (GSocket *socket, g_warning ("Failed to create WSAEvent"); return g_source_new (&broken_funcs, sizeof (GSource)); } +#endif condition |= G_IO_HUP | G_IO_ERR; - source = g_source_new (&winsock_funcs, sizeof (GWinsockSource)); - winsock_source = (GWinsockSource *)source; + source = g_source_new (&socket_source_funcs, sizeof (GSocketSource)); + g_source_set_name (source, "GSocket"); + socket_source = (GSocketSource *)source; - winsock_source->socket = g_object_ref (socket); - winsock_source->condition = condition; - add_condition_watch (socket, &winsock_source->condition); + socket_source->socket = g_object_ref (socket); + socket_source->condition = condition; - if (cancellable) + if (g_cancellable_make_pollfd (cancellable, + &socket_source->cancel_pollfd)) { - winsock_source->cancellable = g_object_ref (cancellable); - g_cancellable_make_pollfd (cancellable, - &winsock_source->cancel_pollfd); - g_source_add_poll (source, &winsock_source->cancel_pollfd); + socket_source->cancellable = g_object_ref (cancellable); + g_source_add_poll (source, &socket_source->cancel_pollfd); } - winsock_source->pollfd.fd = (gintptr) socket->priv->event; - winsock_source->pollfd.events = condition; - g_source_add_poll (source, &winsock_source->pollfd); +#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); + + if (socket->priv->timeout) + socket_source->timeout_time = g_get_monotonic_time () + + socket->priv->timeout * 1000000; + + else + socket_source->timeout_time = 0; return source; } -#endif /** - * 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. * * The callback on the source is of the #GSocketSourceFunc type. * - * It is meaningless to specify %G_IO_ERR or %G_IO_HUP in condition; + * It is meaningless to specify %G_IO_ERR or %G_IO_HUP in @condition; * these conditions will always be reported output if they are true. * * @cancellable if not %NULL can be used to cancel the source, which will @@ -2230,25 +2612,24 @@ winsock_source_new (GSocket *socket, * condition change). You can check for this in the callback using * g_cancellable_is_cancelled(). * - * Returns: a newly allocated %GSource, free with g_source_unref(). + * If @socket has a timeout set, and it is reached before @condition + * occurs, the source will then trigger anyway, reporting %G_IO_IN or + * %G_IO_OUT depending on @condition. However, @socket will have been + * 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: (transfer full): a newly allocated %GSource, free with g_source_unref(). * * Since: 2.22 - **/ + */ GSource * g_socket_create_source (GSocket *socket, GIOCondition condition, GCancellable *cancellable) { - GSource *source; g_return_val_if_fail (G_IS_SOCKET (socket) && (cancellable == NULL || G_IS_CANCELLABLE (cancellable)), NULL); -#ifdef G_OS_WIN32 - source = winsock_source_new (socket, condition, cancellable); -#else - source =_g_fd_source_new_with_object (G_OBJECT (socket), socket->priv->fd, - condition, cancellable); -#endif - return source; + return socket_source_new (socket, condition, cancellable); } /** @@ -2256,11 +2637,19 @@ g_socket_create_source (GSocket *socket, * @socket: a #GSocket * @condition: a #GIOCondition mask to check * - * Checks on the readiness of @socket to perform operations. The - * operations specified in @condition are checked for and masked - * against the currently-satisfied conditions on @socket. The result + * Checks on the readiness of @socket to perform operations. + * The operations specified in @condition are checked for and masked + * 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. * @@ -2269,10 +2658,10 @@ g_socket_create_source (GSocket *socket, * Returns: the @GIOCondition mask of the current state * * Since: 2.22 - **/ + */ GIOCondition -g_socket_condition_check (GSocket *socket, - GIOCondition condition) +g_socket_condition_check (GSocket *socket, + GIOCondition condition) { if (!check_socket (socket, NULL)) return 0; @@ -2308,19 +2697,22 @@ 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 - * becomes true, %TRUE is returned. + * Waits for @condition to become true on @socket. When the condition + * is met, %TRUE is returned. * - * If @cancellable is cancelled before the condition becomes true then - * %FALSE is returned and @error, if non-%NULL, is set to %G_IO_ERROR_CANCELLED. + * If @cancellable is cancelled before the condition is met, or if the + * socket has a timeout set and it is reached before the condition is + * met, then %FALSE is returned and @error, if non-%NULL, is set to + * the appropriate value (%G_IO_ERROR_CANCELLED or + * %G_IO_ERROR_TIMED_OUT). * * Returns: %TRUE if the condition was met, %FALSE otherwise * * Since: 2.22 - **/ + */ gboolean g_socket_condition_wait (GSocket *socket, GIOCondition condition, @@ -2337,7 +2729,7 @@ g_socket_condition_wait (GSocket *socket, { GIOCondition current_condition; WSAEVENT events[2]; - DWORD res; + DWORD res, timeout; GPollFD cancel_fd; int num_events; @@ -2349,17 +2741,19 @@ g_socket_condition_wait (GSocket *socket, num_events = 0; events[num_events++] = socket->priv->event; - if (cancellable) - { - g_cancellable_make_pollfd (cancellable, &cancel_fd); - events[num_events++] = (WSAEVENT)cancel_fd.fd; - } + if (g_cancellable_make_pollfd (cancellable, &cancel_fd)) + events[num_events++] = (WSAEVENT)cancel_fd.fd; + + if (socket->priv->timeout) + timeout = socket->priv->timeout * 1000; + else + timeout = WSA_INFINITE; current_condition = update_condition (socket); while ((condition & current_condition) == 0) { res = WSAWaitForMultipleEvents(num_events, events, - FALSE, WSA_INFINITE, FALSE); + FALSE, timeout, FALSE); if (res == WSA_WAIT_FAILED) { int errsv = get_socket_errno (); @@ -2370,6 +2764,12 @@ g_socket_condition_wait (GSocket *socket, socket_strerror (errsv)); break; } + else if (res == WSA_WAIT_TIMEOUT) + { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT, + _("Socket I/O timed out")); + break; + } if (g_cancellable_set_error_if_cancelled (cancellable, error)) break; @@ -2377,6 +2777,8 @@ g_socket_condition_wait (GSocket *socket, current_condition = update_condition (socket); } remove_condition_watch (socket, &condition); + if (num_events > 1) + g_cancellable_release_fd (cancellable); return (condition & current_condition) != 0; } @@ -2385,23 +2787,35 @@ g_socket_condition_wait (GSocket *socket, GPollFD poll_fd[2]; gint result; gint num; + gint timeout; poll_fd[0].fd = socket->priv->fd; poll_fd[0].events = condition; num = 1; - if (cancellable) - { - g_cancellable_make_pollfd (cancellable, &poll_fd[1]); - num++; - } + if (g_cancellable_make_pollfd (cancellable, &poll_fd[1])) + num++; + + if (socket->priv->timeout) + timeout = socket->priv->timeout * 1000; + else + timeout = -1; do - result = g_poll (poll_fd, num, -1); + result = g_poll (poll_fd, num, timeout); while (result == -1 && get_socket_errno () == EINTR); + + if (num > 1) + g_cancellable_release_fd (cancellable); + + if (result == 0) + { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT, + _("Socket I/O timed out")); + return FALSE; + } - return cancellable == NULL || - !g_cancellable_set_error_if_cancelled (cancellable, error); + return !g_cancellable_set_error_if_cancelled (cancellable, error); } #endif } @@ -2410,12 +2824,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: (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 @@ -2425,12 +2840,14 @@ g_socket_condition_wait (GSocket *socket, * If @address is %NULL then the message is sent to the default receiver * (set by g_socket_connect()). * - * @vector must point to an array of #GOutputVector structs and - * @num_vectors must be the length of this array. These structs - * describe the buffers that the sent data will be gathered from. - * If @num_vector is -1, then @vector is assumed to be terminated - * by a #GOutputVector with a %NULL buffer pointer. - * + * @vectors must point to an array of #GOutputVector structs and + * @num_vectors must be the length of this array. (If @num_vectors is -1, + * 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 + * data from multiple sources into a single buffer, and more + * network-efficient than making multiple calls to g_socket_send(). * * @messages, if non-%NULL, is taken to point to an array of @num_messages * #GSocketControlMessage instances. These correspond to the control @@ -2438,28 +2855,27 @@ g_socket_condition_wait (GSocket *socket, * If @num_messages is -1 then @messages is treated as a %NULL-terminated * array. * - * @flags modify how the message sent. The commonly available arguments - * for this is available in the #GSocketMsgFlags enum, but the + * @flags modify how the message is sent. The commonly available arguments + * for this are available in the #GSocketMsgFlags enum, but the * values there are the same as the system values, and the flags - * are passed in as-is, so you can pass in system specific flags too. + * are passed in as-is, so you can pass in system-specific flags too. * * If the socket is in blocking mode the call will block until there is * space for the data in the socket queue. If there is no space available * and the socket is in non-blocking mode a %G_IO_ERROR_WOULD_BLOCK error - * will be returned. To be notified of available space, wait for the %G_IO_OUT - * condition. - * - * Note that on Windows you can't rely on a %G_IO_OUT condition - * not producing a %G_IO_ERROR_WOULD_BLOCK error, as this is how Winsock - * write notification works. However, robust apps should always be able to - * handle this since it can easily appear in other cases too. + * will be returned. To be notified when space is available, wait for the + * %G_IO_OUT condition. Note though that you may still receive + * %G_IO_ERROR_WOULD_BLOCK from g_socket_send() even if you were previously + * notified of a %G_IO_OUT condition. (On Windows in particular, this is + * very common due to the way the underlying APIs work.) * * On error -1 is returned and @error is set accordingly. * - * Returns: Number of bytes read, or -1 on error + * Returns: Number of bytes written (which may be less than @size), or -1 + * on error * * Since: 2.22 - **/ + */ gssize g_socket_send_message (GSocket *socket, GSocketAddress *address, @@ -2468,6 +2884,7 @@ g_socket_send_message (GSocket *socket, GSocketControlMessage **messages, gint num_messages, gint flags, + GCancellable *cancellable, GError **error) { GOutputVector one_vector; @@ -2476,6 +2893,9 @@ g_socket_send_message (GSocket *socket, if (!check_socket (socket, error)) return -1; + if (g_cancellable_set_error_if_cancelled (cancellable, error)) + return -1; + if (num_vectors == -1) { for (num_vectors = 0; @@ -2507,6 +2927,8 @@ g_socket_send_message (GSocket *socket, struct msghdr msg; gssize result; + msg.msg_flags = 0; + /* name */ if (address) { @@ -2515,6 +2937,11 @@ g_socket_send_message (GSocket *socket, if (!g_socket_address_to_native (address, msg.msg_name, msg.msg_namelen, error)) return -1; } + else + { + msg.msg_name = NULL; + msg.msg_namelen = 0; + } /* iov */ { @@ -2555,7 +2982,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++) @@ -2574,10 +3007,10 @@ g_socket_send_message (GSocket *socket, { if (socket->priv->blocking && !g_socket_condition_wait (socket, - G_IO_OUT, NULL, error)) + G_IO_OUT, cancellable, error)) return -1; - result = sendmsg (socket->priv->fd, &msg, flags); + result = sendmsg (socket->priv->fd, &msg, flags | G_SOCKET_DEFAULT_SEND_FLAGS); if (result < 0) { int errsv = get_socket_errno (); @@ -2642,7 +3075,7 @@ g_socket_send_message (GSocket *socket, { if (socket->priv->blocking && !g_socket_condition_wait (socket, - G_IO_OUT, NULL, error)) + G_IO_OUT, cancellable, error)) return -1; if (address) @@ -2689,13 +3122,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 will 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: (allow-none): a %GCancellable or %NULL * @error: a #GError pointer, or %NULL * * Receive data from a socket. This is the most complicated and @@ -2709,21 +3143,22 @@ g_socket_send_message (GSocket *socket, * @vector must point to an array of #GInputVector structs and * @num_vectors must be the length of this array. These structs * describe the buffers that received data will be scattered into. - * If @num_vector is -1, then @vector is assumed to be terminated + * If @num_vectors is -1, then @vectors is assumed to be terminated * by a #GInputVector with a %NULL buffer pointer. * - * As a special case, if the size of the array is zero (in which case, - * @vectors may of course be %NULL), then a single byte is received - * and discarded. This is to facilitate the common practice of - * sending a single '\0' byte for the purposes of transferring - * ancillary data. + * As a special case, if @num_vectors is 0 (in which case, @vectors + * may of course be %NULL), then a single byte is received and + * discarded. This is to facilitate the common practice of sending a + * single '\0' byte for the purposes of transferring ancillary data. * - * @messages, if non-%NULL, is taken to point to a pointer that will - * be set to point to a newly-allocated array of - * #GSocketControlMessage instances. These correspond to the control - * messages received from the kernel, one #GSocketControlMessage per - * message from the kernel. This array is %NULL-terminated and must be - * freed by the caller using g_free(). + * @messages, if non-%NULL, will be set to point to a newly-allocated + * array of #GSocketControlMessage instances or %NULL if no such + * messages was received. These correspond to the control messages + * received from the kernel, one #GSocketControlMessage per message + * from the kernel. This array is %NULL-terminated and must be freed + * by the caller using g_free() after calling g_object_unref() on each + * element. If @messages is %NULL, any control messages received will + * be discarded. * * @num_messages, if non-%NULL, will be set to the number of control * messages received. @@ -2733,22 +3168,31 @@ g_socket_send_message (GSocket *socket, * in @messages (ie: not including the %NULL terminator). * * @flags is an in/out parameter. The commonly available arguments - * for this is available in the #GSocketMsgFlags enum, but the + * for this are available in the #GSocketMsgFlags enum, but the * values there are the same as the system values, and the flags - * are passed in as-is, so you can pass in system specific flags too. - * - * 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 of available data, wait for the %G_IO_IN - * condition. + * are passed in as-is, so you can pass in system-specific flags too + * (and g_socket_receive_message() may pass system-specific flags out). + * + * As with g_socket_receive(), data may be discarded if @socket is + * %G_SOCKET_TYPE_DATAGRAM or %G_SOCKET_TYPE_SEQPACKET and you do not + * provide enough buffer space to read a complete message. You can pass + * %G_SOCKET_MSG_PEEK in @flags to peek at the current message without + * removing it from the receive queue, but there is no portable way to find + * out the length of the message other than by reading it into a + * 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. * * On error -1 is returned and @error is set accordingly. * * Returns: Number of bytes read, or -1 on error * * Since: 2.22 - **/ + */ gssize g_socket_receive_message (GSocket *socket, GSocketAddress **address, @@ -2757,6 +3201,7 @@ g_socket_receive_message (GSocket *socket, GSocketControlMessage ***messages, gint *num_messages, gint *flags, + GCancellable *cancellable, GError **error) { GInputVector one_vector; @@ -2765,6 +3210,9 @@ g_socket_receive_message (GSocket *socket, if (!check_socket (socket, error)) return -1; + if (g_cancellable_set_error_if_cancelled (cancellable, error)) + return -1; + if (num_vectors == -1) { for (num_vectors = 0; @@ -2842,7 +3290,7 @@ g_socket_receive_message (GSocket *socket, { if (socket->priv->blocking && !g_socket_condition_wait (socket, - G_IO_IN, NULL, error)) + G_IO_IN, cancellable, error)) return -1; result = recvmsg (socket->priv->fd, &msg, msg.msg_flags); @@ -2880,14 +3328,8 @@ g_socket_receive_message (GSocket *socket, /* decode control messages */ { - GSocketControlMessage **my_messages = NULL; - gint allocated = 0, index = 0; - const gchar *scm_pointer; + GPtrArray *my_messages = NULL; 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)) { @@ -2902,36 +3344,39 @@ g_socket_receive_message (GSocket *socket, deserialization code, so just continue */ continue; - if (index == allocated) + if (messages == NULL) { - /* estimated 99% case: exactly 1 control message */ - allocated = MIN (allocated * 2, 1); - my_messages = g_new (GSocketControlMessage *, (allocated + 1)); - allocated = 1; + /* we have to do it this way if the user ignores the + * messages so that we will close any received fds. + */ + g_object_unref (message); + } + else + { + if (my_messages == NULL) + my_messages = g_ptr_array_new (); + g_ptr_array_add (my_messages, message); } - - my_messages[index++] = message; } if (num_messages) - *num_messages = index; + *num_messages = my_messages != NULL ? my_messages->len : 0; if (messages) { - my_messages[index++] = NULL; - *messages = my_messages; + if (my_messages == NULL) + { + *messages = NULL; + } + else + { + g_ptr_array_add (my_messages, NULL); + *messages = (GSocketControlMessage **) g_ptr_array_free (my_messages, FALSE); + } } else { - gint i; - - /* free all those messages we just constructed. - * we have to do it this way if the user ignores the - * messages so that we will close any received fds. - */ - for (i = 0; i < index; i++) - g_object_unref (my_messages[i]); - g_free (my_messages); + g_assert (my_messages == NULL); } } @@ -2970,7 +3415,7 @@ g_socket_receive_message (GSocket *socket, { if (socket->priv->blocking && !g_socket_condition_wait (socket, - G_IO_IN, NULL, error)) + G_IO_IN, cancellable, error)) return -1; addrlen = sizeof addr; @@ -3021,10 +3466,82 @@ g_socket_receive_message (GSocket *socket, if (flags != NULL) *flags = win_flags; + if (messages != NULL) + *messages = NULL; + 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; +}