mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-01-14 08:16:24 +01:00
gsocket: Factor out blocking parameter from g_socket_receive_message()
This will make future API additions easier. The factored version is internal for the time being. https://bugzilla.gnome.org/show_bug.cgi?id=751924
This commit is contained in:
parent
5d68947466
commit
7f985b35ce
396
gio/gsocket.c
396
gio/gsocket.c
@ -138,6 +138,17 @@ static gboolean g_socket_initable_init (GInitable *initable,
|
|||||||
static GSocketAddress *
|
static GSocketAddress *
|
||||||
cache_recv_address (GSocket *socket, struct sockaddr *native, int native_len);
|
cache_recv_address (GSocket *socket, struct sockaddr *native, int native_len);
|
||||||
|
|
||||||
|
static gssize
|
||||||
|
g_socket_receive_message_with_blocking (GSocket *socket,
|
||||||
|
GSocketAddress **address,
|
||||||
|
GInputVector *vectors,
|
||||||
|
gint num_vectors,
|
||||||
|
GSocketControlMessage ***messages,
|
||||||
|
gint *num_messages,
|
||||||
|
gint *flags,
|
||||||
|
gboolean blocking,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error);
|
||||||
static gint
|
static gint
|
||||||
g_socket_send_messages_with_blocking (GSocket *socket,
|
g_socket_send_messages_with_blocking (GSocket *socket,
|
||||||
GOutputMessage *messages,
|
GOutputMessage *messages,
|
||||||
@ -4440,6 +4451,203 @@ cache_recv_address (GSocket *socket, struct sockaddr *native, int native_len)
|
|||||||
return saddr;
|
return saddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gssize
|
||||||
|
g_socket_receive_message_with_blocking (GSocket *socket,
|
||||||
|
GSocketAddress **address,
|
||||||
|
GInputVector *vectors,
|
||||||
|
gint num_vectors,
|
||||||
|
GSocketControlMessage ***messages,
|
||||||
|
gint *num_messages,
|
||||||
|
gint *flags,
|
||||||
|
gboolean blocking,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
GInputVector one_vector;
|
||||||
|
char one_byte;
|
||||||
|
|
||||||
|
g_return_val_if_fail (G_IS_SOCKET (socket), -1);
|
||||||
|
|
||||||
|
if (!check_socket (socket, error))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (!check_timeout (socket, error))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (g_cancellable_set_error_if_cancelled (cancellable, error))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (num_vectors == -1)
|
||||||
|
{
|
||||||
|
for (num_vectors = 0;
|
||||||
|
vectors[num_vectors].buffer != NULL;
|
||||||
|
num_vectors++)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num_vectors == 0)
|
||||||
|
{
|
||||||
|
one_vector.buffer = &one_byte;
|
||||||
|
one_vector.size = 1;
|
||||||
|
num_vectors = 1;
|
||||||
|
vectors = &one_vector;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef G_OS_WIN32
|
||||||
|
{
|
||||||
|
GInputMessage input_message;
|
||||||
|
struct msghdr msg;
|
||||||
|
gssize result;
|
||||||
|
|
||||||
|
input_message.address = address;
|
||||||
|
input_message.vectors = vectors;
|
||||||
|
input_message.num_vectors = num_vectors;
|
||||||
|
input_message.bytes_received = 0;
|
||||||
|
input_message.flags = (flags != NULL) ? *flags : 0;
|
||||||
|
input_message.control_messages = messages;
|
||||||
|
input_message.num_control_messages = (guint *) num_messages;
|
||||||
|
|
||||||
|
/* We always set the close-on-exec flag so we don't leak file
|
||||||
|
* descriptors into child processes. Note that gunixfdmessage.c
|
||||||
|
* will later call fcntl (fd, FD_CLOEXEC), but that isn't atomic.
|
||||||
|
*/
|
||||||
|
#ifdef MSG_CMSG_CLOEXEC
|
||||||
|
input_message.flags |= MSG_CMSG_CLOEXEC;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
input_message_to_msghdr (&input_message, &msg);
|
||||||
|
|
||||||
|
/* do it */
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
result = recvmsg (socket->priv->fd, &msg, msg.msg_flags);
|
||||||
|
#ifdef MSG_CMSG_CLOEXEC
|
||||||
|
if (result < 0 && get_socket_errno () == EINVAL)
|
||||||
|
{
|
||||||
|
/* We must be running on an old kernel. Call without the flag. */
|
||||||
|
msg.msg_flags &= ~(MSG_CMSG_CLOEXEC);
|
||||||
|
result = recvmsg (socket->priv->fd, &msg, msg.msg_flags);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (result < 0)
|
||||||
|
{
|
||||||
|
int errsv = get_socket_errno ();
|
||||||
|
|
||||||
|
if (errsv == EINTR)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (blocking &&
|
||||||
|
(errsv == EWOULDBLOCK ||
|
||||||
|
errsv == EAGAIN))
|
||||||
|
{
|
||||||
|
if (!g_socket_condition_wait (socket,
|
||||||
|
G_IO_IN, cancellable, error))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
socket_set_error_lazy (error, errsv, _("Error receiving message: %s"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
input_message_from_msghdr (&msg, &input_message, socket);
|
||||||
|
|
||||||
|
if (flags != NULL)
|
||||||
|
*flags = input_message.flags;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
{
|
||||||
|
struct sockaddr_storage addr;
|
||||||
|
int addrlen;
|
||||||
|
DWORD bytes_received;
|
||||||
|
DWORD win_flags;
|
||||||
|
int result;
|
||||||
|
WSABUF *bufs;
|
||||||
|
gint i;
|
||||||
|
|
||||||
|
/* iov */
|
||||||
|
bufs = g_newa (WSABUF, num_vectors);
|
||||||
|
for (i = 0; i < num_vectors; i++)
|
||||||
|
{
|
||||||
|
bufs[i].buf = (char *)vectors[i].buffer;
|
||||||
|
bufs[i].len = (gulong)vectors[i].size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* flags */
|
||||||
|
if (flags != NULL)
|
||||||
|
win_flags = *flags;
|
||||||
|
else
|
||||||
|
win_flags = 0;
|
||||||
|
|
||||||
|
/* do it */
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
addrlen = sizeof addr;
|
||||||
|
if (address)
|
||||||
|
result = WSARecvFrom (socket->priv->fd,
|
||||||
|
bufs, num_vectors,
|
||||||
|
&bytes_received, &win_flags,
|
||||||
|
(struct sockaddr *)&addr, &addrlen,
|
||||||
|
NULL, NULL);
|
||||||
|
else
|
||||||
|
result = WSARecv (socket->priv->fd,
|
||||||
|
bufs, num_vectors,
|
||||||
|
&bytes_received, &win_flags,
|
||||||
|
NULL, NULL);
|
||||||
|
if (result != 0)
|
||||||
|
{
|
||||||
|
int errsv = get_socket_errno ();
|
||||||
|
|
||||||
|
if (errsv == WSAEINTR)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (errsv == WSAEWOULDBLOCK)
|
||||||
|
{
|
||||||
|
win32_unset_event_mask (socket, FD_READ);
|
||||||
|
|
||||||
|
if (blocking)
|
||||||
|
{
|
||||||
|
if (!g_socket_condition_wait (socket,
|
||||||
|
G_IO_IN, cancellable, error))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
socket_set_error_lazy (error, errsv, _("Error receiving message: %s"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
win32_unset_event_mask (socket, FD_READ);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* decode address */
|
||||||
|
if (address != NULL)
|
||||||
|
{
|
||||||
|
*address = cache_recv_address (socket, (struct sockaddr *)&addr, addrlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* capture the flags */
|
||||||
|
if (flags != NULL)
|
||||||
|
*flags = win_flags;
|
||||||
|
|
||||||
|
if (messages != NULL)
|
||||||
|
*messages = NULL;
|
||||||
|
if (num_messages != NULL)
|
||||||
|
*num_messages = 0;
|
||||||
|
|
||||||
|
return bytes_received;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* g_socket_receive_message:
|
* g_socket_receive_message:
|
||||||
* @socket: a #GSocket
|
* @socket: a #GSocket
|
||||||
@ -4531,189 +4739,11 @@ g_socket_receive_message (GSocket *socket,
|
|||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
GInputVector one_vector;
|
return g_socket_receive_message_with_blocking (socket, address, vectors,
|
||||||
char one_byte;
|
num_vectors, messages,
|
||||||
|
num_messages, flags,
|
||||||
g_return_val_if_fail (G_IS_SOCKET (socket), -1);
|
socket->priv->blocking,
|
||||||
|
cancellable, error);
|
||||||
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;
|
|
||||||
|
|
||||||
if (num_vectors == -1)
|
|
||||||
{
|
|
||||||
for (num_vectors = 0;
|
|
||||||
vectors[num_vectors].buffer != NULL;
|
|
||||||
num_vectors++)
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (num_vectors == 0)
|
|
||||||
{
|
|
||||||
one_vector.buffer = &one_byte;
|
|
||||||
one_vector.size = 1;
|
|
||||||
num_vectors = 1;
|
|
||||||
vectors = &one_vector;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef G_OS_WIN32
|
|
||||||
{
|
|
||||||
GInputMessage input_message;
|
|
||||||
struct msghdr msg;
|
|
||||||
gssize result;
|
|
||||||
|
|
||||||
input_message.address = address;
|
|
||||||
input_message.vectors = vectors;
|
|
||||||
input_message.num_vectors = num_vectors;
|
|
||||||
input_message.bytes_received = 0;
|
|
||||||
input_message.flags = (flags != NULL) ? *flags : 0;
|
|
||||||
input_message.control_messages = messages;
|
|
||||||
input_message.num_control_messages = (guint *) num_messages;
|
|
||||||
|
|
||||||
/* We always set the close-on-exec flag so we don't leak file
|
|
||||||
* descriptors into child processes. Note that gunixfdmessage.c
|
|
||||||
* will later call fcntl (fd, FD_CLOEXEC), but that isn't atomic.
|
|
||||||
*/
|
|
||||||
#ifdef MSG_CMSG_CLOEXEC
|
|
||||||
input_message.flags |= MSG_CMSG_CLOEXEC;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
input_message_to_msghdr (&input_message, &msg);
|
|
||||||
|
|
||||||
/* do it */
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
result = recvmsg (socket->priv->fd, &msg, msg.msg_flags);
|
|
||||||
#ifdef MSG_CMSG_CLOEXEC
|
|
||||||
if (result < 0 && get_socket_errno () == EINVAL)
|
|
||||||
{
|
|
||||||
/* We must be running on an old kernel. Call without the flag. */
|
|
||||||
msg.msg_flags &= ~(MSG_CMSG_CLOEXEC);
|
|
||||||
result = recvmsg (socket->priv->fd, &msg, msg.msg_flags);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (result < 0)
|
|
||||||
{
|
|
||||||
int errsv = get_socket_errno ();
|
|
||||||
|
|
||||||
if (errsv == EINTR)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (socket->priv->blocking &&
|
|
||||||
(errsv == EWOULDBLOCK ||
|
|
||||||
errsv == EAGAIN))
|
|
||||||
{
|
|
||||||
if (!g_socket_condition_wait (socket,
|
|
||||||
G_IO_IN, cancellable, error))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
socket_set_error_lazy (error, errsv, _("Error receiving message: %s"));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
input_message_from_msghdr (&msg, &input_message, socket);
|
|
||||||
|
|
||||||
if (flags != NULL)
|
|
||||||
*flags = input_message.flags;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
{
|
|
||||||
struct sockaddr_storage addr;
|
|
||||||
int addrlen;
|
|
||||||
DWORD bytes_received;
|
|
||||||
DWORD win_flags;
|
|
||||||
int result;
|
|
||||||
WSABUF *bufs;
|
|
||||||
gint i;
|
|
||||||
|
|
||||||
/* iov */
|
|
||||||
bufs = g_newa (WSABUF, num_vectors);
|
|
||||||
for (i = 0; i < num_vectors; i++)
|
|
||||||
{
|
|
||||||
bufs[i].buf = (char *)vectors[i].buffer;
|
|
||||||
bufs[i].len = (gulong)vectors[i].size;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* flags */
|
|
||||||
if (flags != NULL)
|
|
||||||
win_flags = *flags;
|
|
||||||
else
|
|
||||||
win_flags = 0;
|
|
||||||
|
|
||||||
/* do it */
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
addrlen = sizeof addr;
|
|
||||||
if (address)
|
|
||||||
result = WSARecvFrom (socket->priv->fd,
|
|
||||||
bufs, num_vectors,
|
|
||||||
&bytes_received, &win_flags,
|
|
||||||
(struct sockaddr *)&addr, &addrlen,
|
|
||||||
NULL, NULL);
|
|
||||||
else
|
|
||||||
result = WSARecv (socket->priv->fd,
|
|
||||||
bufs, num_vectors,
|
|
||||||
&bytes_received, &win_flags,
|
|
||||||
NULL, NULL);
|
|
||||||
if (result != 0)
|
|
||||||
{
|
|
||||||
int errsv = get_socket_errno ();
|
|
||||||
|
|
||||||
if (errsv == WSAEINTR)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (errsv == WSAEWOULDBLOCK)
|
|
||||||
{
|
|
||||||
win32_unset_event_mask (socket, FD_READ);
|
|
||||||
|
|
||||||
if (socket->priv->blocking)
|
|
||||||
{
|
|
||||||
if (!g_socket_condition_wait (socket,
|
|
||||||
G_IO_IN, cancellable, error))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
socket_set_error_lazy (error, errsv, _("Error receiving message: %s"));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
win32_unset_event_mask (socket, FD_READ);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* decode address */
|
|
||||||
if (address != NULL)
|
|
||||||
{
|
|
||||||
*address = cache_recv_address (socket, (struct sockaddr *)&addr, addrlen);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* capture the flags */
|
|
||||||
if (flags != NULL)
|
|
||||||
*flags = win_flags;
|
|
||||||
|
|
||||||
if (messages != NULL)
|
|
||||||
*messages = NULL;
|
|
||||||
if (num_messages != NULL)
|
|
||||||
*num_messages = 0;
|
|
||||||
|
|
||||||
return bytes_received;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user