libnice/tests/test-bsd.c

429 lines
14 KiB
C

/*
* This file is part of the Nice GLib ICE library.
*
* (C) 2006, 2007, 2014 Collabora Ltd.
* Contact: Dafydd Harries
* (C) 2006, 2007 Nokia Corporation. All rights reserved.
* Contact: Kai Vehmanen
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the Nice GLib ICE library.
*
* The Initial Developers of the Original Code are Collabora Ltd and Nokia
* Corporation. All Rights Reserved.
*
* Contributors:
* Dafydd Harries, Collabora Ltd.
* Philip Withnall, Collabora Ltd.
*
* Alternatively, the contents of this file may be used under the terms of the
* the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which
* case the provisions of LGPL are applicable instead of those above. If you
* wish to allow use of your version of this file only under the terms of the
* LGPL and not to allow others to use your version of this file under the
* MPL, indicate your decision by deleting the provisions above and replace
* them with the notice and other provisions required by the LGPL. If you do
* not delete the provisions above, a recipient may use your version of this
* file under either the MPL or the LGPL.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <string.h>
#include "socket.h"
static gssize
socket_recv (NiceSocket *sock, NiceAddress *addr, gsize buf_len, gchar *buf)
{
GInputVector local_buf = { buf, buf_len };
NiceInputMessage local_message = { &local_buf, 1, addr, 0 };
gint ret;
ret = nice_socket_recv_messages (sock, &local_message, 1);
if (ret <= 0)
return ret;
return local_buf.size;
}
static void
test_socket_initial_properties (void)
{
NiceSocket *sock;
GError *error = NULL;
sock = nice_udp_bsd_socket_new (NULL, &error);
g_assert_no_error (error);
g_assert_true (sock != NULL);
// not bound to a particular interface
g_assert_cmpint (sock->addr.s.ip4.sin_addr.s_addr, ==, 0);
// is bound to a particular port
g_assert_cmpuint (nice_address_get_port (&sock->addr), !=, 0);
nice_socket_free (sock);
}
static void
test_socket_address_properties (void)
{
NiceSocket *sock;
NiceAddress tmp;
GError *error = NULL;
sock = nice_udp_bsd_socket_new (NULL, &error);
g_assert_no_error (error);
g_assert_true (sock != NULL);
g_assert_true (nice_address_set_from_string (&tmp, "127.0.0.1"));
g_assert_cmpuint (nice_address_get_port (&sock->addr), !=, 0);
nice_address_set_port (&tmp, nice_address_get_port (&sock->addr));
g_assert_cmpuint (nice_address_get_port (&tmp), !=, 0);
nice_socket_free (sock);
}
static void
test_simple_send_recv (void)
{
NiceSocket *server;
NiceSocket *client;
NiceAddress tmp;
gchar buf[5];
GError *error = NULL;
server = nice_udp_bsd_socket_new (NULL, &error);
g_assert_no_error (error);
g_assert_true (server != NULL);
client = nice_udp_bsd_socket_new (NULL, &error);
g_assert_no_error (error);
g_assert_true (client != NULL);
g_assert_true (nice_address_set_from_string (&tmp, "127.0.0.1"));
nice_address_set_port (&tmp, nice_address_get_port (&server->addr));
/* Send and receive stuff. */
g_assert_cmpint (nice_socket_send (client, &tmp, 5, "hello"), ==, 5);
g_assert_cmpint (socket_recv (server, &tmp, 5, buf), ==, 5);
g_assert_cmpint (strncmp (buf, "hello", 5), ==, 0);
g_assert_cmpint (nice_socket_send (server, &tmp, 5, "uryyb"), ==, 5);
g_assert_cmpint (socket_recv (client, &tmp, 5, buf), ==, 5);
g_assert_cmpint (strncmp (buf, "uryyb", 5), ==, 0);
nice_socket_free (client);
nice_socket_free (server);
}
/* Check that sending and receiving to/from zero-length buffers returns
* immediately. */
static void
test_zero_send_recv (void)
{
NiceSocket *sock;
NiceAddress tmp;
gchar buf[5];
NiceOutputMessage local_out_message;
NiceInputMessage local_in_message;
GError *error = NULL;
sock = nice_udp_bsd_socket_new (NULL, &error);
g_assert_no_error (error);
g_assert_true (sock != NULL);
g_assert_true (nice_address_set_from_string (&tmp, "127.0.0.1"));
g_assert_cmpuint (nice_address_get_port (&sock->addr), !=, 0);
nice_address_set_port (&tmp, nice_address_get_port (&sock->addr));
g_assert_cmpuint (nice_address_get_port (&tmp), !=, 0);
g_assert_cmpint (nice_socket_send (sock, &tmp, 0, "ignore-me"), ==, 0);
g_assert_cmpint (nice_socket_send (sock, &tmp, 0, NULL), ==, 0);
g_assert_cmpint (socket_recv (sock, &tmp, 0, buf), ==, 0);
g_assert_cmpint (socket_recv (sock, &tmp, 0, NULL), ==, 0);
/* And again with messages. */
g_assert_cmpint (nice_socket_send_messages (sock, &tmp,
&local_out_message, 0), ==, 0);
g_assert_cmpint (nice_socket_send_messages (sock, &tmp, NULL, 0), ==, 0);
g_assert_cmpint (nice_socket_recv_messages (sock,
&local_in_message, 0), ==, 0);
g_assert_cmpint (nice_socket_recv_messages (sock, NULL, 0), ==, 0);
nice_socket_free (sock);
}
/* Test receiving into multiple tiny buffers. */
static void
test_multi_buffer_recv (void)
{
NiceSocket *server;
NiceSocket *client;
NiceAddress tmp;
guint8 buf[20];
guint8 dummy_buf[9];
GError *error = NULL;
server = nice_udp_bsd_socket_new (NULL, &error);
g_assert_no_error (error);
g_assert_true (server != NULL);
client = nice_udp_bsd_socket_new (NULL, &error);
g_assert_no_error (error);
g_assert_true (client != NULL);
g_assert_true (nice_address_set_from_string (&tmp, "127.0.0.1"));
nice_address_set_port (&tmp, nice_address_get_port (&server->addr));
/* Send and receive stuff. */
{
GInputVector bufs[7] = {
{ &buf[0], 1 },
{ &buf[1], 4 },
{ &buf[1], 0 }, /* should be unused (zero-length) */
{ &buf[5], 1 },
{ &buf[6], 5 },
{ &buf[11], 9 }, /* should be unused (message fits in prior buffers) */
{ &buf[11], 0 }, /* should be unused (zero-length) */
};
NiceInputMessage message = { bufs, G_N_ELEMENTS (bufs), NULL, 0 };
/* Initialise the buffers so we can try and catch out-of-bounds accesses. */
memset (buf, 0xaa, sizeof (buf));
memset (dummy_buf, 0xaa, sizeof (dummy_buf));
/* Send and receive. */
g_assert_cmpint (nice_socket_send (client, &tmp, 11, "hello-world"), ==, 11);
g_assert_cmpuint (nice_socket_recv_messages (server, &message, 1), ==, 1);
g_assert_cmpuint (message.length, ==, 11);
/* Check all of the things. The sizes should not have been modified. */
g_assert_cmpuint (bufs[0].size, ==, 1);
g_assert_cmpuint (bufs[1].size, ==, 4);
g_assert_cmpuint (bufs[2].size, ==, 0);
g_assert_cmpuint (bufs[3].size, ==, 1);
g_assert_cmpuint (bufs[4].size, ==, 5);
g_assert_cmpuint (bufs[5].size, ==, 9);
g_assert_cmpuint (bufs[6].size, ==, 0);
g_assert_cmpint (strncmp ((gchar *) buf, "hello-world", 11), ==, 0);
g_assert_cmpmem (buf + 11, 9, dummy_buf, 9);
}
nice_socket_free (client);
nice_socket_free (server);
}
/* Fill a buffer with deterministic but non-repeated data, so that transmission
* and reception corruption is more likely to be detected. */
static void
fill_send_buf (guint8 *buf, gsize buf_len, guint seed)
{
gsize i;
for (i = 0; i < buf_len; i++) {
buf[i] = '0' + (seed % 10);
seed++;
}
}
/* Test receiving multiple messages in a single call. */
static void
test_multi_message_recv (guint n_sends, guint n_receives,
guint n_bufs_per_message, gsize send_buf_size, gsize recv_buf_size,
guint expected_n_received_messages, guint expected_n_sent_messages)
{
NiceSocket *server;
NiceSocket *client;
NiceAddress tmp;
GError *error = NULL;
server = nice_udp_bsd_socket_new (NULL, &error);
g_assert_no_error (error);
g_assert_true (server != NULL);
client = nice_udp_bsd_socket_new (NULL, &error);
g_assert_no_error (error);
g_assert_true (client != NULL);
g_assert_true (nice_address_set_from_string (&tmp, "127.0.0.1"));
nice_address_set_port (&tmp, nice_address_get_port (&server->addr));
/* Send and receive stuff. */
{
GInputVector *recv_bufs;
NiceInputMessage *recv_messages;
GOutputVector *send_bufs;
NiceOutputMessage *send_messages;
guint i, j;
guint8 *_expected_recv_buf;
gsize expected_recv_buf_len;
/* Set up the send buffers. */
send_bufs = g_malloc0_n (n_sends * n_bufs_per_message,
sizeof (GOutputVector));
send_messages = g_malloc0_n (n_sends, sizeof (NiceOutputMessage));
for (i = 0; i < n_sends; i++) {
for (j = 0; j < n_bufs_per_message; j++) {
guint8 *buf = g_slice_alloc (send_buf_size);
send_bufs[i * n_bufs_per_message + j].buffer = buf;
send_bufs[i * n_bufs_per_message + j].size = send_buf_size;
/* Set up the buffer data. */
fill_send_buf (buf, send_buf_size, i);
}
send_messages[i].buffers = send_bufs + i * n_bufs_per_message;
send_messages[i].n_buffers = n_bufs_per_message;
}
/* Set up the receive buffers. Yay for dynamic tests! */
recv_bufs = g_malloc0_n (n_receives * n_bufs_per_message,
sizeof (GInputVector));
recv_messages = g_malloc0_n (n_receives, sizeof (NiceInputMessage));
for (i = 0; i < n_receives; i++) {
for (j = 0; j < n_bufs_per_message; j++) {
recv_bufs[i * n_bufs_per_message + j].buffer =
g_slice_alloc (recv_buf_size);
recv_bufs[i * n_bufs_per_message + j].size = recv_buf_size;
/* Initialise the buffer to try to catch out-of-bounds accesses. */
memset (recv_bufs[i * n_bufs_per_message + j].buffer, 0xaa,
recv_buf_size);
}
recv_messages[i].buffers = recv_bufs + i * n_bufs_per_message;
recv_messages[i].n_buffers = n_bufs_per_message;
recv_messages[i].from = NULL;
recv_messages[i].length = 0;
}
/* Send multiple packets. */
g_assert_cmpint (
nice_socket_send_messages (client, &tmp, send_messages, n_sends), ==,
expected_n_sent_messages);
/* Receive things. */
g_assert_cmpint (
nice_socket_recv_messages (server, recv_messages, n_receives), ==,
expected_n_received_messages);
/* Check all of the things. The sizes should not have been modified. */
expected_recv_buf_len = recv_buf_size * n_bufs_per_message;
_expected_recv_buf = g_slice_alloc (expected_recv_buf_len);
for (i = 0; i < expected_n_received_messages; i++) {
NiceInputMessage *message = &recv_messages[i];
guint8 *expected_recv_buf = _expected_recv_buf;
gsize expected_len;
expected_len = MIN (send_buf_size * n_bufs_per_message,
expected_recv_buf_len);
g_assert_cmpuint (message->length, ==, expected_len);
/* Build the expected buffer as a concatenation of the expected values of
* all receive buffers in the message. */
memset (expected_recv_buf, 0xaa, expected_recv_buf_len);
fill_send_buf (expected_recv_buf, expected_len, i);
for (j = 0; j < n_bufs_per_message; j++) {
g_assert_cmpuint (message->buffers[j].size, ==, recv_buf_size);
g_assert_cmpint (
memcmp (message->buffers[j].buffer, expected_recv_buf,
recv_buf_size), ==, 0);
expected_recv_buf += recv_buf_size;
}
}
g_slice_free1 (expected_recv_buf_len, _expected_recv_buf);
for (i = 0; i < n_receives; i++) {
for (j = 0; j < n_bufs_per_message; j++) {
g_slice_free1 (recv_buf_size,
recv_bufs[i * n_bufs_per_message + j].buffer);
}
}
for (i = 0; i < n_sends; i++) {
for (j = 0; j < n_bufs_per_message; j++) {
g_slice_free1 (send_buf_size,
(gpointer) send_bufs[i * n_bufs_per_message + j].buffer);
}
}
g_free (recv_messages);
g_free (recv_bufs);
g_free (send_messages);
g_free (send_bufs);
}
nice_socket_free (client);
nice_socket_free (server);
}
int
main (void)
{
test_socket_initial_properties ();
test_socket_address_properties ();
test_simple_send_recv ();
test_zero_send_recv ();
test_multi_buffer_recv ();
/* Multi-message testing. Serious business. */
{
guint i;
struct {
guint n_sends; /* messages */
guint expected_n_sent_messages;
guint n_receives; /* messages */
guint expected_n_received_messages;
guint n_bufs_per_message;
gsize send_buf_size;
gsize recv_buf_size;
} test_cases[] = {
/* same number of sends and receives */
{ 2, 2, 2, 2, 1, 100, 100 }, /* send 200B, receive 200B */
/* more sends than receives */
{ 4, 4, 2, 2, 2, 100, 77 }, /* send 800B, receive 308B */
/* more receives than sends */
{ 1, 1, 4, 1, 4, 10, 100 }, /* send 40B, receive 1600B */
/* small receive buffer (data loss) */
{ 100, 100, 100, 100, 1, 100, 64 }, /* send 10000B, receive 6400B */
/* small receive buffers (data loss) */
{ 50, 50, 50, 50, 10, 100, 8 }, /* send 50000B, receive 4000B */
};
for (i = 0; i < G_N_ELEMENTS (test_cases); i++) {
test_multi_message_recv (test_cases[i].n_sends, test_cases[i].n_receives,
test_cases[i].n_bufs_per_message, test_cases[i].send_buf_size,
test_cases[i].recv_buf_size,
test_cases[i].expected_n_received_messages,
test_cases[i].expected_n_sent_messages);
}
}
return 0;
}