Commit dfab04cd authored by Philip Withnall's avatar Philip Withnall Committed by Olivier Crête

socket: Add vectored I/O support for receiving on sockets

Replace the recv() API with a recv_messages() API, which supports
receiving multiple messages, each with multiple buffers rather than a
single monolithic buffer.

This doesn’t break API, as the socket API is not exposed outside
libnice. It does introduce a new struct: NiceInputMessage, which is
analogous to struct mmsghdr.

This includes updates to the test-bsd test to cover the changed API.
parent bc527dcf
......@@ -181,4 +181,10 @@ component_io_cb (
gssize agent_recv_locked (NiceAgent *agent, Stream *stream,
Component *component, NiceSocket *socket, guint8 *buf, gsize buf_len);
gsize
memcpy_buffer_to_input_message (NiceInputMessage *message,
const guint8 *buffer, gsize buffer_length);
guint8 *
compact_input_message (NiceInputMessage *message, gsize *buffer_length);
#endif /*_NICE_AGENT_PRIV_H */
......@@ -2438,13 +2438,19 @@ agent_recv_locked (
GList *item;
guint8 local_buf[MAX_BUFFER_SIZE];
gsize local_buf_len = MAX_BUFFER_SIZE;
GInputVector local_bufs = { local_buf, local_buf_len };
NiceInputMessage local_messages = { &local_bufs, 1, &from, 0 };
gint n_valid_messages;
/* Returns -1 on error, 0 on EWOULDBLOCK, and > 0 on success.
*
* FIXME: We have to receive into a local buffer then copy out because
* otherwise, if @buf is too small, we could lose data, even when in
* reliable mode (because reliable streams are packetised). */
len = nice_socket_recv (socket, &from, local_buf_len, (gchar *) local_buf);
n_valid_messages = nice_socket_recv_messages (socket, &local_messages, 1);
len = (n_valid_messages == 1) ?
(gssize) local_messages.length : n_valid_messages;
if (len == 0) {
return 0;
......@@ -2555,6 +2561,99 @@ agent_recv_locked (
return len;
}
/* Print the composition of an array of messages. No-op if debugging is
* disabled. */
static void
nice_debug_message_composition (NiceInputMessage *messages, guint n_messages)
{
#ifndef NDEBUG
guint i;
for (i = 0; i < n_messages; i++) {
NiceInputMessage *message = &messages[i];
guint j;
nice_debug ("Message %p (from: %p, length: %" G_GSIZE_FORMAT ")", message,
message->from, message->length);
for (j = 0;
(message->n_buffers >= 0 && j < (guint) message->n_buffers) ||
(message->n_buffers < 0 && message->buffers[j].buffer != NULL);
j++) {
GInputVector *buffer = &message->buffers[j];
nice_debug ("\tBuffer %p (length: %" G_GSIZE_FORMAT ")", buffer->buffer,
buffer->size);
}
}
#endif
}
/* Concatenate all the buffers in the given @recv_message into a single, newly
* allocated, monolithic buffer which is returned. The length of the new buffer
* is returned in @buffer_length, and should be equal to the length field of
* @recv_message.
*
* The return value must be freed with g_free(). */
guint8 *
compact_input_message (NiceInputMessage *message, gsize *buffer_length)
{
guint8 *buffer;
gsize offset = 0;
guint i;
nice_debug ("%s: **WARNING: SLOW PATH**", G_STRFUNC);
nice_debug_message_composition (message, 1);
*buffer_length = message->length;
buffer = g_malloc (*buffer_length);
for (i = 0;
(message->n_buffers >= 0 && i < (guint) message->n_buffers) ||
(message->n_buffers < 0 && message->buffers[i].buffer != NULL);
i++) {
gsize len = MIN (*buffer_length - offset, message->buffers[i].size);
memcpy (buffer + offset, message->buffers[i].buffer, len);
offset += len;
}
return buffer;
}
/* Returns the number of bytes copied. Silently drops any data from @buffer
* which doesn’t fit in @message. */
gsize
memcpy_buffer_to_input_message (NiceInputMessage *message,
const guint8 *buffer, gsize buffer_length)
{
guint i;
nice_debug ("%s: **WARNING: SLOW PATH**", G_STRFUNC);
message->length = 0;
for (i = 0;
buffer_length > 0 &&
((message->n_buffers >= 0 && i < (guint) message->n_buffers) ||
(message->n_buffers < 0 && message->buffers[i].buffer != NULL));
i++) {
gsize len;
len = MIN (message->buffers[i].size, buffer_length);
memcpy (message->buffers[i].buffer, buffer, len);
buffer += len;
buffer_length -= len;
message->buffers[i].size = len;
message->length += len;
}
nice_debug_message_composition (message, 1);
return message->length;
}
static gboolean
nice_agent_recv_cancelled_cb (GCancellable *cancellable, gpointer user_data)
{
......
......@@ -137,6 +137,40 @@ typedef struct _NiceAgent NiceAgent;
G_BEGIN_DECLS
/**
* NiceInputMessage:
* @buffers: (array length=n_buffers): unowned array of #GInputVector buffers to
* store data in for this message
* @n_buffers: number of #GInputVectors in @buffers, or -1 to indicate @buffers
* is %NULL-terminated
* @from: (allow-none): return location to store the address of the peer who
* transmitted the message, or %NULL
* @length: total number of valid bytes contiguously stored in @buffers
*
* Represents a single message received off the network. For reliable
* connections, this is essentially just an array of buffers (specifically,
* @from can be ignored). for non-reliable connections, it represents a single
* packet as received from the OS.
*
* @n_buffers may be -1 to indicate that @buffers is terminated by a
* #GInputVector with a %NULL buffer pointer.
*
* By providing arrays of #NiceInputMessages to functions like
* nice_agent_recv_messages(), multiple messages may be received with a single
* call, which is more efficient than making multiple calls in a loop. In this
* manner, nice_agent_recv_messages() is analogous to recvmmsg(); and
* #NiceInputMessage to struct mmsghdr.
*
* Since: 0.1.5
*/
typedef struct {
GInputVector *buffers;
gint n_buffers; /* may be -1 to indicate @buffers is NULL-terminated */
NiceAddress *from; /* return location for address of message sender */
gsize length; /* sum of the lengths of @buffers */
} NiceInputMessage;
#define NICE_TYPE_AGENT nice_agent_get_type()
#define NICE_AGENT(obj) \
......
......@@ -7,6 +7,7 @@ NiceComponentType
NiceProxyType
NiceCompatibility
NiceAgentRecvFunc
NiceInputMessage
NICE_AGENT_MAX_REMOTE_CANDIDATES
nice_agent_new
nice_agent_new_reliable
......
This diff is collapsed.
......@@ -89,8 +89,8 @@ static const gchar SSL_CLIENT_HANDSHAKE[] = {
static void socket_close (NiceSocket *sock);
static gint socket_recv (NiceSocket *sock, NiceAddress *from,
guint len, gchar *buf);
static gint socket_recv_messages (NiceSocket *sock,
NiceInputMessage *recv_messages, guint n_recv_messages);
static gboolean socket_send (NiceSocket *sock, const NiceAddress *to,
guint len, const gchar *buf);
static gboolean socket_is_reliable (NiceSocket *sock);
......@@ -113,7 +113,7 @@ nice_pseudossl_socket_new (NiceSocket *base_socket)
sock->fileno = priv->base_socket->fileno;
sock->addr = priv->base_socket->addr;
sock->send = socket_send;
sock->recv = socket_recv;
sock->recv_messages = socket_recv_messages;
sock->is_reliable = socket_is_reliable;
sock->close = socket_close;
......@@ -142,23 +142,33 @@ socket_close (NiceSocket *sock)
static gint
socket_recv (NiceSocket *sock, NiceAddress *from, guint len, gchar *buf)
socket_recv_messages (NiceSocket *sock,
NiceInputMessage *recv_messages, guint n_recv_messages)
{
PseudoSSLPriv *priv = sock->priv;
if (priv->handshaken) {
if (priv->base_socket)
return nice_socket_recv (priv->base_socket, from, len, buf);
if (priv->base_socket) {
/* Fast path: once we’ve done the handshake, pass straight through to the
* base socket. */
return nice_socket_recv_messages (priv->base_socket,
recv_messages, n_recv_messages);
}
} else {
gchar data[sizeof(SSL_SERVER_HANDSHAKE)];
gint ret = -1;
if (priv->base_socket)
ret = nice_socket_recv (priv->base_socket, from, sizeof(data), data);
guint8 data[sizeof(SSL_SERVER_HANDSHAKE)];
gint ret = -1;
GInputVector local_recv_buf = { data, sizeof (data) };
NiceInputMessage local_recv_message = { &local_recv_buf, 1, NULL, 0 };
if (priv->base_socket) {
ret = nice_socket_recv_messages (priv->base_socket,
&local_recv_message, 1);
}
if (ret <= 0) {
return ret;
} else if ((guint) ret == sizeof(SSL_SERVER_HANDSHAKE) &&
} else if (ret == 1 &&
local_recv_buf.size == sizeof (SSL_SERVER_HANDSHAKE) &&
memcmp(SSL_SERVER_HANDSHAKE, data, sizeof(SSL_SERVER_HANDSHAKE)) == 0) {
struct to_be_sent *tbs = NULL;
priv->handshaken = TRUE;
......
......@@ -43,10 +43,54 @@
#include "socket.h"
/**
* nice_socket_recv_messages:
* @sock: a #NiceSocket
* @recv_messages: (array length=n_recv_messages) (out caller-allocates):
* array of #NiceInputMessages to return received messages in
* @n_recv_messages: number of elements in the @recv_messages array
*
* Receive up to @n_recv_messages message on the socket, in a non-reliable,
* non-blocking fashion. The total size of the buffers in each #NiceInputMessage
* must be big enough to contain an entire message (65536 bytes), or excess
* bytes will be silently dropped.
*
* On success, the number of messages received into @recv_messages is returned,
* which may be less than @n_recv_messages if the call would have blocked
* part-way through. If the socket would have blocked to begin with, or if
* @n_recv_messages is zero, zero is returned. On failure, a negative value is
* returned, but no further error information is available. Calling this
* function on a socket which has closed is an error, and a negative value is
* returned.
*
* If a positive N is returned, the first N messages in @recv_messages are
* valid. Each valid message is guaranteed to have a non-zero
* #NiceInputMessage::length, and its buffers are guaranteed to be filled
* sequentially up to that number of bytes If #NiceInputMessage::from was
* non-%NULL for a valid message, it may be set to the address of the sender of
* that received message.
*
* If the return value is zero or negative, the from return address and length
* in every #NiceInputMessage in @recv_messages are guaranteed to be unmodified.
* The buffers may have been modified.
*
* The base addresses and sizes of the buffers in a #NiceInputMessage are never
* modified. Neither is the base address of #NiceInputMessage::from, nor the
* base address and length of the #NiceInputMessage::buffers array.
*
* Returns: number of valid messages returned in @recv_messages, or a negative
* value on error
*
* Since: 0.1.5
*/
gint
nice_socket_recv (NiceSocket *sock, NiceAddress *from, guint len, gchar *buf)
nice_socket_recv_messages (NiceSocket *sock,
NiceInputMessage *recv_messages, guint n_recv_messages)
{
return sock->recv (sock, from, len, buf);
g_return_val_if_fail (sock != NULL, -1);
g_return_val_if_fail (n_recv_messages == 0 || recv_messages != NULL, -1);
return sock->recv_messages (sock, recv_messages, n_recv_messages);
}
gboolean
......
......@@ -37,6 +37,7 @@
#ifndef _SOCKET_H
#define _SOCKET_H
#include "agent.h"
#include "address.h"
#include <gio/gio.h>
......@@ -58,8 +59,10 @@ struct _NiceSocket
{
NiceAddress addr;
GSocket *fileno;
gint (*recv) (NiceSocket *sock, NiceAddress *from, guint len,
gchar *buf);
/* Implementations must handle any value of n_recv_messages, including 0. Iff
* n_recv_messages is 0, recv_messages may be NULL. */
gint (*recv_messages) (NiceSocket *sock,
NiceInputMessage *recv_messages, guint n_recv_messages);
gboolean (*send) (NiceSocket *sock, const NiceAddress *to, guint len,
const gchar *buf);
gboolean (*is_reliable) (NiceSocket *sock);
......@@ -69,7 +72,8 @@ struct _NiceSocket
G_GNUC_WARN_UNUSED_RESULT
gint
nice_socket_recv (NiceSocket *sock, NiceAddress *from, guint len, gchar *buf);
nice_socket_recv_messages (NiceSocket *sock,
NiceInputMessage *recv_messages, guint n_recv_messages);
gboolean
nice_socket_send (NiceSocket *sock, const NiceAddress *to,
......
......@@ -76,8 +76,8 @@ struct to_be_sent {
static void socket_close (NiceSocket *sock);
static gint socket_recv (NiceSocket *sock, NiceAddress *from,
guint len, gchar *buf);
static gint socket_recv_messages (NiceSocket *sock,
NiceInputMessage *recv_messages, guint n_recv_messages);
static gboolean socket_send (NiceSocket *sock, const NiceAddress *to,
guint len, const gchar *buf);
static gboolean socket_is_reliable (NiceSocket *sock);
......@@ -106,7 +106,7 @@ nice_socks5_socket_new (NiceSocket *base_socket,
sock->fileno = priv->base_socket->fileno;
sock->addr = priv->base_socket->addr;
sock->send = socket_send;
sock->recv = socket_recv;
sock->recv_messages = socket_recv_messages;
sock->is_reliable = socket_is_reliable;
sock->close = socket_close;
......@@ -160,31 +160,50 @@ socket_close (NiceSocket *sock)
static gint
socket_recv (NiceSocket *sock, NiceAddress *from, guint buf_len, gchar *buf)
socket_recv_messages (NiceSocket *sock,
NiceInputMessage *recv_messages, guint n_recv_messages)
{
Socks5Priv *priv = sock->priv;
if (from)
*from = priv->addr;
guint i;
gint ret = -1;
switch (priv->state) {
case SOCKS_STATE_CONNECTED:
if (priv->base_socket)
return nice_socket_recv (priv->base_socket, NULL, buf_len, buf);
break;
/* Common case: fast pass-through to the base socket once we’re
* connected. */
if (priv->base_socket) {
ret = nice_socket_recv_messages (priv->base_socket,
recv_messages, n_recv_messages);
}
if (ret <= 0)
return ret;
/* After successfully receiving into at least one NiceInputMessage,
* update the from address in each valid NiceInputMessage. */
for (i = 0; i < (guint) ret; i++) {
if (recv_messages[i].from != NULL)
*recv_messages[i].from = priv->addr;
}
return ret;
case SOCKS_STATE_INIT:
{
gchar data[2];
gint ret = -1;
guint8 data[2];
GInputVector local_recv_buf = { data, sizeof (data) };
NiceInputMessage local_recv_message = { &local_recv_buf, 1, NULL, 0 };
nice_debug ("Socks5 state Init");
if (priv->base_socket)
ret = nice_socket_recv (priv->base_socket, NULL, sizeof(data), data);
if (priv->base_socket) {
ret = nice_socket_recv_messages (priv->base_socket,
&local_recv_message, 1);
}
if (ret <= 0) {
return ret;
} else if(ret == sizeof(data)) {
} else if (ret == 1 && local_recv_buf.size == sizeof(data)) {
if (data[0] == 0x05) {
if (data[1] == 0x02) {
gchar msg[515];
......@@ -242,16 +261,19 @@ socket_recv (NiceSocket *sock, NiceAddress *from, guint buf_len, gchar *buf)
break;
case SOCKS_STATE_AUTH:
{
gchar data[2];
gint ret = -1;
guint8 data[2];
GInputVector local_recv_buf = { data, sizeof (data) };
NiceInputMessage local_recv_message = { &local_recv_buf, 1, NULL, 0 };
nice_debug ("Socks5 state auth");
if (priv->base_socket)
ret = nice_socket_recv (priv->base_socket, NULL, sizeof(data), data);
if (priv->base_socket) {
ret = nice_socket_recv_messages (priv->base_socket,
&local_recv_message, 1);
}
if (ret <= 0) {
return ret;
} else if(ret == sizeof(data)) {
} else if (ret == 1 && local_recv_buf.size == sizeof(data)) {
if (data[0] == 0x01 && data[1] == 0x00) {
/* Authenticated */
goto send_connect;
......@@ -264,16 +286,20 @@ socket_recv (NiceSocket *sock, NiceAddress *from, guint buf_len, gchar *buf)
break;
case SOCKS_STATE_CONNECT:
{
gchar data[22];
gint ret = -1;
guint8 data[22];
GInputVector local_recv_buf = { data, sizeof (data) };
NiceInputMessage local_recv_message = { &local_recv_buf, 1, NULL, 0 };
nice_debug ("Socks5 state connect");
if (priv->base_socket)
ret = nice_socket_recv (priv->base_socket, NULL, 4, data);
if (priv->base_socket) {
local_recv_buf.size = 4;
ret = nice_socket_recv_messages (priv->base_socket,
&local_recv_message, 1);
}
if (ret <= 0) {
return ret;
} else if(ret == 4) {
} else if (ret == 1 && local_recv_buf.size == 4) {
if (data[0] == 0x05) {
switch (data[1]) {
case 0x00:
......@@ -281,15 +307,19 @@ socket_recv (NiceSocket *sock, NiceAddress *from, guint buf_len, gchar *buf)
struct to_be_sent *tbs = NULL;
switch (data[3]) {
case 0x01: /* IPV4 bound address */
ret = nice_socket_recv (priv->base_socket, NULL, 6, data);
if (ret != 6) {
local_recv_buf.size = 6;
ret = nice_socket_recv_messages (priv->base_socket,
&local_recv_message, 1);
if (ret != 1 || local_recv_buf.size != 6) {
/* Could not read server bound address */
goto error;
}
break;
case 0x04: /* IPV6 bound address */
ret = nice_socket_recv (priv->base_socket, NULL, 18, data);
if (ret != 18) {
local_recv_buf.size = 18;
ret = nice_socket_recv_messages (priv->base_socket,
&local_recv_message, 1);
if (ret != 1 || local_recv_buf.size != 18) {
/* Could not read server bound address */
goto error;
}
......
......@@ -70,8 +70,8 @@ struct to_be_sent {
#define MAX_QUEUE_LENGTH 20
static void socket_close (NiceSocket *sock);
static gint socket_recv (NiceSocket *sock, NiceAddress *from,
guint len, gchar *buf);
static gint socket_recv_messages (NiceSocket *sock,
NiceInputMessage *recv_messages, guint n_recv_messages);
static gboolean socket_send (NiceSocket *sock, const NiceAddress *to,
guint len, const gchar *buf);
static gboolean socket_is_reliable (NiceSocket *sock);
......@@ -170,7 +170,7 @@ nice_tcp_bsd_socket_new (GMainContext *ctx, NiceAddress *addr)
sock->fileno = gsock;
sock->send = socket_send;
sock->recv = socket_recv;
sock->recv_messages = socket_recv_messages;
sock->is_reliable = socket_is_reliable;
sock->close = socket_close;
......@@ -202,36 +202,54 @@ socket_close (NiceSocket *sock)
}
static gint
socket_recv (NiceSocket *sock, NiceAddress *from, guint len, gchar *buf)
socket_recv_messages (NiceSocket *sock,
NiceInputMessage *recv_messages, guint n_recv_messages)
{
TcpPriv *priv = sock->priv;
int ret;
GError *gerr = NULL;
guint i;
/* Don't try to access the socket if it had an error */
if (priv->error)
return -1;
ret = g_socket_receive (sock->fileno, buf, len, NULL, &gerr);
for (i = 0; i < n_recv_messages; i++) {
gint flags = G_SOCKET_MSG_NONE;
GError *gerr = NULL;
gssize len;
/* recv returns 0 when the peer performed a shutdown.. we must return -1 here
* so that the agent destroys the g_source */
if (ret == 0) {
priv->error = TRUE;
return -1;
}
len = g_socket_receive_message (sock->fileno, NULL,
recv_messages[i].buffers, recv_messages[i].n_buffers,
NULL, NULL, &flags, NULL, &gerr);
recv_messages[i].length = MAX (len, 0);
/* recv returns 0 when the peer performed a shutdown.. we must return -1
* here so that the agent destroys the g_source */
if (len == 0) {
priv->error = TRUE;
break;
}
if (ret < 0) {
if(g_error_matches (gerr, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
ret = 0;
if (len < 0) {
if (g_error_matches (gerr, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
len = 0;
g_error_free (gerr);
return ret;
g_error_free (gerr);
return len;
}
if (recv_messages[i].from)
*recv_messages[i].from = priv->server_addr;
if (len <= 0)
break;
}
if (from)
*from = priv->server_addr;
return ret;
/* Was there an error processing the first message? */
if (priv->error && i == 0)
return -1;
return i;
}
/* Data sent to this function must be a single entity because buffers can be
......
......@@ -43,6 +43,7 @@
#endif
#include "tcp-turn.h"
#include "agent-priv.h"
#include <string.h>
#include <errno.h>
......@@ -66,8 +67,8 @@ typedef struct {
#define MAX_UDP_MESSAGE_SIZE 65535
static void socket_close (NiceSocket *sock);
static gint socket_recv (NiceSocket *sock, NiceAddress *from,
guint len, gchar *buf);
static gint socket_recv_messages (NiceSocket *sock,
NiceInputMessage *recv_messages, guint n_recv_messages);
static gboolean socket_send (NiceSocket *sock, const NiceAddress *to,
guint len, const gchar *buf);
static gboolean socket_is_reliable (NiceSocket *sock);
......@@ -86,7 +87,7 @@ nice_tcp_turn_socket_new (NiceSocket *base_socket,
sock->fileno = priv->base_socket->fileno;
sock->addr = priv->base_socket->addr;
sock->send = socket_send;
sock->recv = socket_recv;
sock->recv_messages = socket_recv_messages;
sock->is_reliable = socket_is_reliable;
sock->close = socket_close;
......@@ -105,13 +106,14 @@ socket_close (NiceSocket *sock)
g_slice_free(TurnTcpPriv, sock->priv);
}
static gint
socket_recv (NiceSocket *sock, NiceAddress *from, guint len, gchar *buf)
static gssize
socket_recv_message (NiceSocket *sock, NiceInputMessage *recv_message)
{
TurnTcpPriv *priv = sock->priv;
int ret;
gssize ret;
guint padlen;
GInputVector local_recv_buf;
NiceInputMessage local_recv_message;
if (priv->expecting_len == 0) {
guint headerlen = 0;
......@@ -124,13 +126,18 @@ socket_recv (NiceSocket *sock, NiceAddress *from, guint len, gchar *buf)
else
return -1;
ret = nice_socket_recv (priv->base_socket, from,
headerlen - priv->recv_buf_len,
(gchar *) priv->recv_buf.u8 + priv->recv_buf_len);
local_recv_buf.buffer = priv->recv_buf.u8 + priv->recv_buf_len;
local_recv_buf.size = headerlen - priv->recv_buf_len;
local_recv_message.buffers = &local_recv_buf;
local_recv_message.n_buffers = 1;
local_recv_message.from = recv_message->from;
local_recv_message.length = 0;
ret = nice_socket_recv_messages (priv->base_socket, &local_recv_message, 1);
if (ret < 0)
return ret;
priv->recv_buf_len += ret;
priv->recv_buf_len += local_recv_message.length;
if (priv->recv_buf_len < headerlen)
return 0;
......@@ -161,27 +168,60 @@ socket_recv (NiceSocket *sock, NiceAddress *from, guint len, gchar *buf)
else
padlen = 0;
ret = nice_socket_recv (priv->base_socket, from,
priv->expecting_len + padlen - priv->recv_buf_len,
(gchar *) priv->recv_buf.u8 + priv->recv_buf_len);
local_recv_buf.buffer = priv->recv_buf.u8 + priv->recv_buf_len;
local_recv_buf.size = priv->expecting_len + padlen - priv->recv_buf_len;
local_recv_message.buffers = &local_recv_buf;
local_recv_message.n_buffers = 1;
local_recv_message.from = recv_message->from;
local_recv_message.length = 0;
ret = nice_socket_recv_messages (priv->base_socket, &local_recv_message, 1);
if (ret < 0)
return ret;
priv->recv_buf_len += ret;
priv->recv_buf_len += local_recv_message.length;
if (priv->recv_buf_len == priv->expecting_len + padlen) {
guint copy_len = MIN (len, priv->recv_buf_len);
memcpy (buf, priv->recv_buf.u8, copy_len);
/* FIXME: Eliminate this memcpy(). */
ret = memcpy_buffer_to_input_message (recv_message,
priv->recv_buf.u8, priv->recv_buf_len);
priv->expecting_len = 0;
priv->recv_buf_len = 0;
return copy_len;
return ret;
}
return 0;
}
static gint
socket_recv_messages (NiceSocket *socket,
NiceInputMessage *recv_messages, guint n_recv_messages)
{
guint i;
gboolean error = FALSE;
for (i = 0; i < n_recv_messages; i++) {
gssize len;
len = socket_recv_message (socket, &recv_messages[i]);
recv_messages[i].length = MAX (len, 0);
if (len < 0)
error = TRUE;
if (len <= 0)
break;
}
/* Was there an error processing the first message? */
if (error && i == 0)
return -1;
return i;
}
static gboolean
socket_send (NiceSocket *sock, const NiceAddress *to,
guint len, const gchar *buf)
......
......@@ -114,8 +114,8 @@ typedef struct {
} SendData;
static void socket_close (NiceSocket *sock);
static gint socket_recv (NiceSocket *sock, NiceAddress *from,
guint len, gchar *buf);
static gint socket_recv_messages (NiceSocket *sock,
NiceInputMessage *recv_messages, guint n_recv_messages);
static gboolean socket_send (NiceSocket *sock, const NiceAddress *to,
guint len, const gchar *buf);
static gboolean socket_is_reliable (NiceSocket *sock);
......@@ -230,7 +230,7 @@ nice_turn_socket_new (GMainContext *ctx, NiceAddress *addr,
sock->addr = *addr;