/gio/gsocket.c
C | 5610 lines | 3486 code | 675 blank | 1449 comment | 638 complexity | 1869d0305b5d4bbd678622dbba1691ac MD5 | raw file
Possible License(s): LGPL-2.1, AGPL-3.0
Large files files are truncated, but you can click here to view the full file
- /* 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.
- *
- * 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_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 "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"
- #ifdef G_OS_WIN32
- /* For Windows XP runtime compatibility, but use the system's if_nametoindex() if available */
- #include "gwin32networking.h"
- #endif
- /**
- * SECTION:gsocket
- * @short_description: Low-level socket object
- * @include: gio/gio.h
- * @see_also: #GInitable, [<gnetworking.h>][gio-gnetworking.h]
- *
- * A #GSocket is a low-level networking primitive. It is a more or less
- * direct mapping of the BSD socket API in a portable GObject based API.
- * 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 #GSocketClient,
- * #GSocketService and #GSocketConnection. However there may be cases where
- * direct use of #GSocket is useful.
- *
- * #GSocket implements the #GInitable interface, so if it is manually constructed
- * by e.g. g_object_new() you must call g_initable_init() and check the
- * results before using the object. This is done automatically in
- * g_socket_new() and g_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 g_socket_condition_check(),
- * or g_socket_condition_wait(). You can also use g_socket_create_source() and
- * attach it to a #GMainContext 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.
- *
- * #GSockets can be either connection oriented or datagram based.
- * For connection oriented types you must first establish a connection by
- * either connecting to an address or accepting a connection from another
- * address. For connectionless socket types the target/source address is
- * 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.
- *
- * 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,
- GCancellable *cancellable,
- GError **error);
- static gint g_socket_datagram_based_send_messages (GDatagramBased *self,
- GOutputMessage *messages,
- guint num_messages,
- gint flags,
- gint64 timeout,
- 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,
- GCancellable *cancellable,
- GError **error);
- static GSocketAddress *
- cache_recv_address (GSocket *socket, struct sockaddr *native, int 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,
- GCancellable *cancellable,
- GError **error);
- static gint
- g_socket_receive_messages_with_timeout (GSocket *socket,
- GInputMessage *messages,
- guint num_messages,
- gint flags,
- gint64 timeout,
- GCancellable *cancellable,
- GError **error);
- static gssize
- g_socket_send_message_with_timeout (GSocket *socket,
- GSocketAddress *address,
- GOutputVector *vectors,
- gint num_vectors,
- GSocketControlMessage **messages,
- gint num_messages,
- gint flags,
- gint64 timeout,
- GCancellable *cancellable,
- GError **error);
- static gint
- g_socket_send_messages_with_timeout (GSocket *socket,
- GOutputMessage *messages,
- guint num_messages,
- gint flags,
- gint64 timeout,
- 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;
- gint 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 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)
- {
- struct sockaddr_storage address;
- gint fd;
- guint addrlen;
- int value, family;
- int errsv;
- 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, (struct sockaddr *) &address, &addrlen) != 0)
- {
- errsv = get_socket_errno ();
- goto err;
- }
- if (addrlen > 0)
- {
- g_assert (G_STRUCT_OFFSET (struct sockaddr, sa_family) +
- sizeof address.ss_family <= addrlen);
- family = address.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.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, (struct sockaddr *) &address, &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));
- }
- /* Wrapper around socket() that is shared with gnetworkmonitornetlink.c */
- gint
- g_socket (gint domain,
- gint type,
- gint protocol,
- GError **error)
- {
- int fd, errsv;
- #ifdef SOCK_CLOEXEC
- fd = socket (domain, type | SOCK_CLOEXEC, protocol);
- errsv = errno;
- if (fd != -1)
- return fd;
- /* It's possible that libc has SOCK_CLOEXEC but the kernel does not */
- if (fd < 0 && (errsv == EINVAL || errsv == EPROTOTYPE))
- #endif
- fd = socket (domain, type, protocol);
- if (fd < 0)
- {
- int 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;
- fcntl (fd, F_SETFD, flags);
- }
- }
- #endif
- return fd;
- }
- 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 */
- g_socket_details_from_fd (socket);
- else
- /* create the fd from socket->priv info */
- 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)
- {
- #ifndef G_OS_WIN32
- GError *error = NULL;
- #else
- gulong arg;
- #endif
- /* Always use native nonblocking sockets, as Windows sets sockets to
- * nonblocking automatically in certain operations. This way we make
- * things work the same on all platforms.
- */
- #ifndef G_OS_WIN32
- if (!g_unix_set_fd_nonblocking (socket->priv->fd, TRUE, &error))
- {
- g_warning ("Error setting socket nonblocking: %s", error->message);
- g_clear_error (&error);
- }
- #else
- arg = TRUE;
- if (ioctlsocket (socket->priv->fd, FIONBIO, &arg) == SOCKET_ERROR)
- {
- int errsv = get_socket_errno ();
- g_warning ("Error setting socket status flags: %s", socket_strerror (errsv));
- }
- #endif
- #ifdef SO_NOSIGPIPE
- /* See note about SIGPIPE below. */
- g_socket_set_option (socket, SOL_SOCKET, SO_NOSIGPIPE, TRUE, NULL);
- #endif
- }
- }
- static void
- 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;
- g_object_class_install_property (gobject_class, PROP_FAMILY,
- g_param_spec_enum ("family",
- P_("Socket family"),
- P_("The sockets address family"),
- G_TYPE_SOCKET_FAMILY,
- G_SOCKET_FAMILY_INVALID,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (gobject_class, PROP_TYPE,
- g_param_spec_enum ("type",
- P_("Socket type"),
- P_("The sockets type"),
- G_TYPE_SOCKET_TYPE,
- G_SOCKET_TYPE_STREAM,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (gobject_class, PROP_PROTOCOL,
- g_param_spec_enum ("protocol",
- P_("Socket protocol"),
- P_("The id of the protocol to use, or -1 for unknown"),
- G_TYPE_SOCKET_PROTOCOL,
- G_SOCKET_PROTOCOL_UNKNOWN,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (gobject_class, PROP_FD,
- g_param_spec_int ("fd",
- P_("File descriptor"),
- P_("The sockets file descriptor"),
- G_MININT,
- G_MAXINT,
- -1,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (gobject_class, PROP_BLOCKING,
- g_param_spec_boolean ("blocking",
- P_("blocking"),
- P_("Whether or not I/O on this socket is blocking"),
- TRUE,
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (gobject_class, PROP_LISTEN_BACKLOG,
- g_param_spec_int ("listen-backlog",
- P_("Listen backlog"),
- P_("Outstanding connections in the listen queue"),
- 0,
- SOMAXCONN,
- 10,
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (gobject_class, PROP_KEEPALIVE,
- g_param_spec_boolean ("keepalive",
- P_("Keep connection alive"),
- P_("Keep connection alive by sending periodic pings"),
- FALSE,
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (gobject_class, PROP_LOCAL_ADDRESS,
- g_param_spec_object ("local-address",
- P_("Local address"),
- P_("The local address the socket is bound to"),
- G_TYPE_SOCKET_ADDRESS,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (gobject_class, PROP_REMOTE_ADDRESS,
- g_param_spec_object ("remote-address",
- P_("Remote address"),
- P_("The remote address the socket is connected to"),
- G_TYPE_SOCKET_ADDRESS,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS));
- /**
- * GSocket:timeout:
- *
- * The timeout in seconds on socket I/O
- *
- * Since: 2.26
- */
- g_object_class_install_property (gobject_class, PROP_TIMEOUT,
- g_param_spec_uint ("timeout",
- P_("Timeout"),
- P_("The timeout in seconds on socket I/O"),
- 0,
- G_MAXUINT,
- 0,
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS));
- /**
- * 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",
- P_("Broadcast"),
- P_("Whether to allow sending to broadcast addresses"),
- 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",
- P_("TTL"),
- P_("Time-to-live of outgoing unicast packets"),
- 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",
- P_("Multicast loopback"),
- P_("Whether outgoing multicast packets loop back to the local host"),
- 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",
- P_("Multicast TTL"),
- P_("Time-to-live of outgoing multicast packets"),
- 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,
- 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,
- cancellable, error);
- }
- static gint
- g_socket_datagram_based_send_messages (GDatagramBased *self,
- GOutputMessage *messages,
- guint num_messages,
- gint flags,
- gint64 timeout,
- 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,
- 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,
- 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, 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…
Large files files are truncated, but you can click here to view the full file