[farsight2/master] Use internal stunalternd for testing

Olivier Crête olivier.crete at collabora.co.uk
Wed Apr 15 15:29:22 PDT 2009


---
 tests/check/Makefile.am               |    9 +-
 tests/check/transmitter/generic.c     |   60 ------
 tests/check/transmitter/generic.h     |    8 -
 tests/check/transmitter/rawudp.c      |   56 +++++-
 tests/check/transmitter/stunalternd.c |  350 +++++++++++++++++++++++++++++++++
 tests/check/transmitter/stunalternd.h |   38 ++++
 6 files changed, 448 insertions(+), 73 deletions(-)
 create mode 100644 tests/check/transmitter/stunalternd.c
 create mode 100644 tests/check/transmitter/stunalternd.h

diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am
index 918f55c..75a934c 100644
--- a/tests/check/Makefile.am
+++ b/tests/check/Makefile.am
@@ -63,16 +63,19 @@ LDADD = \
 	$(GST_CHECK_LIBS) \
 	$(GST_LIBS)
 
-transmitter_rawudp_CFLAGS = $(AM_CFLAGS) $(GUPNP_CFLAGS)
+transmitter_rawudp_CFLAGS = $(AM_CFLAGS) $(GUPNP_CFLAGS) $(NICE_CFLAGS)
 transmitter_rawudp_LDADD = $(LDADD) \
-	$(GUPNP_LIBS)
+	$(GUPNP_LIBS) \
+	$(NICE_LIBS)
 transmitter_rawudp_SOURCES = \
 	check-threadsafe.h  \
 	transmitter/generic.c \
 	transmitter/generic.h \
 	transmitter/rawudp.c \
 	transmitter/rawudp-upnp.c \
-	transmitter/rawudp-upnp.h
+	transmitter/rawudp-upnp.h \
+	transmitter/stunalternd.c \
+	transmitter/stunalternd.h
 
 
 transmitter_multicast_CFLAGS = $(AM_CFLAGS)
diff --git a/tests/check/transmitter/generic.c b/tests/check/transmitter/generic.c
index f20aa55..c8ff8fb 100644
--- a/tests/check/transmitter/generic.c
+++ b/tests/check/transmitter/generic.c
@@ -32,7 +32,6 @@
 #include "check-threadsafe.h"
 #include "generic.h"
 
-
 static void
 _transmitter_error (FsTransmitter *transmitter, gint errorno, gchar *error_msg,
   gchar *debug_msg, gpointer user_data)
@@ -242,62 +241,3 @@ teardown_stund (void)
   stund_pid = 0;
 }
 
-
-GPid stunalternd_pid = 0;
-
-static void
-setup_stunalternd_internal (gchar *argv[])
-{
-  GError *error = NULL;
-
-  stunalternd_pid = 0;
-
-  if (!g_spawn_async (NULL, argv, NULL,
-          G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
-          NULL, NULL, &stunalternd_pid, &error))
-  {
-    g_debug ("Could not spawn stunalternd, skipping stun testing: %s",
-        error->message);
-    g_clear_error (&error);
-    return;
-  }
-}
-
-void
-setup_stunalternd_valid (void)
-{
-  gchar *argv[] = {"stunalternd", "127.0.0.1", "3478", "3480", NULL};
-  setup_stunalternd_internal (argv);
-}
-
-void
-setup_stunalternd_loop (void)
-{
-  gchar *argv[] = {"stunalternd", "127.0.0.1", "3480", "3480", NULL};
-  setup_stunalternd_internal (argv);
-}
-
-void
-teardown_stunalternd (void)
-{
-  if (!stunalternd_pid)
-    return;
-
-  kill (stunalternd_pid, SIGTERM);
-  waitpid (stunalternd_pid, NULL, 0);
-  g_spawn_close_pid (stunalternd_pid);
-  stunalternd_pid = 0;
-}
-
-void setup_stund_stunalternd (void)
-{
-  setup_stund ();
-  setup_stunalternd_valid ();
-}
-
-
-void teardown_stund_stunalternd (void)
-{
-  teardown_stund ();
-  teardown_stunalternd ();
-}
diff --git a/tests/check/transmitter/generic.h b/tests/check/transmitter/generic.h
index 642a2c4..200b4c8 100644
--- a/tests/check/transmitter/generic.h
+++ b/tests/check/transmitter/generic.h
@@ -39,16 +39,8 @@ gboolean bus_error_callback (GstBus *bus, GstMessage *message,
 void test_transmitter_creation (gchar *transmitter_name);
 
 extern GPid stund_pid;
-extern GPid stunalternd_pid;
 
 void setup_stund (void);
 void teardown_stund (void);
 
-void setup_stunalternd_valid (void);
-void setup_stunalternd_loop (void);
-void teardown_stunalternd (void);
-
-void setup_stund_stunalternd (void);
-void teardown_stund_stunalternd (void);
-
 #endif /* __GENERIC_H__ */
diff --git a/tests/check/transmitter/rawudp.c b/tests/check/transmitter/rawudp.c
index ea60015..22afb29 100644
--- a/tests/check/transmitter/rawudp.c
+++ b/tests/check/transmitter/rawudp.c
@@ -35,6 +35,9 @@
 #include "generic.h"
 #include "transmitter/rawudp-upnp.h"
 
+#include "stunalternd.h"
+
+
 gint buffer_count[2] = {0, 0};
 GMainLoop *loop = NULL;
 gint candidates[2] = {0, 0};
@@ -48,6 +51,7 @@ gboolean associate_on_source = TRUE;
 gboolean pipeline_done = FALSE;
 GStaticMutex pipeline_mod_mutex = G_STATIC_MUTEX_INIT;
 
+void *stun_alternd_data = NULL;
 
 enum {
   FLAG_HAS_STUN  = 1 << 0,
@@ -809,7 +813,7 @@ GST_START_TEST (test_rawudptransmitter_run_stunalternd)
 {
   GParameter params[4];
 
-  if (stund_pid <= 0 || stunalternd_pid <= 0)
+  if (stund_pid <= 0 || stun_alternd_data == NULL)
     return;
 
   memset (params, 0, sizeof (GParameter) * 4);
@@ -840,7 +844,7 @@ GST_START_TEST (test_rawudptransmitter_run_stun_altern_to_nowhere)
 {
   GParameter params[3];
 
-  if (stunalternd_pid <= 0)
+  if (stun_alternd_data == NULL)
     return;
 
   /*
@@ -867,6 +871,54 @@ GST_START_TEST (test_rawudptransmitter_run_stun_altern_to_nowhere)
 GST_END_TEST;
 
 
+void
+setup_stunalternd_valid (void)
+{
+  stun_alternd_data = stun_alternd_init (AF_INET,
+      "127.0.0.1", 3478, 3480);
+
+  if (!stun_alternd_data)
+    g_debug ("Could not spawn stunalternd,"
+        " skipping stun alternate server testing");
+}
+
+static void
+setup_stunalternd_loop (void)
+{
+  stun_alternd_data = stun_alternd_init (AF_INET,
+      "127.0.0.1", 3478, 3478);
+
+  if (!stun_alternd_data)
+    g_debug ("Could not spawn stunalternd,"
+        " skipping stun alternate server testing");
+}
+
+static void
+teardown_stunalternd (void)
+{
+  if (!stun_alternd_data)
+    return;
+
+  stun_alternd_stop (stun_alternd_data);
+  stun_alternd_data = NULL;
+}
+
+static void
+setup_stund_stunalternd (void)
+{
+  setup_stund ();
+  setup_stunalternd_valid ();
+}
+
+
+static void
+teardown_stund_stunalternd (void)
+{
+  teardown_stund ();
+  teardown_stunalternd ();
+}
+
+
 static Suite *
 rawudptransmitter_suite (void)
 {
diff --git a/tests/check/transmitter/stunalternd.c b/tests/check/transmitter/stunalternd.c
new file mode 100644
index 0000000..19a8d95
--- /dev/null
+++ b/tests/check/transmitter/stunalternd.c
@@ -0,0 +1,350 @@
+/* Farsight 2 unit tests for FsRawUdpTransmitter
+ * This file is taken from the Nice GLib ICE library. 
+ *
+ * (C) 2007-2009 Nokia Corporation
+ *  @contributor: Rémi Denis-Courmont
+ * (C) 2008-2009 Collabora Ltd
+ *  @author: Youness Alaoui <youness.alaoui at collabora.co.uk>
+ *  @author: Olivier Crete <olivier.crete at collabora.co.uk>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <signal.h>
+
+#include <sys/types.h>
+
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+
+#include <unistd.h>
+#include <getopt.h>
+#include <errno.h>
+#include <limits.h>
+
+#include <pthread.h>
+
+#ifndef SOL_IP
+# define SOL_IP IPPROTO_IP
+#endif
+
+#ifndef SOL_IPV6
+# define SOL_IPV6 IPPROTO_IPV6
+#endif
+
+#ifndef IPV6_RECVPKTINFO
+# define IPV6_RECVPKTINFO IPV6_PKTINFO
+#endif
+
+/** Default port for STUN binding discovery */
+#define IPPORT_STUN  3478
+
+#include <stun/stunagent.h>
+#include "stunalternd.h"
+
+static const uint16_t known_attributes[] =  {
+  0
+};
+
+/**
+ * Creates a listening socket
+ */
+int listen_socket (int fam, int type, int proto, unsigned int port)
+{
+  int yes = 1;
+  int fd = socket (fam, type, proto);
+  union {
+    struct sockaddr addr;
+    struct sockaddr_in in;
+    struct sockaddr_in6 in6;
+    struct sockaddr_storage storage;
+  } addr;
+  if (fd == -1)
+  {
+    perror ("Error opening IP port");
+    return -1;
+  }
+  if (fd < 3)
+    goto error;
+
+  memset (&addr, 0, sizeof (addr));
+  addr.storage.ss_family = fam;
+
+  switch (fam)
+  {
+    case AF_INET:
+      addr.in.sin_port = htons (port);
+      break;
+
+    case AF_INET6:
+      addr.in6.sin6_port = htons (port);
+      break;
+  }
+
+  if (bind (fd, (struct sockaddr *)&addr, sizeof (addr)))
+  {
+    perror ("Error opening IP port");
+    goto error;
+  }
+
+  if ((type == SOCK_DGRAM) || (type == SOCK_RAW))
+  {
+    switch (fam)
+    {
+      case AF_INET:
+        setsockopt (fd, SOL_IP, IP_RECVERR, &yes, sizeof (yes));
+        break;
+
+      case AF_INET6:
+        setsockopt (fd, SOL_IPV6, IPV6_RECVERR, &yes, sizeof (yes));
+        break;
+    }
+  }
+  else
+  {
+    if (listen (fd, INT_MAX))
+    {
+      perror ("Error opening IP port");
+      goto error;
+    }
+  }
+
+  return fd;
+
+error:
+  close (fd);
+  return -1;
+}
+
+
+/** Dequeue error from a socket if applicable */
+static int recv_err (int fd)
+{
+  struct msghdr hdr;
+  memset (&hdr, 0, sizeof (hdr));
+  return recvmsg (fd, &hdr, MSG_ERRQUEUE) >= 0;
+}
+
+
+/** Receives a message or dequeues an error from a socket */
+ssize_t recv_safe (int fd, struct msghdr *msg)
+{
+  ssize_t len = recvmsg (fd, msg, 0);
+  if (len == -1)
+    recv_err (fd);
+  else
+  if (msg->msg_flags & MSG_TRUNC)
+  {
+    errno = EMSGSIZE;
+    return -1;
+  }
+
+  return len;
+}
+
+
+/** Sends a message through a socket */
+ssize_t send_safe (int fd, const struct msghdr *msg)
+{
+  ssize_t len;
+
+  do
+    len = sendmsg (fd, msg, 0);
+  while ((len == -1) && (recv_err (fd) == 0));
+
+  return len;
+}
+
+
+static int dgram_process (int sock, StunAgent *oldagent, StunAgent *newagent,
+    struct sockaddr *alt_addr, socklen_t alt_addr_len)
+{
+  struct sockaddr_storage addr;
+  uint8_t buf[STUN_MAX_MESSAGE_SIZE];
+  char ctlbuf[256];
+  struct iovec iov = { buf, sizeof (buf) };
+  StunMessage request;
+  StunMessage response;
+  StunValidationStatus validation;
+  StunAgent *agent = NULL;
+
+  struct msghdr mh =
+  {
+    .msg_name = (struct sockaddr *)&addr,
+    .msg_namelen = sizeof (addr),
+    .msg_iov = &iov,
+    .msg_iovlen = 1,
+    .msg_control = ctlbuf,
+    .msg_controllen = sizeof (ctlbuf)
+  };
+
+  size_t len = recv_safe (sock, &mh);
+  if (len == (size_t)-1)
+    return -1;
+
+  validation = stun_agent_validate (newagent, &request, buf, len, NULL, 0);
+
+  if (validation == STUN_VALIDATION_SUCCESS) {
+    agent = newagent;
+  }
+  else {
+    validation = stun_agent_validate (oldagent, &request, buf, len, NULL, 0);
+    agent = oldagent;
+  }
+
+  /* Unknown attributes */
+  if (validation == STUN_VALIDATION_UNKNOWN_REQUEST_ATTRIBUTE)
+  {
+    stun_agent_build_unknown_attributes_error (agent, &response, buf,
+        sizeof (buf), &request);
+    goto send_buf;
+  }
+
+  /* Mal-formatted packets */
+  if (validation != STUN_VALIDATION_SUCCESS ||
+      stun_message_get_class (&request) != STUN_REQUEST) {
+    return -1;
+  }
+
+  switch (stun_message_get_method (&request))
+  {
+    case STUN_BINDING:
+      stun_agent_init_error (agent, &response, buf, sizeof (buf), &request,
+          STUN_ERROR_TRY_ALTERNATE);
+      stun_message_append_addr (&response, STUN_ATTRIBUTE_ALTERNATE_SERVER,
+          alt_addr, alt_addr_len);
+      break;
+
+    default:
+      stun_agent_init_error (agent, &response, buf, sizeof (buf),
+          &request, STUN_ERROR_BAD_REQUEST);
+  }
+
+  iov.iov_len = stun_agent_finish_message (agent, &response, NULL, 0);
+send_buf:
+
+  len = send_safe (sock, &mh);
+  return (len < iov.iov_len) ? -1 : 0;
+}
+
+
+
+static int
+resolve_addr (char *server, unsigned int port, int family,
+    struct sockaddr *addr, socklen_t *addr_len)
+{
+  struct addrinfo hints, *res;
+  int ret = -1;
+  char portstr[10];
+
+  memset (&hints, 0, sizeof (hints));
+  hints.ai_family = family;
+  hints.ai_socktype = SOCK_DGRAM;
+  hints.ai_flags = AI_NUMERICHOST;
+
+  snprintf (portstr, 9, "%u", port);
+
+  ret = getaddrinfo (server, portstr, &hints, &res);
+  if (ret)
+  {
+    fprintf (stderr, "%s: %s:%s\n", server, portstr,
+             gai_strerror (ret));
+    return 0;
+  }
+
+  memcpy (addr, res->ai_addr, res->ai_addrlen);
+  *addr_len = res->ai_addrlen;
+
+  freeaddrinfo (res);
+
+  return 1;
+}
+
+struct thread_data {
+  pthread_t thread;
+  struct sockaddr_storage alt_addr;
+  socklen_t alt_addr_len;
+  StunAgent oldagent;
+  StunAgent newagent;
+  int sock;
+};
+
+void * stund_thread (void *data)
+{
+  struct thread_data *td = data;
+
+  pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
+  pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL);
+
+  for (;;)
+    dgram_process (td->sock, &td->oldagent, &td->newagent,
+        (struct sockaddr*) &td->alt_addr, td->alt_addr_len);
+
+
+  return NULL;
+}
+
+void *stun_alternd_init (int family, char *redirect_ip,
+    unsigned int redirect_port,
+    unsigned int listen_port)
+{
+  struct thread_data *td;
+
+  td = malloc (sizeof(struct thread_data));
+
+  if (!redirect_port)
+    redirect_port = IPPORT_STUN;
+
+  if (!listen_port)
+    listen_port = IPPORT_STUN;
+
+  if (!resolve_addr (redirect_ip, redirect_port, family,
+          (struct sockaddr *)&td->alt_addr, &td->alt_addr_len))
+  {
+    free (td);
+    return NULL;
+  }
+
+  td->sock = listen_socket (family, SOCK_DGRAM, IPPROTO_UDP, listen_port);
+  if (td->sock == -1)
+  {
+    free (td);
+    return NULL;
+  }
+
+  stun_agent_init (&td->oldagent, known_attributes,
+      STUN_COMPATIBILITY_RFC3489, 0);
+  stun_agent_init (&td->newagent, known_attributes,
+      STUN_COMPATIBILITY_RFC5389, STUN_AGENT_USAGE_USE_FINGERPRINT);
+
+  pthread_create (&td->thread, NULL, stund_thread, td);
+
+  return td;
+}
+
+
+void stun_alternd_stop (void *data)
+{
+  struct thread_data *td = data;
+
+  pthread_cancel (td->thread);
+  pthread_join (td->thread, NULL);
+  free (data);
+}
diff --git a/tests/check/transmitter/stunalternd.h b/tests/check/transmitter/stunalternd.h
new file mode 100644
index 0000000..d5be290
--- /dev/null
+++ b/tests/check/transmitter/stunalternd.h
@@ -0,0 +1,38 @@
+/* Farsight 2 unit tests for FsRawUdpTransmitter
+ * This file is taken from the Nice GLib ICE library. 
+ *
+ * (C) 2007-2009 Nokia Corporation
+ *  @contributor: Rémi Denis-Courmont
+ * (C) 2008-2009 Collabora Ltd
+ *  @author: Youness Alaoui <youness.alaoui at collabora.co.uk>
+ *  @author: Olivier Crete <olivier.crete at collabora.co.uk>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#ifndef __STUNALTERND_H__
+#define __STUNALTERND_H__
+
+#include <sys/socket.h>
+#include <pthread.h>
+
+void *stun_alternd_init (int family,
+    char *redirect_ip,
+    unsigned int redirect_port,
+    unsigned int listen_port);
+
+void stun_alternd_stop (void *data);
+
+#endif /* __STUNALTERND_H__ */
-- 
1.5.6.5



More information about the farsight-commits mailing list