| /* GIO - GLib Input, Output and Streaming Library |
| * |
| * Copyright (C) 2008 Christian Kellner, Samuel Cormier-Iijima |
| * Copyright © 2009 Codethink Limited |
| * Copyright © 2009 Red Hat, Inc |
| * Copyright © 2015 Collabora, Ltd. |
| * |
| * SPDX-License-Identifier: LGPL-2.1-or-later |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * 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, see <http://www.gnu.org/licenses/>. |
| * |
| * Authors: Christian Kellner <gicmo@gnome.org> |
| * Samuel Cormier-Iijima <sciyoshi@gmail.com> |
| * Ryan Lortie <desrt@desrt.ca> |
| * Alexander Larsson <alexl@redhat.com> |
| * Philip Withnall <philip.withnall@collabora.co.uk> |
| */ |
| |
| #include "config.h" |
| |
| #include "gsocket.h" |
| |
| #ifdef G_OS_UNIX |
| #include "glib-unix.h" |
| #endif |
| |
| #include <errno.h> |
| #include <signal.h> |
| #include <string.h> |
| #include <stdlib.h> |
| |
| #ifndef G_OS_WIN32 |
| # include <fcntl.h> |
| # include <unistd.h> |
| # include <sys/ioctl.h> |
| #endif |
| |
| #ifdef HAVE_SIOCGIFADDR |
| #include <net/if.h> |
| #endif |
| |
| #ifdef HAVE_SYS_FILIO_H |
| # include <sys/filio.h> |
| #endif |
| |
| #ifdef G_OS_UNIX |
| #include <sys/uio.h> |
| #endif |
| |
| #define GOBJECT_COMPILATION |
| #include "gobject/gtype-private.h" /* For _PRELUDE type define */ |
| #undef GOBJECT_COMPILATION |
| #include "gcancellable.h" |
| #include "gdatagrambased.h" |
| #include "gioenumtypes.h" |
| #include "ginetaddress.h" |
| #include "ginetsocketaddress.h" |
| #include "ginitable.h" |
| #include "gioerror.h" |
| #include "gioenums.h" |
| #include "gioerror.h" |
| #include "gnetworkingprivate.h" |
| #include "gsocketaddress.h" |
| #include "gsocketcontrolmessage.h" |
| #include "gcredentials.h" |
| #include "gcredentialsprivate.h" |
| #include "glibintl.h" |
| #include "gioprivate.h" |
| |
| #ifdef G_OS_WIN32 |
| #include "giowin32-afunix.h" |
| #endif |
| |
| /** |
| * GSocket: |
| * |
| * 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. |
| * |
| * `GSocket` is the platform independent base upon which the higher level |
| * network primitives are based. Applications are not typically meant to |
| * use it directly, but rather through classes like [class@Gio.SocketClient], |
| * [class@Gio.SocketService] and [class@Gio.SocketConnection]. However there may |
| * be cases where direct use of `GSocket` is useful. |
| * |
| * `GSocket` implements the [iface@Gio.Initable] interface, so if it is manually |
| * constructed by e.g. [ctor@GObject.Object.new] you must call |
| * [method@Gio.Initable.init] and check the results before using the object. |
| * This is done automatically in [ctor@Gio.Socket.new] and |
| * [ctor@Gio.Socket.new_from_fd], so these functions can return `NULL`. |
| * |
| * Sockets operate in two general modes, blocking or non-blocking. When |
| * in blocking mode all operations (which don’t take an explicit blocking |
| * parameter) block until the requested operation |
| * is finished or there is an error. In non-blocking mode all calls that |
| * would block return immediately with a `G_IO_ERROR_WOULD_BLOCK` error. |
| * To know when a call would successfully run you can call |
| * [method@Gio.Socket.condition_check], or [method@Gio.Socket.condition_wait]. |
| * You can also use [method@Gio.Socket.create_source] and attach it to a |
| * [type@GLib.MainContext] to get callbacks when I/O is possible. |
| * Note that all sockets are always set to non blocking mode in the system, and |
| * blocking mode is emulated in `GSocket`. |
| * |
| * When working in non-blocking mode applications should always be able to |
| * handle getting a `G_IO_ERROR_WOULD_BLOCK` error even when some other |
| * function said that I/O was possible. This can easily happen in case |
| * of a race condition in the application, but it can also happen for other |
| * reasons. For instance, on Windows a socket is always seen as writable |
| * until a write returns `G_IO_ERROR_WOULD_BLOCK`. |
| * |
| * `GSocket`s 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 |
| * specified or received in each I/O operation. |
| * |
| * All socket file descriptors are set to be close-on-exec. |
| * |
| * Note that creating a `GSocket` causes the signal `SIGPIPE` to be |
| * ignored for the remainder of the program. If you are writing a |
| * command-line utility that uses `GSocket`, you may need to take into |
| * 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. |
| * |
| * ## Nagle’s algorithm |
| * |
| * Since GLib 2.80, `GSocket` will automatically set the `TCP_NODELAY` option on |
| * all `G_SOCKET_TYPE_STREAM` sockets. This disables |
| * [Nagle’s algorithm](https://en.wikipedia.org/wiki/Nagle%27s_algorithm) as it |
| * typically does more harm than good on modern networks. |
| * |
| * If your application needs Nagle’s algorithm enabled, call |
| * [method@Gio.Socket.set_option] after constructing a `GSocket` to enable it: |
| * ```c |
| * socket = g_socket_new (…, G_SOCKET_TYPE_STREAM, …); |
| * if (socket != NULL) |
| * { |
| * g_socket_set_option (socket, IPPROTO_TCP, TCP_NODELAY, FALSE, &local_error); |
| * // handle error if needed |
| * } |
| * ``` |
| * |
| * Since: 2.22 |
| */ |
| |
| static void g_socket_initable_iface_init (GInitableIface *iface); |
| static gboolean g_socket_initable_init (GInitable *initable, |
| GCancellable *cancellable, |
| GError **error); |
| |
| static void g_socket_datagram_based_iface_init (GDatagramBasedInterface *iface); |
| static gint g_socket_datagram_based_receive_messages (GDatagramBased *self, |
| GInputMessage *messages, |
| guint num_messages, |
| gint flags, |
| gint64 timeout_us, |
| GCancellable *cancellable, |
| GError **error); |
| static gint g_socket_datagram_based_send_messages (GDatagramBased *self, |
| GOutputMessage *messages, |
| guint num_messages, |
| gint flags, |
| gint64 timeout_us, |
| GCancellable *cancellable, |
| GError **error); |
| static GSource *g_socket_datagram_based_create_source (GDatagramBased *self, |
| GIOCondition condition, |
| GCancellable *cancellable); |
| static GIOCondition g_socket_datagram_based_condition_check (GDatagramBased *datagram_based, |
| GIOCondition condition); |
| static gboolean g_socket_datagram_based_condition_wait (GDatagramBased *datagram_based, |
| GIOCondition condition, |
| gint64 timeout_us, |
| GCancellable *cancellable, |
| GError **error); |
| |
| static GSocketAddress * |
| cache_recv_address (GSocket *socket, struct sockaddr *native, size_t native_len); |
| |
| static gssize |
| g_socket_receive_message_with_timeout (GSocket *socket, |
| GSocketAddress **address, |
| GInputVector *vectors, |
| gint num_vectors, |
| GSocketControlMessage ***messages, |
| gint *num_messages, |
| gint *flags, |
| gint64 timeout_us, |
| GCancellable *cancellable, |
| GError **error); |
| static gint |
| g_socket_receive_messages_with_timeout (GSocket *socket, |
| GInputMessage *messages, |
| guint num_messages, |
| gint flags, |
| gint64 timeout_us, |
| GCancellable *cancellable, |
| GError **error); |
| static gint |
| g_socket_send_messages_with_timeout (GSocket *socket, |
| GOutputMessage *messages, |
| guint num_messages, |
| gint flags, |
| gint64 timeout_us, |
| GCancellable *cancellable, |
| GError **error); |
| |
| enum |
| { |
| PROP_0, |
| PROP_FAMILY, |
| PROP_TYPE, |
| PROP_PROTOCOL, |
| PROP_FD, |
| PROP_BLOCKING, |
| PROP_LISTEN_BACKLOG, |
| PROP_KEEPALIVE, |
| PROP_LOCAL_ADDRESS, |
| PROP_REMOTE_ADDRESS, |
| PROP_TIMEOUT, |
| PROP_TTL, |
| PROP_BROADCAST, |
| PROP_MULTICAST_LOOPBACK, |
| PROP_MULTICAST_TTL |
| }; |
| |
| /* Size of the receiver cache for g_socket_receive_from() */ |
| #define RECV_ADDR_CACHE_SIZE 8 |
| |
| struct _GSocketPrivate |
| { |
| GSocketFamily family; |
| GSocketType type; |
| 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_read : 1; |
| guint connected_write : 1; |
| guint listening : 1; |
| guint timed_out : 1; |
| guint connect_pending : 1; |
| #ifdef G_OS_WIN32 |
| WSAEVENT event; |
| gboolean waiting; |
| DWORD waiting_result; |
| int current_events; |
| int current_errors; |
| int selected_events; |
| GList *requested_conditions; /* list of requested GIOCondition * */ |
| GMutex win32_source_lock; |
| GCond win32_source_cond; |
| #endif |
| |
| struct { |
| GSocketAddress *addr; |
| struct sockaddr *native; |
| gsize native_len; |
| guint64 last_used; |
| } recv_addr_cache[RECV_ADDR_CACHE_SIZE]; |
| }; |
| |
| _G_DEFINE_TYPE_EXTENDED_WITH_PRELUDE (GSocket, g_socket, G_TYPE_OBJECT, 0, |
| /* Need a prelude for https://bugzilla.gnome.org/show_bug.cgi?id=674885 */ |
| g_type_ensure (G_TYPE_SOCKET_FAMILY); |
| g_type_ensure (G_TYPE_SOCKET_TYPE); |
| g_type_ensure (G_TYPE_SOCKET_PROTOCOL); |
| g_type_ensure (G_TYPE_SOCKET_ADDRESS); |
| /* And networking init is appropriate for the prelude */ |
| g_networking_init (); |
| , /* And now the regular type init code */ |
| G_ADD_PRIVATE (GSocket) |
| G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, |
| g_socket_initable_iface_init); |
| G_IMPLEMENT_INTERFACE (G_TYPE_DATAGRAM_BASED, |
| g_socket_datagram_based_iface_init)); |
| |
| static int |
| get_socket_errno (void) |
| { |
| #ifndef G_OS_WIN32 |
| return errno; |
| #else |
| return WSAGetLastError (); |
| #endif |
| } |
| |
| static GIOErrorEnum |
| socket_io_error_from_errno (int err) |
| { |
| #ifdef G_OS_WIN32 |
| return g_io_error_from_win32_error (err); |
| #else |
| return g_io_error_from_errno (err); |
| #endif |
| } |
| |
| static const char * |
| socket_strerror (int err) |
| { |
| #ifndef G_OS_WIN32 |
| return g_strerror (err); |
| #else |
| const char *msg_ret; |
| char *msg; |
| |
| msg = g_win32_error_message (err); |
| |
| msg_ret = g_intern_string (msg); |
| g_free (msg); |
| |
| return msg_ret; |
| #endif |
| } |
| |
| /* Wrapper around g_set_error() to avoid doing excess work */ |
| #define socket_set_error_lazy(err, errsv, fmt) \ |
| G_STMT_START { \ |
| GError **__err = (err); \ |
| int __errsv = (errsv); \ |
| \ |
| if (__err) \ |
| { \ |
| int __code = socket_io_error_from_errno (__errsv); \ |
| const char *__strerr = socket_strerror (__errsv); \ |
| \ |
| if (__code == G_IO_ERROR_WOULD_BLOCK) \ |
| g_set_error_literal (__err, G_IO_ERROR, __code, __strerr); \ |
| else \ |
| g_set_error (__err, G_IO_ERROR, __code, fmt, __strerr); \ |
| } \ |
| } G_STMT_END |
| |
| #ifdef G_OS_WIN32 |
| #define win32_unset_event_mask(_socket, _mask) _win32_unset_event_mask (_socket, _mask) |
| static void |
| _win32_unset_event_mask (GSocket *socket, int mask) |
| { |
| g_mutex_lock (&socket->priv->win32_source_lock); |
| socket->priv->current_events &= ~mask; |
| socket->priv->current_errors &= ~mask; |
| g_mutex_unlock (&socket->priv->win32_source_lock); |
| } |
| #else |
| #define win32_unset_event_mask(_socket, _mask) |
| #endif |
| |
| /* Windows has broken prototypes... */ |
| #ifdef G_OS_WIN32 |
| #define getsockopt(sockfd, level, optname, optval, optlen) \ |
| getsockopt (sockfd, level, optname, (gpointer) optval, (int*) optlen) |
| #define setsockopt(sockfd, level, optname, optval, optlen) \ |
| setsockopt (sockfd, level, optname, (gpointer) optval, optlen) |
| #define getsockname(sockfd, addr, addrlen) \ |
| getsockname (sockfd, addr, (int *)addrlen) |
| #define getpeername(sockfd, addr, addrlen) \ |
| getpeername (sockfd, addr, (int *)addrlen) |
| #define recv(sockfd, buf, len, flags) \ |
| recv (sockfd, (gpointer)buf, len, flags) |
| #endif |
| |
| static gchar * |
| address_to_string (GSocketAddress *address) |
| { |
| GString *ret = g_string_new (""); |
| |
| if (G_IS_INET_SOCKET_ADDRESS (address)) |
| { |
| GInetSocketAddress *isa = G_INET_SOCKET_ADDRESS (address); |
| GInetAddress *ia = g_inet_socket_address_get_address (isa); |
| GSocketFamily family = g_inet_address_get_family (ia); |
| gchar *tmp; |
| |
| /* Represent IPv6 addresses in URL style: |
| * ::1 port 12345 -> [::1]:12345 */ |
| if (family == G_SOCKET_FAMILY_IPV6) |
| g_string_append_c (ret, '['); |
| |
| tmp = g_inet_address_to_string (ia); |
| g_string_append (ret, tmp); |
| g_free (tmp); |
| |
| if (family == G_SOCKET_FAMILY_IPV6) |
| { |
| guint32 scope = g_inet_socket_address_get_scope_id (isa); |
| |
| if (scope != 0) |
| g_string_append_printf (ret, "%%%u", scope); |
| |
| g_string_append_c (ret, ']'); |
| } |
| |
| g_string_append_c (ret, ':'); |
| |
| g_string_append_printf (ret, "%u", g_inet_socket_address_get_port (isa)); |
| } |
| else |
| { |
| /* For unknown address types, just show the type */ |
| g_string_append_printf (ret, "(%s)", G_OBJECT_TYPE_NAME (address)); |
| } |
| |
| return g_string_free (ret, FALSE); |
| } |
| |
| static gboolean |
| check_socket (GSocket *socket, |
| GError **error) |
| { |
| if (!socket->priv->inited) |
| { |
| g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_INITIALIZED, |
| _("Invalid socket, not initialized")); |
| return FALSE; |
| } |
| |
| if (socket->priv->construct_error) |
| { |
| g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_INITIALIZED, |
| _("Invalid socket, initialization failed due to: %s"), |
| socket->priv->construct_error->message); |
| return FALSE; |
| } |
| |
| if (socket->priv->closed) |
| { |
| g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CLOSED, |
| _("Socket is already closed")); |
| return FALSE; |
| } |
| |
| return TRUE; |
| } |
| |
| static gboolean |
| check_timeout (GSocket *socket, |
| GError **error) |
| { |
| 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; |
| } |
| |
| static void |
| g_socket_details_from_fd (GSocket *socket) |
| { |
| union { |
| struct sockaddr_storage storage; |
| struct sockaddr sa; |
| } address; |
| gint fd; |
| socklen_t addrlen; |
| int value, family; |
| int errsv; |
| |
| memset (&address, 0, sizeof (address)); |
| |
| fd = socket->priv->fd; |
| if (!g_socket_get_option (socket, SOL_SOCKET, SO_TYPE, &value, NULL)) |
| { |
| errsv = get_socket_errno (); |
| goto err; |
| } |
| |
| switch (value) |
| { |
| case SOCK_STREAM: |
| socket->priv->type = G_SOCKET_TYPE_STREAM; |
| break; |
| |
| case SOCK_DGRAM: |
| socket->priv->type = G_SOCKET_TYPE_DATAGRAM; |
| break; |
| |
| case SOCK_SEQPACKET: |
| socket->priv->type = G_SOCKET_TYPE_SEQPACKET; |
| break; |
| |
| default: |
| socket->priv->type = G_SOCKET_TYPE_INVALID; |
| break; |
| } |
| |
| addrlen = sizeof address; |
| if (getsockname (fd, &address.sa, &addrlen) != 0) |
| { |
| errsv = get_socket_errno (); |
| goto err; |
| } |
| |
| if (addrlen > 0) |
| { |
| g_assert (G_STRUCT_OFFSET (struct sockaddr, sa_family) + |
| (socklen_t) sizeof address.storage.ss_family <= addrlen); |
| family = address.storage.ss_family; |
| } |
| else |
| { |
| /* On Solaris, this happens if the socket is not yet connected. |
| * But we can use SO_DOMAIN as a workaround there. |
| */ |
| #ifdef SO_DOMAIN |
| if (!g_socket_get_option (socket, SOL_SOCKET, SO_DOMAIN, &family, NULL)) |
| { |
| errsv = get_socket_errno (); |
| goto err; |
| } |
| #else |
| /* This will translate to G_IO_ERROR_FAILED on either unix or windows */ |
| errsv = -1; |
| goto err; |
| #endif |
| } |
| |
| switch (family) |
| { |
| case G_SOCKET_FAMILY_IPV4: |
| case G_SOCKET_FAMILY_IPV6: |
| socket->priv->family = address.storage.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 = G_SOCKET_FAMILY_UNIX; |
| socket->priv->protocol = G_SOCKET_PROTOCOL_DEFAULT; |
| break; |
| |
| default: |
| socket->priv->family = G_SOCKET_FAMILY_INVALID; |
| break; |
| } |
| |
| if (socket->priv->family != G_SOCKET_FAMILY_INVALID) |
| { |
| addrlen = sizeof address; |
| if (getpeername (fd, &address.sa, &addrlen) >= 0) |
| { |
| socket->priv->connected_read = TRUE; |
| socket->priv->connected_write = TRUE; |
| } |
| } |
| |
| if (g_socket_get_option (socket, SOL_SOCKET, SO_KEEPALIVE, &value, NULL)) |
| { |
| socket->priv->keepalive = !!value; |
| } |
| else |
| { |
| /* Can't read, maybe not supported, assume FALSE */ |
| socket->priv->keepalive = FALSE; |
| } |
| |
| return; |
| |
| err: |
| g_set_error (&socket->priv->construct_error, G_IO_ERROR, |
| socket_io_error_from_errno (errsv), |
| _("creating GSocket from fd: %s"), |
| socket_strerror (errsv)); |
| } |
| |
| static void |
| socket_set_nonblock (int 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 (fd, TRUE, &error)) |
| { |
| g_warning ("Error setting socket to nonblocking mode: %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 |
| } |
| |
| /* Wrapper around socket() that is shared with gnetworkmonitornetlink.c. |
| * It always sets SOCK_CLOEXEC | SOCK_NONBLOCK. */ |
| gint |
| g_socket (gint domain, |
| gint type, |
| gint protocol, |
| GError **error) |
| { |
| int fd, errsv; |
| |
| #if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK) |
| fd = socket (domain, type | SOCK_CLOEXEC | SOCK_NONBLOCK, protocol); |
| errsv = errno; |
| if (fd != -1) |
| return fd; |
| |
| /* It's possible that libc has SOCK_CLOEXEC and/or SOCK_NONBLOCK but the kernel does not */ |
| if (fd < 0 && (errsv == EINVAL || errsv == EPROTOTYPE)) |
| #endif |
| fd = socket (domain, type, protocol); |
| |
| if (fd < 0) |
| { |
| errsv = get_socket_errno (); |
| |
| g_set_error (error, G_IO_ERROR, socket_io_error_from_errno (errsv), |
| _("Unable to create socket: %s"), socket_strerror (errsv)); |
| errno = errsv; |
| return -1; |
| } |
| |
| #ifndef G_OS_WIN32 |
| { |
| int flags; |
| |
| /* We always want to set close-on-exec to protect users. If you |
| need to so some weird inheritance to exec you can re-enable this |
| using lower level hacks with g_socket_get_fd(). */ |
| flags = fcntl (fd, F_GETFD, 0); |
| if (flags != -1 && |
| (flags & FD_CLOEXEC) == 0) |
| { |
| flags |= FD_CLOEXEC; |
| (void) fcntl (fd, F_SETFD, flags); |
| } |
| } |
| #else |
| if ((domain == AF_INET || domain == AF_INET6) && type == SOCK_DGRAM) |
| { |
| BOOL new_behavior = FALSE; |
| DWORD bytes_returned = 0; |
| |
| /* Disable connection reset error on ICMP port unreachable. */ |
| WSAIoctl (fd, SIO_UDP_CONNRESET, &new_behavior, sizeof (new_behavior), |
| NULL, 0, &bytes_returned, NULL, NULL); |
| } |
| #endif |
| |
| /* Ensure the socket is non-blocking. */ |
| socket_set_nonblock (fd); |
| |
| return fd; |
| } |
| |
| /* Returned socket has SOCK_CLOEXEC | SOCK_NONBLOCK set. */ |
| static gint |
| g_socket_create_socket (GSocketFamily family, |
| GSocketType type, |
| int protocol, |
| GError **error) |
| { |
| gint native_type; |
| |
| switch (type) |
| { |
| case G_SOCKET_TYPE_STREAM: |
| native_type = SOCK_STREAM; |
| break; |
| |
| case G_SOCKET_TYPE_DATAGRAM: |
| native_type = SOCK_DGRAM; |
| break; |
| |
| case G_SOCKET_TYPE_SEQPACKET: |
| native_type = SOCK_SEQPACKET; |
| break; |
| |
| default: |
| g_assert_not_reached (); |
| } |
| |
| if (family <= 0) |
| { |
| g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, |
| _("Unable to create socket: %s"), _("Unknown family was specified")); |
| return -1; |
| } |
| |
| if (protocol == -1) |
| { |
| g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, |
| _("Unable to create socket: %s"), _("Unknown protocol was specified")); |
| return -1; |
| } |
| |
| return g_socket (family, native_type, protocol, error); |
| } |
| |
| static void |
| g_socket_constructed (GObject *object) |
| { |
| GSocket *socket = G_SOCKET (object); |
| |
| if (socket->priv->fd >= 0) |
| { |
| /* create socket->priv info from the fd and ensure it’s non-blocking */ |
| g_socket_details_from_fd (socket); |
| socket_set_nonblock (socket->priv->fd); |
| } |
| else |
| { |
| /* create the fd from socket->priv info; this sets it non-blocking by construction */ |
| socket->priv->fd = g_socket_create_socket (socket->priv->family, |
| socket->priv->type, |
| socket->priv->protocol, |
| &socket->priv->construct_error); |
| } |
| |
| if (socket->priv->fd != -1) |
| { |
| #ifdef SO_NOSIGPIPE |
| /* See note about SIGPIPE below. */ |
| g_socket_set_option (socket, SOL_SOCKET, SO_NOSIGPIPE, TRUE, NULL); |
| #endif |
| if (socket->priv->type == G_SOCKET_TYPE_STREAM) |
| g_socket_set_option (socket, IPPROTO_TCP, TCP_NODELAY, TRUE, NULL); |
| } |
| } |
| |
| static void |
| g_socket_get_property (GObject *object, |
| guint prop_id, |
| GValue *value, |
| GParamSpec *pspec) |
| { |
| GSocket *socket = G_SOCKET (object); |
| GSocketAddress *address; |
| |
| switch (prop_id) |
| { |
| case PROP_FAMILY: |
| g_value_set_enum (value, socket->priv->family); |
| break; |
| |
| case PROP_TYPE: |
| g_value_set_enum (value, socket->priv->type); |
| break; |
| |
| case PROP_PROTOCOL: |
| g_value_set_enum (value, socket->priv->protocol); |
| break; |
| |
| case PROP_FD: |
| g_value_set_int (value, socket->priv->fd); |
| break; |
| |
| case PROP_BLOCKING: |
| g_value_set_boolean (value, socket->priv->blocking); |
| break; |
| |
| case PROP_LISTEN_BACKLOG: |
| g_value_set_int (value, socket->priv->listen_backlog); |
| break; |
| |
| case PROP_KEEPALIVE: |
| g_value_set_boolean (value, socket->priv->keepalive); |
| break; |
| |
| case PROP_LOCAL_ADDRESS: |
| address = g_socket_get_local_address (socket, NULL); |
| g_value_take_object (value, address); |
| break; |
| |
| case PROP_REMOTE_ADDRESS: |
| address = g_socket_get_remote_address (socket, NULL); |
| g_value_take_object (value, address); |
| break; |
| |
| case PROP_TIMEOUT: |
| g_value_set_uint (value, socket->priv->timeout); |
| break; |
| |
| case PROP_TTL: |
| g_value_set_uint (value, g_socket_get_ttl (socket)); |
| break; |
| |
| case PROP_BROADCAST: |
| g_value_set_boolean (value, g_socket_get_broadcast (socket)); |
| break; |
| |
| case PROP_MULTICAST_LOOPBACK: |
| g_value_set_boolean (value, g_socket_get_multicast_loopback (socket)); |
| break; |
| |
| case PROP_MULTICAST_TTL: |
| g_value_set_uint (value, g_socket_get_multicast_ttl (socket)); |
| break; |
| |
| default: |
| G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
| } |
| } |
| |
| static void |
| g_socket_set_property (GObject *object, |
| guint prop_id, |
| const GValue *value, |
| GParamSpec *pspec) |
| { |
| GSocket *socket = G_SOCKET (object); |
| |
| switch (prop_id) |
| { |
| case PROP_FAMILY: |
| socket->priv->family = g_value_get_enum (value); |
| break; |
| |
| case PROP_TYPE: |
| socket->priv->type = g_value_get_enum (value); |
| break; |
| |
| case PROP_PROTOCOL: |
| socket->priv->protocol = g_value_get_enum (value); |
| break; |
| |
| case PROP_FD: |
| socket->priv->fd = g_value_get_int (value); |
| break; |
| |
| case PROP_BLOCKING: |
| g_socket_set_blocking (socket, g_value_get_boolean (value)); |
| break; |
| |
| case PROP_LISTEN_BACKLOG: |
| g_socket_set_listen_backlog (socket, g_value_get_int (value)); |
| break; |
| |
| case PROP_KEEPALIVE: |
| 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; |
| |
| case PROP_TTL: |
| g_socket_set_ttl (socket, g_value_get_uint (value)); |
| break; |
| |
| case PROP_BROADCAST: |
| g_socket_set_broadcast (socket, g_value_get_boolean (value)); |
| break; |
| |
| case PROP_MULTICAST_LOOPBACK: |
| g_socket_set_multicast_loopback (socket, g_value_get_boolean (value)); |
| break; |
| |
| case PROP_MULTICAST_TTL: |
| g_socket_set_multicast_ttl (socket, g_value_get_uint (value)); |
| break; |
| |
| default: |
| G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
| } |
| } |
| |
| static void |
| g_socket_finalize (GObject *object) |
| { |
| GSocket *socket = G_SOCKET (object); |
| gint i; |
| |
| g_clear_error (&socket->priv->construct_error); |
| |
| if (socket->priv->fd != -1 && |
| !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); |
| g_mutex_clear (&socket->priv->win32_source_lock); |
| g_cond_clear (&socket->priv->win32_source_cond); |
| #endif |
| |
| for (i = 0; i < RECV_ADDR_CACHE_SIZE; i++) |
| { |
| if (socket->priv->recv_addr_cache[i].addr) |
| { |
| g_object_unref (socket->priv->recv_addr_cache[i].addr); |
| g_free (socket->priv->recv_addr_cache[i].native); |
| } |
| } |
| |
| if (G_OBJECT_CLASS (g_socket_parent_class)->finalize) |
| (*G_OBJECT_CLASS (g_socket_parent_class)->finalize) (object); |
| } |
| |
| static void |
| g_socket_class_init (GSocketClass *klass) |
| { |
| GObjectClass *gobject_class G_GNUC_UNUSED = G_OBJECT_CLASS (klass); |
| |
| #ifdef SIGPIPE |
| /* 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 |
| |
| gobject_class->finalize = g_socket_finalize; |
| gobject_class->constructed = g_socket_constructed; |
| gobject_class->set_property = g_socket_set_property; |
| gobject_class->get_property = g_socket_get_property; |
| |
| /** |
| * GSocket:family: |
| * |
| * The socket’s address family. |
| * |
| * Since: 2.22 |
| */ |
| g_object_class_install_property (gobject_class, PROP_FAMILY, |
| g_param_spec_enum ("family", NULL, NULL, |
| G_TYPE_SOCKET_FAMILY, |
| G_SOCKET_FAMILY_INVALID, |
| G_PARAM_CONSTRUCT_ONLY | |
| G_PARAM_READWRITE | |
| G_PARAM_STATIC_STRINGS)); |
| |
| /** |
| * GSocket:type: |
| * |
| * The socket’s type. |
| * |
| * Since: 2.22 |
| */ |
| g_object_class_install_property (gobject_class, PROP_TYPE, |
| g_param_spec_enum ("type", NULL, NULL, |
| G_TYPE_SOCKET_TYPE, |
| G_SOCKET_TYPE_STREAM, |
| G_PARAM_CONSTRUCT_ONLY | |
| G_PARAM_READWRITE | |
| G_PARAM_STATIC_STRINGS)); |
| |
| /** |
| * GSocket:protocol: |
| * |
| * The ID of the protocol to use, or `-1` for unknown. |
| * |
| * Since: 2.22 |
| */ |
| g_object_class_install_property (gobject_class, PROP_PROTOCOL, |
| g_param_spec_enum ("protocol", NULL, NULL, |
| G_TYPE_SOCKET_PROTOCOL, |
| G_SOCKET_PROTOCOL_UNKNOWN, |
| G_PARAM_CONSTRUCT_ONLY | |
| G_PARAM_READWRITE | |
| G_PARAM_STATIC_STRINGS)); |
| |
| /** |
| * GSocket:fd: |
| * |
| * The socket’s file descriptor. |
| * |
| * Since: 2.22 |
| */ |
| g_object_class_install_property (gobject_class, PROP_FD, |
| g_param_spec_int ("fd", NULL, NULL, |
| G_MININT, |
| G_MAXINT, |
| -1, |
| G_PARAM_CONSTRUCT_ONLY | |
| G_PARAM_READWRITE | |
| G_PARAM_STATIC_STRINGS)); |
| |
| /** |
| * GSocket:blocking: |
| * |
| * Whether I/O on this socket is blocking. |
| * |
| * Since: 2.22 |
| */ |
| g_object_class_install_property (gobject_class, PROP_BLOCKING, |
| g_param_spec_boolean ("blocking", NULL, NULL, |
| TRUE, |
| G_PARAM_READWRITE | |
| G_PARAM_STATIC_STRINGS)); |
| |
| /** |
| * GSocket:listen-backlog: |
| * |
| * The number of outstanding connections in the listen queue. |
| * |
| * Since: 2.22 |
| */ |
| g_object_class_install_property (gobject_class, PROP_LISTEN_BACKLOG, |
| g_param_spec_int ("listen-backlog", NULL, NULL, |
| 0, |
| SOMAXCONN, |
| 10, |
| G_PARAM_READWRITE | |
| G_PARAM_STATIC_STRINGS)); |
| |
| /** |
| * GSocket:keepalive: |
| * |
| * Whether to keep the connection alive by sending periodic pings. |
| * |
| * Since: 2.22 |
| */ |
| g_object_class_install_property (gobject_class, PROP_KEEPALIVE, |
| g_param_spec_boolean ("keepalive", NULL, NULL, |
| FALSE, |
| G_PARAM_READWRITE | |
| G_PARAM_STATIC_STRINGS)); |
| |
| /** |
| * GSocket:local-address: |
| * |
| * The local address the socket is bound to. |
| * |
| * Since: 2.22 |
| */ |
| g_object_class_install_property (gobject_class, PROP_LOCAL_ADDRESS, |
| g_param_spec_object ("local-address", NULL, NULL, |
| G_TYPE_SOCKET_ADDRESS, |
| G_PARAM_READABLE | |
| G_PARAM_STATIC_STRINGS)); |
| |
| /** |
| * GSocket:remote-address: |
| * |
| * The remote address the socket is connected to. |
| * |
| * Since: 2.22 |
| */ |
| g_object_class_install_property (gobject_class, PROP_REMOTE_ADDRESS, |
| g_param_spec_object ("remote-address", NULL, NULL, |
| G_TYPE_SOCKET_ADDRESS, |
| 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", NULL, NULL, |
| 0, |
| G_MAXUINT, |
| 0, |
| G_PARAM_READWRITE | |
| G_PARAM_STATIC_STRINGS)); |
| |
| /** |
| * GSocket:broadcast: |
| * |
| * Whether the socket should allow sending to broadcast addresses. |
| * |
| * Since: 2.32 |
| */ |
| g_object_class_install_property (gobject_class, PROP_BROADCAST, |
| g_param_spec_boolean ("broadcast", NULL, NULL, |
| FALSE, |
| G_PARAM_READWRITE | |
| G_PARAM_STATIC_STRINGS)); |
| |
| /** |
| * GSocket:ttl: |
| * |
| * Time-to-live for outgoing unicast packets |
| * |
| * Since: 2.32 |
| */ |
| g_object_class_install_property (gobject_class, PROP_TTL, |
| g_param_spec_uint ("ttl", NULL, NULL, |
| 0, G_MAXUINT, 0, |
| G_PARAM_READWRITE | |
| G_PARAM_STATIC_STRINGS)); |
| |
| /** |
| * GSocket:multicast-loopback: |
| * |
| * Whether outgoing multicast packets loop back to the local host. |
| * |
| * Since: 2.32 |
| */ |
| g_object_class_install_property (gobject_class, PROP_MULTICAST_LOOPBACK, |
| g_param_spec_boolean ("multicast-loopback", NULL, NULL, |
| TRUE, |
| G_PARAM_READWRITE | |
| G_PARAM_STATIC_STRINGS)); |
| |
| /** |
| * GSocket:multicast-ttl: |
| * |
| * Time-to-live out outgoing multicast packets |
| * |
| * Since: 2.32 |
| */ |
| g_object_class_install_property (gobject_class, PROP_MULTICAST_TTL, |
| g_param_spec_uint ("multicast-ttl", NULL, NULL, |
| 0, G_MAXUINT, 1, |
| G_PARAM_READWRITE | |
| G_PARAM_STATIC_STRINGS)); |
| } |
| |
| static void |
| g_socket_initable_iface_init (GInitableIface *iface) |
| { |
| iface->init = g_socket_initable_init; |
| } |
| |
| static void |
| g_socket_datagram_based_iface_init (GDatagramBasedInterface *iface) |
| { |
| iface->receive_messages = g_socket_datagram_based_receive_messages; |
| iface->send_messages = g_socket_datagram_based_send_messages; |
| iface->create_source = g_socket_datagram_based_create_source; |
| iface->condition_check = g_socket_datagram_based_condition_check; |
| iface->condition_wait = g_socket_datagram_based_condition_wait; |
| } |
| |
| static void |
| g_socket_init (GSocket *socket) |
| { |
| socket->priv = g_socket_get_instance_private (socket); |
| |
| socket->priv->fd = -1; |
| socket->priv->blocking = TRUE; |
| socket->priv->listen_backlog = 10; |
| socket->priv->construct_error = NULL; |
| #ifdef G_OS_WIN32 |
| socket->priv->event = WSA_INVALID_EVENT; |
| g_mutex_init (&socket->priv->win32_source_lock); |
| g_cond_init (&socket->priv->win32_source_cond); |
| #endif |
| } |
| |
| static gboolean |
| g_socket_initable_init (GInitable *initable, |
| GCancellable *cancellable, |
| GError **error) |
| { |
| GSocket *socket; |
| |
| g_return_val_if_fail (G_IS_SOCKET (initable), FALSE); |
| |
| socket = G_SOCKET (initable); |
| |
| if (cancellable != NULL) |
| { |
| g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, |
| _("Cancellable initialization not supported")); |
| return FALSE; |
| } |
| |
| socket->priv->inited = TRUE; |
| |
| if (socket->priv->construct_error) |
| { |
| if (error) |
| *error = g_error_copy (socket->priv->construct_error); |
| return FALSE; |
| } |
| |
| |
| return TRUE; |
| } |
| |
| static gboolean |
| check_datagram_based (GDatagramBased *self, |
| GError **error) |
| { |
| switch (g_socket_get_socket_type (G_SOCKET (self))) |
| { |
| case G_SOCKET_TYPE_INVALID: |
| case G_SOCKET_TYPE_STREAM: |
| g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, |
| _("Cannot use datagram operations on a non-datagram " |
| "socket.")); |
| return FALSE; |
| case G_SOCKET_TYPE_DATAGRAM: |
| case G_SOCKET_TYPE_SEQPACKET: |
| /* Fall through. */ |
| break; |
| } |
| |
| /* Due to us sharing #GSocketSource with the #GSocket implementation, it is |
| * pretty tricky to split out #GSocket:timeout so that it does not affect |
| * #GDatagramBased operations (but still affects #GSocket operations). It is |
| * not worth that effort — just disallow it and require the user to specify |
| * timeouts on a per-operation basis. */ |
| if (g_socket_get_timeout (G_SOCKET (self)) != 0) |
| { |
| g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, |
| _("Cannot use datagram operations on a socket with a " |
| "timeout set.")); |
| return FALSE; |
| } |
| |
| return TRUE; |
| } |
| |
| static gint |
| g_socket_datagram_based_receive_messages (GDatagramBased *self, |
| GInputMessage *messages, |
| guint num_messages, |
| gint flags, |
| gint64 timeout_us, |
| GCancellable *cancellable, |
| GError **error) |
| { |
| if (!check_datagram_based (self, error)) |
| return FALSE; |
| |
| return g_socket_receive_messages_with_timeout (G_SOCKET (self), messages, |
| num_messages, flags, timeout_us, |
| cancellable, error); |
| } |
| |
| static gint |
| g_socket_datagram_based_send_messages (GDatagramBased *self, |
| GOutputMessage *messages, |
| guint num_messages, |
| gint flags, |
| gint64 timeout_us, |
| GCancellable *cancellable, |
| GError **error) |
| { |
| if (!check_datagram_based (self, error)) |
| return FALSE; |
| |
| return g_socket_send_messages_with_timeout (G_SOCKET (self), messages, |
| num_messages, flags, timeout_us, |
| cancellable, error); |
| } |
| |
| static GSource * |
| g_socket_datagram_based_create_source (GDatagramBased *self, |
| GIOCondition condition, |
| GCancellable *cancellable) |
| { |
| if (!check_datagram_based (self, NULL)) |
| return NULL; |
| |
| return g_socket_create_source (G_SOCKET (self), condition, cancellable); |
| } |
| |
| static GIOCondition |
| g_socket_datagram_based_condition_check (GDatagramBased *datagram_based, |
| GIOCondition condition) |
| { |
| if (!check_datagram_based (datagram_based, NULL)) |
| return G_IO_ERR; |
| |
| return g_socket_condition_check (G_SOCKET (datagram_based), condition); |
| } |
| |
| static gboolean |
| g_socket_datagram_based_condition_wait (GDatagramBased *datagram_based, |
| GIOCondition condition, |
| gint64 timeout_us, |
| GCancellable *cancellable, |
| GError **error) |
| { |
| if (!check_datagram_based (datagram_based, error)) |
| return FALSE; |
| |
| return g_socket_condition_timed_wait (G_SOCKET (datagram_based), condition, |
| timeout_us, cancellable, error); |
| } |
| |
| /** |
| * g_socket_new: |
| * @family: the socket family to use, e.g. %G_SOCKET_FAMILY_IPV4. |
| * @type: the socket type to use. |
| * @protocol: the id of the protocol to use, or 0 for default. |
| * @error: #GError for error reporting, or %NULL to ignore. |
| * |
| * Creates a new #GSocket with the defined family, type and protocol. |
| * If @protocol is 0 (%G_SOCKET_PROTOCOL_DEFAULT) the default protocol type |
| * for the family and type is used. |
| * |
| * The @protocol is a family and type specific int that specifies what |
| * kind of protocol to use. #GSocketProtocol lists several common ones. |
| * Many families only support one protocol, and use 0 for this, others |
| * support several and using 0 means to use the default protocol for |
| * the family and type. |
| * |
| * The protocol id is passed directly to the operating |
| * system, so you can use protocols not listed in #GSocketProtocol if you |
| * know the protocol number used for it. |
| * |
| * Returns: a #GSocket or %NULL on error. |
| * Free the returned object with g_object_unref(). |
| * |
| * Since: 2.22 |
| */ |
| GSocket * |
| g_socket_new (GSocketFamily family, |
| GSocketType type, |
| GSocketProtocol protocol, |
| GError **error) |
| { |
| return G_SOCKET (g_initable_new (G_TYPE_SOCKET, |
| NULL, error, |
| "family", family, |
| "type", type, |
| "protocol", protocol, |
| NULL)); |
| } |
| |
| /** |
| * g_socket_new_from_fd: |
| * @fd: a native socket file descriptor. |
| * @error: #GError for error reporting, or %NULL to ignore. |
| * |
| * Creates a new #GSocket from a native file descriptor |
| * or winsock SOCKET handle. |
| * |
| * This reads all the settings from the file descriptor so that |
| * all properties should work. Note that the file descriptor |
| * will be set to non-blocking mode, independent on the blocking |
| * mode of the #GSocket. |
| * |
| * On success, the returned #GSocket takes ownership of @fd. On failure, the |
| * caller must close @fd themselves. |
| * |
| * Since GLib 2.46, it is no longer a fatal error to call this on a non-socket |
| * descriptor. Instead, a GError will be set with code %G_IO_ERROR_FAILED |
| * |
| * Returns: a #GSocket or %NULL on error. |
| * Free the returned object with g_object_unref(). |
| * |
| * Since: 2.22 |
| */ |
| GSocket * |
| g_socket_new_from_fd (gint fd, |
| GError **error) |
| { |
| return G_SOCKET (g_initable_new (G_TYPE_SOCKET, |
| NULL, error, |
| "fd", fd, |
| NULL)); |
| } |
| |
| /** |
| * g_socket_set_blocking: |
| * @socket: a #GSocket. |
| * @blocking: Whether to use blocking I/O or not. |
| * |
| * Sets the blocking mode of the socket. In blocking mode |
| * all operations (which don’t take an explicit blocking parameter) block until |
| * they succeed or there is an error. In |
| * non-blocking mode all functions return results immediately or |
| * with a %G_IO_ERROR_WOULD_BLOCK error. |
| * |
| * All sockets are created in blocking mode. However, note that the |
| * platform level socket is always non-blocking, and blocking mode |
| * is a GSocket level feature. |
| * |
| * Since: 2.22 |
| */ |
| void |
| g_socket_set_blocking (GSocket *socket, |
| gboolean blocking) |
| { |
| g_return_if_fail (G_IS_SOCKET (socket)); |
| |
| blocking = !!blocking; |
| |
| if (socket->priv->blocking == blocking) |
| return; |
| |
| socket->priv->blocking = blocking; |
| g_object_notify (G_OBJECT (socket), "blocking"); |
| } |
| |
| /** |
| * g_socket_get_blocking: |
| * @socket: a #GSocket. |
| * |
| * Gets the blocking mode of the socket. For details on blocking I/O, |
| * see g_socket_set_blocking(). |
| * |
| * Returns: %TRUE if blocking I/O is used, %FALSE otherwise. |
| * |
| * Since: 2.22 |
| */ |
| gboolean |
| g_socket_get_blocking (GSocket *socket) |
| { |
| g_return_val_if_fail (G_IS_SOCKET (socket), FALSE); |
| |
| return socket->priv->blocking; |
| } |
| |
| /** |
| * g_socket_set_keepalive: |
| * @socket: a #GSocket. |
| * @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. |
| * |
| * This option is only functional on certain kinds of sockets. (Notably, |
| * %G_SOCKET_PROTOCOL_TCP sockets.) |
| * |
| * 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) |
| { |
| GError *error = NULL; |
| |
| g_return_if_fail (G_IS_SOCKET (socket)); |
| |
| keepalive = !!keepalive; |
| if (socket->priv->keepalive == keepalive) |
| return; |
| |
| if (!g_socket_set_option (socket, SOL_SOCKET, SO_KEEPALIVE, |
| keepalive, &error)) |
| { |
| g_warning ("error setting keepalive: %s", error->message); |
| g_error_free (error); |
| return; |
| } |
| |
| socket->priv->keepalive = keepalive; |
| g_object_notify (G_OBJECT (socket), "keepalive"); |
| } |
| |
| /** |
| * g_socket_get_keepalive: |
| * @socket: a #GSocket. |
| * |
| * Gets the keepalive mode of the socket. For details on this, |
| * see g_socket_set_keepalive(). |
| * |
| * Returns: %TRUE if keepalive is active, %FALSE otherwise. |
| * |
| * Since: 2.22 |
| */ |
| gboolean |
| g_socket_get_keepalive (GSocket *socket) |
| { |
| g_return_val_if_fail (G_IS_SOCKET (socket), FALSE); |
| |
| return socket->priv->keepalive; |
| } |
| |
| /** |
| * g_socket_get_listen_backlog: |
| * @socket: a #GSocket. |
| * |
| * Gets the listen backlog setting of the socket. For details on this, |
| * see g_socket_set_listen_backlog(). |
| * |
| * Returns: the maximum number of pending connections. |
| * |
| * Since: 2.22 |
| */ |
| gint |
| g_socket_get_listen_backlog (GSocket *socket) |
| { |
| g_return_val_if_fail (G_IS_SOCKET (socket), 0); |
| |
| return socket->priv->listen_backlog; |
| } |
| |
| /** |
| * g_socket_set_listen_backlog: |
| * @socket: a #GSocket. |
| * @backlog: the maximum number of pending connections. |
| * |
| * Sets the maximum number of outstanding connections allowed |
| * when listening on this socket. If more clients than this are |
| * connecting to the socket and the application is not handling them |
| * on time then the new connections will be refused. |
| * |
| * Note that this must be called before g_socket_listen() and has no |
| * effect if called after that. |
| * |
| * Since: 2.22 |
| */ |
| void |
| g_socket_set_listen_backlog (GSocket *socket, |
| gint backlog) |
| { |
| g_return_if_fail (G_IS_SOCKET (socket)); |
| g_return_if_fail (!socket->priv->listening); |
| |
| if (backlog != socket->priv->listen_backlog) |
| { |
| socket->priv->listen_backlog = backlog; |
| g_object_notify (G_OBJECT (socket), "listen-backlog"); |
| } |
| } |
| |
| /** |
| * 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_ttl: |
| * @socket: a #GSocket. |
| * |
| * Gets the unicast time-to-live setting on @socket; see |
| * g_socket_set_ttl() for more details. |
| * |
| * Returns: the time-to-live setting on @socket |
| * |
| * Since: 2.32 |
| */ |
| guint |
| g_socket_get_ttl (GSocket *socket) |
| { |
| GError *error = NULL; |
| gint value; |
| |
| g_return_val_if_fail (G_IS_SOCKET (socket), 0); |
| |
| if (socket->priv->family == G_SOCKET_FAMILY_IPV4) |
| { |
| g_socket_get_option (socket, IPPROTO_IP, IP_TTL, |
| &value, &error); |
| } |
| else if (socket->priv->family == G_SOCKET_FAMILY_IPV6) |
| { |
| g_socket_get_option (socket, IPPROTO_IPV6, IPV6_UNICAST_HOPS, |
| &value, &error); |
| } |
| else |
| g_return_val_if_reached (0); |
| |
| if (error) |
| { |
| g_warning ("error getting unicast ttl: %s", error->message); |
| g_error_free (error); |
| return 0; |
| } |
| |
| return value; |
| } |
| |
| /** |
| * g_socket_set_ttl: |
| * @socket: a #GSocket. |
| * @ttl: the time-to-live value for all unicast packets on @socket |
| * |
| * Sets the time-to-live for outgoing unicast packets on @socket. |
| * By default the platform-specific default value is used. |
| * |
| * Since: 2.32 |
| */ |
| void |
| g_socket_set_ttl (GSocket *socket, |
| guint ttl) |
| { |
| GError *error = NULL; |
| |
| g_return_if_fail (G_IS_SOCKET (socket)); |
| |
| if (socket->priv->family == G_SOCKET_FAMILY_IPV4) |
| { |
| g_socket_set_option (socket, IPPROTO_IP, IP_TTL, |
| ttl, &error); |
| } |
| else if (socket->priv->family == G_SOCKET_FAMILY_IPV6) |
| { |
| g_socket_set_option (socket, IPPROTO_IP, IP_TTL, |
| ttl, NULL); |
| g_socket_set_option (socket, IPPROTO_IPV6, IPV6_UNICAST_HOPS, |
| ttl, &error); |
| } |
| else |
| g_return_if_reached (); |
| |
| if (error) |
| { |
| g_warning ("error setting unicast ttl: %s", error->message); |
| g_error_free (error); |
| return; |
| } |
| |
| g_object_notify (G_OBJECT (socket), "ttl"); |
| } |
| |
| /** |
| * g_socket_get_broadcast: |
| * @socket: a #GSocket. |
| * |
| * Gets the broadcast setting on @socket; if %TRUE, |
| * it is possible to send packets to broadcast |
| * addresses. |
| * |
| * Returns: the broadcast setting on @socket |
| * |
| * Since: 2.32 |
| */ |
| gboolean |
| g_socket_get_broadcast (GSocket *socket) |
| { |
| GError *error = NULL; |
| gint value; |
| |
| g_return_val_if_fail (G_IS_SOCKET (socket), FALSE); |
| |
| if (!g_socket_get_option (socket, SOL_SOCKET, SO_BROADCAST, |
| &value, &error)) |
| { |
| g_warning ("error getting broadcast: %s", error->message); |
| g_error_free (error); |
| return FALSE; |
| } |
| |
| return !!value; |
| } |
| |
| /** |
| * g_socket_set_broadcast: |
| * @socket: a #GSocket. |
| * @broadcast: whether @socket should allow sending to broadcast |
| * addresses |
| * |
| * Sets whether @socket should allow sending to broadcast addresses. |
| * This is %FALSE by default. |
| * |
| * Since: 2.32 |
| */ |
| void |
| g_socket_set_broadcast (GSocket *socket, |
| gboolean broadcast) |
| { |
| GError *error = NULL; |
| |
| g_return_if_fail (G_IS_SOCKET (socket)); |
| |
| broadcast = !!broadcast; |
| |
| if (!g_socket_set_option (socket, SOL_SOCKET, SO_BROADCAST, |
| broadcast, &error)) |
| { |
| g_warning ("error setting broadcast: %s", error->message); |
| g_error_free (error); |
| return; |
| } |
| |
| g_object_notify (G_OBJECT (socket), "broadcast"); |
| } |
| |
| /** |
| * g_socket_get_multicast_loopback: |
| * @socket: a #GSocket. |
| * |
| * Gets the multicast loopback setting on @socket; if %TRUE (the |
| * default), outgoing multicast packets will be looped back to |
| * multicast listeners on the same host. |
| * |
| * Returns: the multicast loopback setting on @socket |
| * |
| * Since: 2.32 |
| */ |
| gboolean |
| g_socket_get_multicast_loopback (GSocket *socket) |
| { |
| GError *error = NULL; |
| gint value; |
| |
| g_return_val_if_fail (G_IS_SOCKET (socket), FALSE); |
| |
| if (socket->priv->family == G_SOCKET_FAMILY_IPV4) |
| { |
| g_socket_get_option (socket, IPPROTO_IP, IP_MULTICAST_LOOP, |
| &value, &error); |
| } |
| else if (socket->priv->family == G_SOCKET_FAMILY_IPV6) |
| { |
| g_socket_get_option (socket, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, |
| &value, &error); |
| } |
| else |
| g_return_val_if_reached (FALSE); |
| |
| if (error) |
| { |
| g_warning ("error getting multicast loopback: %s", error->message); |
| g_error_free (error); |
| return FALSE; |
| } |
| |
| return !!value; |
| } |
| |
| /** |
| * g_socket_set_multicast_loopback: |
| * @socket: a #GSocket. |
| * @loopback: whether @socket should receive messages sent to its |
| * multicast groups from the local host |
| * |
| * Sets whether outgoing multicast packets will be received by sockets |
| * listening on that multicast address on the same host. This is %TRUE |
| * by default. |
| * |
| * Since: 2.32 |
| */ |
| void |
| g_socket_set_multicast_loopback (GSocket *socket, |
| gboolean loopback) |
| { |
| GError *error = NULL; |
| |
| g_return_if_fail (G_IS_SOCKET (socket)); |
| |
| loopback = !!loopback; |
| |
| if (socket->priv->family == G_SOCKET_FAMILY_IPV4) |
| { |
| g_socket_set_option (socket, IPPROTO_IP, IP_MULTICAST_LOOP, |
| loopback, &error); |
| } |
| else if (socket->priv->family == G_SOCKET_FAMILY_IPV6) |
| { |
| g_socket_set_option (socket, IPPROTO_IP, IP_MULTICAST_LOOP, |
| loopback, NULL); |
| g_socket_set_option (socket, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, |
| loopback, &error); |
| } |
| else |
| g_return_if_reached (); |
| |
| if (error) |
| { |
| g_warning ("error setting multicast loopback: %s", error->message); |
| g_error_free (error); |
| return; |
| } |
| |
| g_object_notify (G_OBJECT (socket), "multicast-loopback"); |
| } |
| |
| /** |
| * g_socket_get_multicast_ttl: |
| * @socket: a #GSocket. |
| * |
| * Gets the multicast time-to-live setting on @socket; see |
| * g_socket_set_multicast_ttl() for more details. |
| * |
| * Returns: the multicast time-to-live setting on @socket |
| * |
| * Since: 2.32 |
| */ |
| guint |
| g_socket_get_multicast_ttl (GSocket *socket) |
| { |
| GError *error = NULL; |
| gint value; |
| |
| g_return_val_if_fail (G_IS_SOCKET (socket), 0); |
| |
| if (socket->priv->family == G_SOCKET_FAMILY_IPV4) |
| { |
| g_socket_get_option (socket, IPPROTO_IP, IP_MULTICAST_TTL, |
| &value, &error); |
| } |
| else if (socket->priv->family == G_SOCKET_FAMILY_IPV6) |
| { |
| g_socket_get_option (socket, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, |
| &value, &error); |
| } |
| else |
| g_return_val_if_reached (FALSE); |
| |
| if (error) |
| { |
| g_warning ("error getting multicast ttl: %s", error->message); |
| g_error_free (error); |
| return FALSE; |
| } |
| |
| return value; |
| } |
| |
| /** |
| * g_socket_set_multicast_ttl: |
| * @socket: a #GSocket. |
| * @ttl: the time-to-live value for all multicast datagrams on @socket |
| * |
| * Sets the time-to-live for outgoing multicast datagrams on @socket. |
| * By default, this is 1, meaning that multicast packets will not leave |
| * the local network. |
| * |
| * Since: 2.32 |
| */ |
| void |
| g_socket_set_multicast_ttl (GSocket *socket, |
| guint ttl) |
| { |
| GError *error = NULL; |
| |
| g_return_if_fail (G_IS_SOCKET (socket)); |
| |
| if (socket->priv->family == G_SOCKET_FAMILY_IPV4) |
| { |
| g_socket_set_option (socket, IPPROTO_IP, IP_MULTICAST_TTL, |
| ttl, &error); |
| } |
| else if (socket->priv->family == G_SOCKET_FAMILY_IPV6) |
| { |
| g_socket_set_option (socket, IPPROTO_IP, IP_MULTICAST_TTL, |
| ttl, NULL); |
| g_socket_set_option (socket, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, |
| ttl, &error); |
| } |
| else |
| g_return_if_reached (); |
| |
| if (error) |
| { |
| g_warning ("error setting multicast ttl: %s", error->message); |
| g_error_free (error); |
| return; |
| } |
| |
| g_object_notify (G_OBJECT (socket), "multicast-ttl"); |
| } |
| |
| /** |
| * g_socket_get_family: |
| * @socket: a #GSocket. |
| * |
| * Gets the socket family of the socket. |
| * |
| * Returns: a #GSocketFamily |
| * |
| * Since: 2.22 |
| */ |
| GSocketFamily |
| g_socket_get_family (GSocket *socket) |
| { |
| g_return_val_if_fail (G_IS_SOCKET (socket), G_SOCKET_FAMILY_INVALID); |
| |
| return socket->priv->family; |
| } |
| |
| /** |
| * g_socket_get_socket_type: |
| * @socket: a #GSocket. |
| * |
| * Gets the socket type of the socket. |
| * |
| * Returns: a #GSocketType |
| * |
| * Since: 2.22 |
| */ |
| GSocketType |
| g_socket_get_socket_type (GSocket *socket) |
| { |
| g_return_val_if_fail (G_IS_SOCKET (socket), G_SOCKET_TYPE_INVALID); |
| |
| return socket->priv->type; |
| } |
| |
| /** |
| * g_socket_get_protocol: |
| * @socket: a #GSocket. |
| * |
| * Gets the socket protocol id the socket was created with. |
| * In case the protocol is unknown, -1 is returned. |
| * |
| * Returns: a protocol id, or -1 if unknown |
| * |
| * Since: 2.22 |
| */ |
| GSocketProtocol |
| g_socket_get_protocol (GSocket *socket) |
| { |
| g_return_val_if_fail (G_IS_SOCKET (socket), -1); |
| |
| return socket->priv->protocol; |
| } |
| |
| /** |
| * g_socket_get_fd: |
| * @socket: a #GSocket. |
| * |
| * Returns the underlying OS socket object. On unix this |
| * is a socket file descriptor, and on Windows this is |
| * a Winsock2 SOCKET handle. This may be useful for |
| * doing platform specific or otherwise unusual operations |
| * on the socket. |
| * |
| * Returns: the file descriptor of the socket. |
| * |
| * Since: 2.22 |
| */ |
| int |
| g_socket_get_fd (GSocket *socket) |
| { |
| g_return_val_if_fail (G_IS_SOCKET (socket), -1); |
| |
| return socket->priv->fd; |
| } |
| |
| /** |
| * g_socket_get_local_address: |
| * @socket: a #GSocket. |
| * @error: #GError for error reporting, or %NULL to ignore. |
| * |
| * Try to get the local address of a bound socket. This is only |
| * useful if the socket has been bound to a local address, |
| * either explicitly or implicitly when connecting. |
| * |
| * 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) |
| { |
| union { |
| struct sockaddr_storage storage; |
| struct sockaddr sa; |
| } buffer; |
| socklen_t len = sizeof (buffer); |
| |
| g_return_val_if_fail (G_IS_SOCKET (socket), NULL); |
| |
| if (getsockname (socket->priv->fd, &buffer.sa, &len) < 0) |
| { |
| int errsv = get_socket_errno (); |
| g_set_error (error, G_IO_ERROR, socket_io_error_from_errno (errsv), |
| _("could not get local address: %s"), socket_strerror (errsv)); |
| return NULL; |
| } |
| |
| return g_socket_address_new_from_native (&buffer.storage, len); |
| } |
| |
| /** |
| * g_socket_get_remote_address: |
| * @socket: a #GSocket. |
| * @error: #GError for error reporting, or %NULL to ignore. |
| * |
| * Try to get the remote address of a connected socket. This is only |
| * useful for connection oriented sockets that have been connected. |
| * |
| * 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) |
| { |
| union { |
| struct sockaddr_storage storage; |
| struct sockaddr sa; |
| } buffer; |
| socklen_t len = sizeof (buffer); |
| |
| g_return_val_if_fail (G_IS_SOCKET (socket), NULL); |
| |
| if (socket->priv->connect_pending) |
| { |
| if (!g_socket_check_connect_result (socket, error)) |
| return NULL; |
| else |
| socket->priv->connect_pending = FALSE; |
| } |
| |
| if (!socket->priv->remote_address) |
| { |
| if (getpeername (socket->priv->fd, &buffer.sa, &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.storage, len); |
| } |
| |
| return g_object_ref (socket->priv->remote_address); |
| } |
| |
| /** |
| * g_socket_is_connected: |
| * @socket: a #GSocket. |
| * |
| * Check whether the socket is connected. This is only useful for |
| * connection-oriented sockets. |
| * |
| * If using g_socket_shutdown(), this function will return %TRUE until the |
| * socket has been shut down for reading and writing. If you do a non-blocking |
| * connect, this function will not return %TRUE until after you call |
| * g_socket_check_connect_result(). |
| * |
| * Returns: %TRUE if socket is connected, %FALSE otherwise. |
| * |
| * Since: 2.22 |
| */ |
| gboolean |
| g_socket_is_connected (GSocket *socket) |
| { |
| g_return_val_if_fail (G_IS_SOCKET (socket), FALSE); |
| |
| return (socket->priv->connected_read || socket->priv->connected_write); |
| } |
| |
| /** |
| * g_socket_listen: |
| * @socket: a #GSocket. |
| * @error: #GError for error reporting, or %NULL to ignore. |
| * |
| * Marks the socket as a server socket, i.e. a socket that is used |
| * to accept incoming requests using g_socket_accept(). |
| * |
| * Before calling this the socket must be bound to a local address using |
| * g_socket_bind(). |
| * |
| * To set the maximum amount of outstanding clients, use |
| * g_socket_set_listen_backlog(). |
| * |
| * Returns: %TRUE on success, %FALSE on error. |
| * |
| * Since: 2.22 |
| */ |
| gboolean |
| g_socket_listen (GSocket *socket, |
| GError **error) |
| { |
| g_return_val_if_fail (G_IS_SOCKET (socket), FALSE); |
| |
| if (!check_socket (socket, error)) |
| return FALSE; |
| |
| if (listen (socket->priv->fd, socket->priv->listen_backlog) < 0) |
| { |
| int errsv = get_socket_errno (); |
| |
| g_set_error (error, G_IO_ERROR, socket_io_error_from_errno (errsv), |
| _("could not listen: %s"), socket_strerror (errsv)); |
| return FALSE; |
| } |
| |
| socket->priv->listening = TRUE; |
| |
| return TRUE; |
| } |
| |
| /** |
| * g_socket_bind: |
| * @socket: a #GSocket. |
| * @address: a #GSocketAddress specifying the local address. |
| * @allow_reuse: whether to allow reusing this address |
| * @error: #GError for error reporting, or %NULL to ignore. |
| * |
| * When a socket is created it is attached to an address family, but it |
| * doesn't have an address in this family. g_socket_bind() assigns the |
| * address (sometimes called name) of the socket. |
| * |
| * It is generally required to bind to a local address before you can |
| * receive connections. (See g_socket_listen() and g_socket_accept() ). |
| * In certain situations, you may also want to bind a socket that will be |
| * 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.) |
| * |
| * If @socket is a UDP socket, then @allow_reuse determines whether or |
| * not other UDP sockets can be bound to the same address at the same |
| * time. In particular, you can have several UDP sockets bound to the |
| * same address, and they will all receive all of the multicast and |
| * broadcast packets sent to that address. (The behavior of unicast |
| * UDP packets to an address with multiple listeners is not defined.) |
| * |
| * Returns: %TRUE on success, %FALSE on error. |
| * |
| * Since: 2.22 |
| */ |
| gboolean |
| g_socket_bind (GSocket *socket, |
| GSocketAddress *address, |
| gboolean reuse_address, |
| GError **error) |
| { |
| union { |
| struct sockaddr_storage storage; |
| struct sockaddr sa; |
| } addr; |
| gboolean so_reuseaddr; |
| #ifdef SO_REUSEPORT |
| gboolean so_reuseport; |
| #endif |
| |
| g_return_val_if_fail (G_IS_SOCKET (socket) && G_IS_SOCKET_ADDRESS (address), FALSE); |
| |
| if (!check_socket (socket, error)) |
| return FALSE; |
| |
| if (!g_socket_address_to_native (address, &addr.storage, sizeof addr, error)) |
| return FALSE; |
| |
| /* On Windows, SO_REUSEADDR has the semantics we want for UDP |
| * sockets, but has nasty side effects we don't want for TCP |
| * sockets. |
| * |
| * On other platforms, we set SO_REUSEPORT, if it exists, for |
| * UDP sockets, and SO_REUSEADDR for all sockets, hoping that |
| * if SO_REUSEPORT doesn't exist, then SO_REUSEADDR will have |
| * the desired semantics on UDP (as it does on Linux, although |
| * Linux has SO_REUSEPORT too as of 3.9). |
| */ |
| |
| #ifdef G_OS_WIN32 |
| so_reuseaddr = reuse_address && (socket->priv->type == G_SOCKET_TYPE_DATAGRAM); |
| #else |
| so_reuseaddr = !!reuse_address; |
| #endif |
| |
| #ifdef SO_REUSEPORT |
| so_reuseport = reuse_address && (socket->priv->type == G_SOCKET_TYPE_DATAGRAM); |
| #endif |
| |
| /* Ignore errors here, the only likely error is "not supported", and |
| * this is a "best effort" thing mainly. |
| */ |
| g_socket_set_option (socket, SOL_SOCKET, SO_REUSEADDR, so_reuseaddr, NULL); |
| #ifdef SO_REUSEPORT |
| g_socket_set_option (socket, SOL_SOCKET, SO_REUSEPORT, so_reuseport, NULL); |
| #endif |
| |
| if (bind (socket->priv->fd, &addr.sa, |
| g_socket_address_get_native_size (address)) < 0) |
| { |
| int errsv = get_socket_errno (); |
| gchar *address_string = address_to_string (address); |
| |
| g_set_error (error, |
| G_IO_ERROR, socket_io_error_from_errno (errsv), |
| _("Error binding to address %s: %s"), |
| address_string, socket_strerror (errsv)); |
| g_free (address_string); |
| return FALSE; |
| } |
| |
| return TRUE; |
| } |
| |
| #ifdef G_OS_WIN32 |
| static gulong |
| g_socket_w32_get_adapter_ipv4_addr (const gchar *name_or_ip) |
| { |
| ULONG bufsize = 15000; /* MS-recommended initial bufsize */ |
| DWORD ret = ERROR_BUFFER_OVERFLOW; |
| unsigned int malloc_iterations = 0; |
| PIP_ADAPTER_ADDRESSES addr_buf = NULL, eth_adapter; |
| wchar_t *wchar_name_or_ip = NULL; |
| gulong ip_result = 0; |
| NET_IFINDEX if_index; |
| |
| /* |
| * For Windows OS only - return adapter IPv4 address in network byte order. |
| * |
| * Input string can be either friendly name of adapter, IP address of adapter, |
| * indextoname, or fullname of adapter. |
| * Example: |
| * 192.168.1.109 ===> IP address given directly, |
| * convert directly with inet_addr() function |
| * Wi-Fi ===> Adapter friendly name "Wi-Fi", |
| * scan with GetAdapterAddresses and adapter->FriendlyName |
| * ethernet_32774 ===> Adapter name as returned by if_indextoname |
| * {33E8F5CD-BAEA-4214-BE13-B79AB8080CAB} ===> Adaptername, |
| * as returned in GetAdapterAddresses and adapter->AdapterName |
| */ |
| |
| /* Step 1: Check if string is an IP address: */ |
| if (inet_pton (AF_INET, name_or_ip, &ip_result) == 1) |
| return ip_result; /* Success, IP address string was given directly */ |
| |
| /* |
| * Step 2: Check if name represents a valid Interface index (e.g. ethernet_75521) |
| * function if_nametoindex will return >=1 if a valid index, or 0=no match |
| * valid index will be used later in GetAdaptersAddress loop for lookup of adapter IP address |
| */ |
| if_index = if_nametoindex (name_or_ip); |
| |
| /* Step 3: Prepare wchar string for friendly name comparison */ |
| if (if_index == 0) |
| { |
| size_t if_name_len = strlen (name_or_ip); |
| if (if_name_len >= MAX_ADAPTER_NAME_LENGTH + 4) |
| return INADDR_NONE; |
| /* Name-check only needed if index=0... */ |
| wchar_name_or_ip = (wchar_t *) g_try_malloc ((if_name_len + 1) * sizeof(wchar_t)); |
| if (wchar_name_or_ip) |
| mbstowcs (wchar_name_or_ip, name_or_ip, if_name_len + 1); |
| /* NOTE: Even if malloc fails here, some comparisons can still be done later... so no exit here! */ |
| } |
| |
| /* |
| * Step 4: Allocate memory and get adapter addresses. |
| * Buffer allocation loop recommended by MS, since size can be dynamic |
| * https://docs.microsoft.com/en-us/windows/desktop/api/iphlpapi/nf-iphlpapi-getadaptersaddresses |
| */ |
| #define MAX_ALLOC_ITERATIONS 3 |
| do |
| { |
| malloc_iterations++; |
| addr_buf = (PIP_ADAPTER_ADDRESSES) g_try_realloc (addr_buf, bufsize); |
| if (addr_buf) |
| ret = GetAdaptersAddresses (AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, addr_buf, &bufsize); |
| } |
| while (addr_buf && |
| ret == ERROR_BUFFER_OVERFLOW && |
| malloc_iterations < MAX_ALLOC_ITERATIONS); |
| #undef MAX_ALLOC_ITERATIONS |
| |
| if (addr_buf == 0 || ret != NO_ERROR) |
| { |
| g_free (addr_buf); |
| g_free (wchar_name_or_ip); |
| return INADDR_NONE; |
| } |
| |
| /* Step 5: Loop through adapters and check match for index or name */ |
| for (eth_adapter = addr_buf; eth_adapter != NULL; eth_adapter = eth_adapter->Next) |
| { |
| /* Check if match for interface index/name: */ |
| gboolean any_match = (if_index > 0) && (eth_adapter->IfIndex == if_index); |
| |
| /* Check if match for friendly name - but only if NO if_index! */ |
| if (!any_match && if_index == 0 && eth_adapter->FriendlyName && |
| eth_adapter->FriendlyName[0] != 0 && wchar_name_or_ip != NULL) |
| any_match = (_wcsicmp (eth_adapter->FriendlyName, wchar_name_or_ip) == 0); |
| |
| /* Check if match for adapter low level name - but only if NO if_index: */ |
| if (!any_match && if_index == 0 && eth_adapter->AdapterName && |
| eth_adapter->AdapterName[0] != 0) |
| any_match = (stricmp (eth_adapter->AdapterName, name_or_ip) == 0); |
| |
| if (any_match) |
| { |
| /* We have match for this adapter, lets get its local unicast IP address! */ |
| PIP_ADAPTER_UNICAST_ADDRESS uni_addr; |
| for (uni_addr = eth_adapter->FirstUnicastAddress; |
| uni_addr != NULL; uni_addr = uni_addr->Next) |
| { |
| if (uni_addr->Address.lpSockaddr->sa_family == AF_INET) |
| { |
| ip_result = ((PSOCKADDR_IN) uni_addr->Address.lpSockaddr)->sin_addr.S_un.S_addr; |
| break; /* finished, exit unicast addr loop */ |
| } |
| } |
| } |
| } |
| |
| g_free (addr_buf); |
| g_free (wchar_name_or_ip); |
| |
| return ip_result; |
| } |
| #endif |
| |
| static gboolean |
| g_socket_multicast_group_operation (GSocket *socket, |
| GInetAddress *group, |
| gboolean source_specific, |
| const gchar *iface, |
| gboolean join_group, |
| GError **error) |
| { |
| const guint8 *native_addr; |
| gint optname, result; |
| |
| g_return_val_if_fail (G_IS_SOCKET (socket), FALSE); |
| g_return_val_if_fail (socket->priv->type == G_SOCKET_TYPE_DATAGRAM, FALSE); |
| g_return_val_if_fail (G_IS_INET_ADDRESS (group), FALSE); |
| |
| if (!check_socket (socket, error)) |
| return FALSE; |
| |
| native_addr = g_inet_address_to_bytes (group); |
| if (g_inet_address_get_family (group) == G_SOCKET_FAMILY_IPV4) |
| { |
| #ifdef HAVE_IP_MREQN |
| struct ip_mreqn mc_req; |
| #else |
| struct ip_mreq mc_req; |
| #endif |
| |
| memset (&mc_req, 0, sizeof (mc_req)); |
| memcpy (&mc_req.imr_multiaddr, native_addr, sizeof (struct in_addr)); |
| |
| #ifdef HAVE_IP_MREQN |
| if (iface) |
| mc_req.imr_ifindex = if_nametoindex (iface); |
| else |
| mc_req.imr_ifindex = 0; /* Pick any. */ |
| #elif defined(G_OS_WIN32) |
| if (iface) |
| mc_req.imr_interface.s_addr = g_socket_w32_get_adapter_ipv4_addr (iface); |
| else |
| mc_req.imr_interface.s_addr = g_htonl (INADDR_ANY); |
| #else |
| mc_req.imr_interface.s_addr = g_htonl (INADDR_ANY); |
| #endif |
| |
| if (source_specific) |
| { |
| #ifdef IP_ADD_SOURCE_MEMBERSHIP |
| optname = join_group ? IP_ADD_SOURCE_MEMBERSHIP : IP_DROP_SOURCE_MEMBERSHIP; |
| #else |
| g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, |
| join_group ? |
| _("Error joining multicast group: %s") : |
| _("Error leaving multicast group: %s"), |
| _("No support for source-specific multicast")); |
| return FALSE; |
| #endif |
| } |
| else |
| optname = join_group ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP; |
| result = setsockopt (socket->priv->fd, IPPROTO_IP, optname, |
| &mc_req, sizeof (mc_req)); |
| } |
| else if (g_inet_address_get_family (group) == G_SOCKET_FAMILY_IPV6) |
| { |
| struct ipv6_mreq mc_req_ipv6; |
| |
| memset (&mc_req_ipv6, 0, sizeof (mc_req_ipv6)); |
| memcpy (&mc_req_ipv6.ipv6mr_multiaddr, native_addr, sizeof (struct in6_addr)); |
| #ifdef HAVE_IF_NAMETOINDEX |
| if (iface) |
| mc_req_ipv6.ipv6mr_interface = if_nametoindex (iface); |
| else |
| #endif |
| mc_req_ipv6.ipv6mr_interface = 0; |
| |
| optname = join_group ? IPV6_JOIN_GROUP : IPV6_LEAVE_GROUP; |
| result = setsockopt (socket->priv->fd, IPPROTO_IPV6, optname, |
| &mc_req_ipv6, sizeof (mc_req_ipv6)); |
| } |
| else |
| g_return_val_if_reached (FALSE); |
| |
| if (result < 0) |
| { |
| int errsv = get_socket_errno (); |
| |
| g_set_error (error, G_IO_ERROR, socket_io_error_from_errno (errsv), |
| join_group ? |
| _("Error joining multicast group: %s") : |
| _("Error leaving multicast group: %s"), |
| socket_strerror (errsv)); |
| return FALSE; |
| } |
| |
| return TRUE; |
| } |
| |
| /** |
| * g_socket_join_multicast_group: |
| * @socket: a #GSocket. |
| * @group: a #GInetAddress specifying the group address to join. |
| * @iface: (nullable): Name of the interface to use, or %NULL |
| * @source_specific: %TRUE if source-specific multicast should be used |
| * @error: #GError for error reporting, or %NULL to ignore. |
| * |
| * Registers @socket to receive multicast messages sent to @group. |
| * @socket must be a %G_SOCKET_TYPE_DATAGRAM socket, and must have |
| * been bound to an appropriate interface and port with |
| * g_socket_bind(). |
| * |
| * If @iface is %NULL, the system will automatically pick an interface |
| * to bind to based on @group. |
| * |
| * If @source_specific is %TRUE, source-specific multicast as defined |
| * in RFC 4604 is used. Note that on older platforms this may fail |
| * with a %G_IO_ERROR_NOT_SUPPORTED error. |
| * |
| * To bind to a given source-specific multicast address, use |
| * g_socket_join_multicast_group_ssm() instead. |
| * |
| * Returns: %TRUE on success, %FALSE on error. |
| * |
| * Since: 2.32 |
| */ |
| gboolean |
| g_socket_join_multicast_group (GSocket *socket, |
| GInetAddress *group, |
| gboolean source_specific, |
| const gchar *iface, |
| GError **error) |
| { |
| return g_socket_multicast_group_operation (socket, group, source_specific, iface, TRUE, error); |
| } |
| |
| /** |
| * g_socket_leave_multicast_group: |
| * @socket: a #GSocket. |
| * @group: a #GInetAddress specifying the group address to leave. |
| * @iface: (nullable): Interface used |
| * @source_specific: %TRUE if source-specific multicast was used |
| * @error: #GError for error reporting, or %NULL to ignore. |
| * |
| * Removes @socket from the multicast group defined by @group, @iface, |
| * and @source_specific (which must all have the same values they had |
| * when you joined the group). |
| * |
| * @socket remains bound to its address and port, and can still receive |
| * unicast messages after calling this. |
| * |
| * To unbind to a given source-specific multicast address, use |
| * g_socket_leave_multicast_group_ssm() instead. |
| * |
| * Returns: %TRUE on success, %FALSE on error. |
| * |
| * Since: 2.32 |
| */ |
| gboolean |
| g_socket_leave_multicast_group (GSocket *socket, |
| GInetAddress *group, |
| gboolean source_specific, |
| const gchar *iface, |
| GError **error) |
| { |
| return g_socket_multicast_group_operation (socket, group, source_specific, iface, FALSE, error); |
| } |
| |
| static gboolean |
| g_socket_multicast_group_operation_ssm (GSocket *socket, |
| GInetAddress *group, |
| GInetAddress *source_specific, |
| const gchar *iface, |
| gboolean join_group, |
| GError **error) |
| { |
| gint result; |
| |
| g_return_val_if_fail (G_IS_SOCKET (socket), FALSE); |
| g_return_val_if_fail (socket->priv->type == G_SOCKET_TYPE_DATAGRAM, FALSE); |
| g_return_val_if_fail (G_IS_INET_ADDRESS (group), FALSE); |
| g_return_val_if_fail (iface == NULL || *iface != '\0', FALSE); |
| g_return_val_if_fail (error == NULL || *error == NULL, FALSE); |
| |
| if (!source_specific) |
| { |
| return g_socket_multicast_group_operation (socket, group, FALSE, iface, |
| join_group, error); |
| } |
| |
| if (!check_socket (socket, error)) |
| return FALSE; |
| |
| switch (g_inet_address_get_family (group)) |
| { |
| case G_SOCKET_FAMILY_INVALID: |
| case G_SOCKET_FAMILY_UNIX: |
| { |
| g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, |
| join_group ? |
| _("Error joining multicast group: %s") : |
| _("Error leaving multicast group: %s"), |
| _("Unsupported socket family")); |
| return FALSE; |
| } |
| break; |
| |
| case G_SOCKET_FAMILY_IPV4: |
| { |
| #ifdef IP_ADD_SOURCE_MEMBERSHIP |
| |
| #ifdef BROKEN_IP_MREQ_SOURCE_STRUCT |
| #define S_ADDR_FIELD(src) src.imr_interface |
| #else |
| #define S_ADDR_FIELD(src) src.imr_interface.s_addr |
| #endif |
| |
| gint optname; |
| struct ip_mreq_source mc_req_src; |
| |
| if (g_inet_address_get_family (source_specific) != |
| G_SOCKET_FAMILY_IPV4) |
| { |
| g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, |
| join_group ? |
| _("Error joining multicast group: %s") : |
| _("Error leaving multicast group: %s"), |
| _("source-specific not an IPv4 address")); |
| return FALSE; |
| } |
| |
| memset (&mc_req_src, 0, sizeof (mc_req_src)); |
| |
| /* By default use the default IPv4 multicast interface. */ |
| S_ADDR_FIELD(mc_req_src) = g_htonl (INADDR_ANY); |
| |
| if (iface) |
| { |
| #if defined(G_OS_WIN32) |
| S_ADDR_FIELD(mc_req_src) = g_socket_w32_get_adapter_ipv4_addr (iface); |
| #elif defined (HAVE_SIOCGIFADDR) |
| int ret; |
| struct ifreq ifr; |
| struct sockaddr_in *iface_addr; |
| size_t if_name_len = strlen (iface); |
| |
| memset (&ifr, 0, sizeof (ifr)); |
| |
| if (if_name_len >= sizeof (ifr.ifr_name)) |
| { |
| g_set_error (error, G_IO_ERROR, G_IO_ERROR_FILENAME_TOO_LONG, |
| _("Interface name too long")); |
| return FALSE; |
| } |
| |
| memcpy (ifr.ifr_name, iface, if_name_len); |
| |
| /* Get the IPv4 address of the given network interface name. */ |
| ret = ioctl (socket->priv->fd, SIOCGIFADDR, &ifr); |
| if (ret < 0) |
| { |
| int errsv = errno; |
| |
| g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv), |
| _("Interface not found: %s"), g_strerror (errsv)); |
| return FALSE; |
| } |
| |
| iface_addr = (struct sockaddr_in *) &ifr.ifr_addr; |
| S_ADDR_FIELD(mc_req_src) = iface_addr->sin_addr.s_addr; |
| #endif /* defined(G_OS_WIN32) && defined (HAVE_IF_NAMETOINDEX) */ |
| } |
| |
| g_assert (g_inet_address_get_native_size (group) == sizeof (mc_req_src.imr_multiaddr)); |
| memcpy (&mc_req_src.imr_multiaddr, g_inet_address_to_bytes (group), |
| g_inet_address_get_native_size (group)); |
| |
| g_assert (g_inet_address_get_native_size (source_specific) == sizeof (mc_req_src.imr_sourceaddr)); |
| memcpy (&mc_req_src.imr_sourceaddr, |
| g_inet_address_to_bytes (source_specific), |
| g_inet_address_get_native_size (source_specific)); |
| |
| optname = |
| join_group ? IP_ADD_SOURCE_MEMBERSHIP : IP_DROP_SOURCE_MEMBERSHIP; |
| result = setsockopt (socket->priv->fd, IPPROTO_IP, optname, |
| &mc_req_src, sizeof (mc_req_src)); |
| |
| #undef S_ADDR_FIELD |
| |
| #else |
| g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, |
| join_group ? |
| _("Error joining multicast group: %s") : |
| _("Error leaving multicast group: %s"), |
| _("No support for IPv4 source-specific multicast")); |
| return FALSE; |
| #endif /* IP_ADD_SOURCE_MEMBERSHIP */ |
| } |
| break; |
| |
| case G_SOCKET_FAMILY_IPV6: |
| { |
| #ifdef MCAST_JOIN_SOURCE_GROUP |
| gboolean res; |
| gint optname; |
| struct group_source_req mc_req_src; |
| GSocketAddress *saddr_group, *saddr_source_specific; |
| guint iface_index = 0; |
| |
| #if defined (HAVE_IF_NAMETOINDEX) |
| if (iface) |
| { |
| iface_index = if_nametoindex (iface); |
| if (iface_index == 0) |
| { |
| int errsv = errno; |
| |
| g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv), |
| _("Interface not found: %s"), g_strerror (errsv)); |
| return FALSE; |
| } |
| } |
| #endif /* defined (HAVE_IF_NAMETOINDEX) */ |
| mc_req_src.gsr_interface = iface_index; |
| |
| saddr_group = g_inet_socket_address_new (group, 0); |
| res = g_socket_address_to_native (saddr_group, &mc_req_src.gsr_group, |
| sizeof (mc_req_src.gsr_group), |
| error); |
| g_object_unref (saddr_group); |
| if (!res) |
| return FALSE; |
| |
| saddr_source_specific = g_inet_socket_address_new (source_specific, 0); |
| res = g_socket_address_to_native (saddr_source_specific, |
| &mc_req_src.gsr_source, |
| sizeof (mc_req_src.gsr_source), |
| error); |
| g_object_unref (saddr_source_specific); |
| |
| if (!res) |
| return FALSE; |
| |
| optname = |
| join_group ? MCAST_JOIN_SOURCE_GROUP : MCAST_LEAVE_SOURCE_GROUP; |
| result = setsockopt (socket->priv->fd, IPPROTO_IPV6, optname, |
| &mc_req_src, sizeof (mc_req_src)); |
| #else |
| g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, |
| join_group ? |
| _("Error joining multicast group: %s") : |
| _("Error leaving multicast group: %s"), |
| _("No support for IPv6 source-specific multicast")); |
| return FALSE; |
| #endif /* MCAST_JOIN_SOURCE_GROUP */ |
| } |
| break; |
| |
| default: |
| g_return_val_if_reached (FALSE); |
| } |
| |
| if (result < 0) |
| { |
| int errsv = get_socket_errno (); |
| |
| g_set_error (error, G_IO_ERROR, socket_io_error_from_errno (errsv), |
| join_group ? |
| _("Error joining multicast group: %s") : |
| _("Error leaving multicast group: %s"), |
| socket_strerror (errsv)); |
| return FALSE; |
| } |
| |
| return TRUE; |
| } |
| |
| /** |
| * g_socket_join_multicast_group_ssm: |
| * @socket: a #GSocket. |
| * @group: a #GInetAddress specifying the group address to join. |
| * @source_specific: (nullable): a #GInetAddress specifying the |
| * source-specific multicast address or %NULL to ignore. |
| * @iface: (nullable): Name of the interface to use, or %NULL |
| * @error: #GError for error reporting, or %NULL to ignore. |
| * |
| * Registers @socket to receive multicast messages sent to @group. |
| * @socket must be a %G_SOCKET_TYPE_DATAGRAM socket, and must have |
| * been bound to an appropriate interface and port with |
| * g_socket_bind(). |
| * |
| * If @iface is %NULL, the system will automatically pick an interface |
| * to bind to based on @group. |
| * |
| * If @source_specific is not %NULL, use source-specific multicast as |
| * defined in RFC 4604. Note that on older platforms this may fail |
| * with a %G_IO_ERROR_NOT_SUPPORTED error. |
| * |
| * Note that this function can be called multiple times for the same |
| * @group with different @source_specific in order to receive multicast |
| * packets from more than one source. |
| * |
| * Returns: %TRUE on success, %FALSE on error. |
| * |
| * Since: 2.56 |
| */ |
| gboolean |
| g_socket_join_multicast_group_ssm (GSocket *socket, |
| GInetAddress *group, |
| GInetAddress *source_specific, |
| const gchar *iface, |
| GError **error) |
| { |
| return g_socket_multicast_group_operation_ssm (socket, group, |
| source_specific, iface, TRUE, error); |
| } |
| |
| /** |
| * g_socket_leave_multicast_group_ssm: |
| * @socket: a #GSocket. |
| * @group: a #GInetAddress specifying the group address to leave. |
| * @source_specific: (nullable): a #GInetAddress specifying the |
| * source-specific multicast address or %NULL to ignore. |
| * @iface: (nullable): Name of the interface to use, or %NULL |
| * @error: #GError for error reporting, or %NULL to ignore. |
| * |
| * Removes @socket from the multicast group defined by @group, @iface, |
| * and @source_specific (which must all have the same values they had |
| * when you joined the group). |
| * |
| * @socket remains bound to its address and port, and can still receive |
| * unicast messages after calling this. |
| * |
| * Returns: %TRUE on success, %FALSE on error. |
| * |
| * Since: 2.56 |
| */ |
| gboolean |
| g_socket_leave_multicast_group_ssm (GSocket *socket, |
| GInetAddress *group, |
| GInetAddress *source_specific, |
| const gchar *iface, |
| GError **error) |
| { |
| return g_socket_multicast_group_operation_ssm (socket, group, |
| source_specific, iface, FALSE, error); |
| } |
| |
| /** |
| * 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) |
| { |
| gint v6_only; |
| |
| if (!g_socket_get_option (socket, |
| IPPROTO_IPV6, IPV6_V6ONLY, |
| &v6_only, NULL)) |
| return FALSE; |
| |
| return !v6_only; |
| } |
| #else |
| return FALSE; |
| #endif |
| |
| default: |
| return FALSE; |
| } |
| } |
| |
| /** |
| * g_socket_accept: |
| * @socket: a #GSocket. |
| * @cancellable: (nullable): a %GCancellable or %NULL |
| * @error: #GError for error reporting, or %NULL to ignore. |
| * |
| * Accept incoming connections on a connection-based socket. This removes |
| * the first outstanding connection request from the listening socket and |
| * creates a #GSocket object for it. |
| * |
| * The @socket must be bound to a local address with g_socket_bind() and |
| * must be listening for incoming connections (g_socket_listen()). |
| * |
| * If there are no outstanding connections then the operation will block |
| * 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: (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) |
| { |
| #ifdef HAVE_ACCEPT4 |
| gboolean try_accept4 = TRUE; |
| #endif |
| GSocket *new_socket; |
| gint ret; |
| |
| g_return_val_if_fail (G_IS_SOCKET (socket), NULL); |
| |
| if (!check_socket (socket, error)) |
| return NULL; |
| |
| if (!check_timeout (socket, error)) |
| return NULL; |
| |
| while (TRUE) |
| { |
| gboolean try_accept = TRUE; |
| |
| #ifdef HAVE_ACCEPT4 |
| if (try_accept4) |
| { |
| ret = accept4 (socket->priv->fd, NULL, 0, SOCK_CLOEXEC); |
| if (ret < 0 && errno == ENOSYS) |
| { |
| try_accept4 = FALSE; |
| } |
| else |
| { |
| try_accept = FALSE; |
| } |
| } |
| |
| g_assert (try_accept4 || try_accept); |
| #endif |
| if (try_accept) |
| ret = accept (socket->priv->fd, NULL, 0); |
| |
| if (ret < 0) |
| { |
| int errsv = get_socket_errno (); |
| |
| if (errsv == EINTR) |
| continue; |
| |
| #ifdef WSAEWOULDBLOCK |
| if (errsv == WSAEWOULDBLOCK) |
| #else |
| if (errsv == EWOULDBLOCK || |
| errsv == EAGAIN) |
| #endif |
| { |
| win32_unset_event_mask (socket, FD_ACCEPT); |
| |
| if (socket->priv->blocking) |
| { |
| if (!g_socket_condition_wait (socket, |
| G_IO_IN, cancellable, error)) |
| return NULL; |
| |
| continue; |
| } |
| } |
| |
| socket_set_error_lazy (error, errsv, _("Error accepting connection: %s")); |
| return NULL; |
| } |
| break; |
| } |
| |
| win32_unset_event_mask (socket, FD_ACCEPT); |
| |
| #ifdef G_OS_WIN32 |
| { |
| /* The socket inherits the accepting sockets event mask and even object, |
| we need to remove that */ |
| WSAEventSelect (ret, NULL, 0); |
| } |
| #else |
| { |
| int flags; |
| |
| /* We always want to set close-on-exec to protect users. If you |
| need to so some weird inheritance to exec you can re-enable this |
| using lower level hacks with g_socket_get_fd(). */ |
| flags = fcntl (ret, F_GETFD, 0); |
| if (flags != -1 && |
| (flags & FD_CLOEXEC) == 0) |
| { |
| flags |= FD_CLOEXEC; |
| fcntl (ret, F_SETFD, flags); |
| } |
| } |
| #endif |
| |
| new_socket = g_socket_new_from_fd (ret, error); |
| if (new_socket == NULL) |
| { |
| #ifdef G_OS_WIN32 |
| closesocket (ret); |
| #else |
| close (ret); |
| #endif |
| } |
| else |
| new_socket->priv->protocol = socket->priv->protocol; |
| |
| return new_socket; |
| } |
| |
| /** |
| * g_socket_connect: |
| * @socket: a #GSocket. |
| * @address: a #GSocketAddress specifying the remote address. |
| * @cancellable: (nullable): a %GCancellable or %NULL |
| * @error: #GError for error reporting, or %NULL to ignore. |
| * |
| * Connect the socket to the specified remote address. |
| * |
| * For connection oriented socket this generally means we attempt to make |
| * a connection to the @address. For a connection-less socket it sets |
| * 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. |
| * |
| * 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 |
| * and the user can be notified of the connection finishing by waiting |
| * for the G_IO_OUT condition. The result of the connection must then be |
| * checked with g_socket_check_connect_result(). |
| * |
| * Returns: %TRUE if connected, %FALSE on error. |
| * |
| * Since: 2.22 |
| */ |
| gboolean |
| g_socket_connect (GSocket *socket, |
| GSocketAddress *address, |
| GCancellable *cancellable, |
| GError **error) |
| { |
| union { |
| struct sockaddr_storage storage; |
| struct sockaddr sa; |
| } buffer; |
| |
| g_return_val_if_fail (G_IS_SOCKET (socket) && G_IS_SOCKET_ADDRESS (address), FALSE); |
| |
| if (!check_socket (socket, error)) |
| return FALSE; |
| |
| if (!g_socket_address_to_native (address, &buffer.storage, 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, &buffer.sa, |
| g_socket_address_get_native_size (address)) < 0) |
| { |
| int errsv = get_socket_errno (); |
| |
| if (errsv == EINTR) |
| continue; |
| |
| #ifndef G_OS_WIN32 |
| if (errsv == EINPROGRESS) |
| #else |
| if (errsv == WSAEWOULDBLOCK) |
| #endif |
| { |
| win32_unset_event_mask (socket, FD_CONNECT); |
| |
| if (socket->priv->blocking) |
| { |
| if (g_socket_condition_wait (socket, G_IO_OUT, cancellable, error)) |
| { |
| if (g_socket_check_connect_result (socket, error)) |
| break; |
| } |
| } |
| else |
| { |
| g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PENDING, |
| _("Connection in progress")); |
| socket->priv->connect_pending = TRUE; |
| } |
| } |
| else |
| g_set_error_literal (error, G_IO_ERROR, |
| socket_io_error_from_errno (errsv), |
| socket_strerror (errsv)); |
| |
| return FALSE; |
| } |
| break; |
| } |
| |
| win32_unset_event_mask (socket, FD_CONNECT); |
| |
| socket->priv->connected_read = TRUE; |
| socket->priv->connected_write = TRUE; |
| |
| return TRUE; |
| } |
| |
| /** |
| * g_socket_check_connect_result: |
| * @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. |
| * |
| * 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) |
| { |
| int value; |
| |
| g_return_val_if_fail (G_IS_SOCKET (socket), FALSE); |
| |
| 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: ")); |
| return FALSE; |
| } |
| |
| if (value != 0) |
| { |
| 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; |
| } |
| |
| socket->priv->connected_read = TRUE; |
| socket->priv->connected_write = TRUE; |
| |
| return TRUE; |
| } |
| |
| /** |
| * g_socket_get_available_bytes: |
| * @socket: a #GSocket |
| * |
| * Get the amount of data pending in the OS input buffer, without blocking. |
| * |
| * If @socket is a UDP or SCTP socket, this will return the size of |
| * just the next packet, even if additional packets are buffered after |
| * that one. |
| * |
| * Note that on Windows, this function is rather inefficient in the |
| * UDP case, and so if you know any plausible upper bound on the size |
| * of the incoming packet, it is better to just do a |
| * g_socket_receive() with a buffer of that size, rather than calling |
| * g_socket_get_available_bytes() first and then doing a receive of |
| * exactly the right size. |
| * |
| * Returns: the number of bytes that can be read from the socket |
| * without blocking or truncating, or -1 on error. |
| * |
| * Since: 2.32 |
| */ |
| gssize |
| g_socket_get_available_bytes (GSocket *socket) |
| { |
| #ifndef SO_NREAD |
| const gint bufsize = 64 * 1024; |
| static guchar *buf = NULL; |
| #endif |
| #ifdef G_OS_WIN32 |
| u_long avail; |
| #else |
| gint avail; |
| #endif |
| |
| g_return_val_if_fail (G_IS_SOCKET (socket), -1); |
| |
| if (!check_socket (socket, NULL)) |
| return -1; |
| |
| #ifdef SO_NREAD |
| if (!g_socket_get_option (socket, SOL_SOCKET, SO_NREAD, &avail, NULL)) |
| return -1; |
| #else |
| if (socket->priv->type == G_SOCKET_TYPE_DATAGRAM) |
| { |
| if (G_UNLIKELY (g_once_init_enter_pointer (&buf))) |
| g_once_init_leave_pointer (&buf, g_malloc (bufsize)); |
| |
| /* On datagram sockets, FIONREAD ioctl is not reliable because many |
| * systems add internal header size to the reported size, making it |
| * unusable for this function. */ |
| avail = recv (socket->priv->fd, buf, bufsize, MSG_PEEK); |
| if ((gint) avail == -1) |
| { |
| int errsv = get_socket_errno (); |
| #ifdef G_OS_WIN32 |
| if (errsv == WSAEWOULDBLOCK) |
| #else |
| if (errsv == EWOULDBLOCK || errsv == EAGAIN) |
| #endif |
| avail = 0; |
| } |
| } |
| else |
| { |
| #ifdef G_OS_WIN32 |
| if (ioctlsocket (socket->priv->fd, FIONREAD, &avail) < 0) |
| #else |
| if (ioctl (socket->priv->fd, FIONREAD, &avail) < 0) |
| #endif |
| avail = -1; |
| } |
| #endif |
| |
| return avail; |
| } |
| |
| /* Block on a timed wait for @condition until (@start_time + @timeout). |
| * Return %G_IO_ERROR_TIMED_OUT if the timeout is reached; otherwise %TRUE. |
| */ |
| static gboolean |
| block_on_timeout (GSocket *socket, |
| GIOCondition condition, |
| gint64 timeout_us, |
| gint64 start_time, |
| GCancellable *cancellable, |
| GError **error) |
| { |
| gint64 wait_timeout = -1; |
| |
| g_return_val_if_fail (timeout_us != 0, TRUE); |
| |
| /* check if we've timed out or how much time to wait at most */ |
| if (timeout_us >= 0) |
| { |
| gint64 elapsed = g_get_monotonic_time () - start_time; |
| |
| if (elapsed >= timeout_us) |
| { |
| g_set_error_literal (error, |
| G_IO_ERROR, G_IO_ERROR_TIMED_OUT, |
| _("Socket I/O timed out")); |
| return FALSE; |
| } |
| |
| wait_timeout = timeout_us - elapsed; |
| } |
| |
| return g_socket_condition_timed_wait (socket, condition, wait_timeout, |
| cancellable, error); |
| } |
| |
| static gssize |
| g_socket_receive_with_timeout (GSocket *socket, |
| guint8 *buffer, |
| gsize size, |
| gint64 timeout_us, |
| GCancellable *cancellable, |
| GError **error) |
| { |
| gssize ret; |
| gint64 start_time; |
| |
| g_return_val_if_fail (G_IS_SOCKET (socket) && buffer != NULL, -1); |
| |
| start_time = g_get_monotonic_time (); |
| |
| 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; |
| |
| while (1) |
| { |
| if ((ret = recv (socket->priv->fd, buffer, size, 0)) < 0) |
| { |
| int errsv = get_socket_errno (); |
| |
| if (errsv == EINTR) |
| continue; |
| |
| #ifdef WSAEWOULDBLOCK |
| if (errsv == WSAEWOULDBLOCK) |
| #else |
| if (errsv == EWOULDBLOCK || |
| errsv == EAGAIN) |
| #endif |
| { |
| win32_unset_event_mask (socket, FD_READ); |
| |
| if (timeout_us != 0) |
| { |
| if (!block_on_timeout (socket, G_IO_IN, timeout_us, start_time, |
| cancellable, error)) |
| return -1; |
| |
| continue; |
| } |
| } |
| |
| win32_unset_event_mask (socket, FD_READ); |
| |
| socket_set_error_lazy (error, errsv, _("Error receiving data: %s")); |
| return -1; |
| } |
| |
| win32_unset_event_mask (socket, FD_READ); |
| |
| break; |
| } |
| |
| return ret; |
| } |
| |
| /** |
| * g_socket_receive_bytes: |
| * @socket: a #GSocket |
| * @size: the number of bytes you want to read from the socket |
| * @timeout_us: the timeout to wait for, in microseconds, or `-1` to block |
| * indefinitely |
| * @cancellable: (nullable): a %GCancellable, or `NULL` |
| * @error: return location for a #GError, or `NULL` |
| * |
| * Receives data (up to @size bytes) from a socket. |
| * |
| * This function is a variant of [method@Gio.Socket.receive] which returns a |
| * [struct@GLib.Bytes] rather than a plain buffer. |
| * |
| * Pass `-1` to @timeout_us to block indefinitely until data is received (or |
| * the connection is closed, or there is an error). Pass `0` to use the default |
| * timeout from [property@Gio.Socket:timeout], or pass a positive number to wait |
| * for that many microseconds for data before returning `G_IO_ERROR_TIMED_OUT`. |
| * |
| * Returns: (transfer full): a bytes buffer containing the |
| * received bytes, or `NULL` on error |
| * Since: 2.80 |
| */ |
| GBytes * |
| g_socket_receive_bytes (GSocket *socket, |
| gsize size, |
| gint64 timeout_us, |
| GCancellable *cancellable, |
| GError **error) |
| { |
| guint8 *data; |
| gssize res; |
| GBytes *buf; |
| |
| g_return_val_if_fail (G_IS_SOCKET (socket), NULL); |
| g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); |
| g_return_val_if_fail (error == NULL || *error == NULL, NULL); |
| |
| data = g_new0 (guint8, size); |
| res = g_socket_receive_with_timeout (socket, data, size, timeout_us, cancellable, error); |
| if (res < 0) |
| { |
| g_free (data); |
| return NULL; |
| } |
| |
| if ((gsize) res == size) |
| { |
| buf = g_bytes_new_take (g_steal_pointer (&data), (gsize) res); |
| } |
| else |
| { |
| GBytes *sub_buf; |
| |
| buf = g_bytes_new_take (g_steal_pointer (&data), size); |
| sub_buf = g_bytes_new_from_bytes (buf, 0, (gsize) res); |
| g_bytes_unref (buf); |
| buf = g_steal_pointer (&sub_buf); |
| } |
| |
| return g_steal_pointer (&buf); |
| } |
| |
| /** |
| * g_socket_receive: |
| * @socket: a #GSocket |
| * @buffer: (array length=size) (element-type guint8) (out caller-allocates): |
| * a buffer to read data into (which should be at least @size bytes long). |
| * @size: (in): the number of bytes you want to read from the socket |
| * @cancellable: (nullable): 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() |
| * with @address set to %NULL. |
| * |
| * 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, the connection is closed, or there is an |
| * error. If there is no data available and the socket is in |
| * non-blocking mode, a %G_IO_ERROR_WOULD_BLOCK error will be |
| * returned. To be notified when data is available, wait for the |
| * %G_IO_IN condition. |
| * |
| * On error -1 is returned and @error is set accordingly. |
| * |
| * Returns: Number of bytes read, or 0 if the connection was closed b
|