gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] r15888 - in gnunet/src: include nat util


From: gnunet
Subject: [GNUnet-SVN] r15888 - in gnunet/src: include nat util
Date: Fri, 8 Jul 2011 12:23:45 +0200

Author: grothoff
Date: 2011-07-08 12:23:45 +0200 (Fri, 08 Jul 2011)
New Revision: 15888

Added:
   gnunet/src/nat/test_nat_mini.c
Modified:
   gnunet/src/include/gnunet_nat_lib.h
   gnunet/src/nat/Makefile.am
   gnunet/src/nat/nat_mini.c
   gnunet/src/util/os_priority.c
Log:
towards UPnP support

Modified: gnunet/src/include/gnunet_nat_lib.h
===================================================================
--- gnunet/src/include/gnunet_nat_lib.h 2011-07-08 08:04:25 UTC (rev 15887)
+++ gnunet/src/include/gnunet_nat_lib.h 2011-07-08 10:23:45 UTC (rev 15888)
@@ -201,6 +201,44 @@
 GNUNET_NAT_mini_get_external_ipv4 (struct in_addr *addr);
 
 
+/**
+ * Handle to a mapping created with upnpc.
+ */ 
+struct GNUNET_NAT_MiniHandle;
+
+
+/**
+ * Start mapping the given port using (mini)upnpc.  This function
+ * should typically not be used directly (it is used within the
+ * general-purpose 'GNUNET_NAT_register' code).  However, it can be
+ * used if specifically UPnP-based NAT traversal is to be used or
+ * tested.
+ * 
+ * @param port port to map
+ * @param is_tcp GNUNET_YES to map TCP, GNUNET_NO for UDP
+ * @param ac function to call with mapping result
+ * @param ac_cls closure for 'ac'
+ * @return NULL on error
+ */
+struct GNUNET_NAT_MiniHandle *
+GNUNET_NAT_mini_map_start (uint16_t port,
+                          int is_tcp,
+                          GNUNET_NAT_AddressCallback ac,
+                          void *ac_cls);
+
+
+/**
+ * Remove a mapping created with (mini)upnpc.  Calling
+ * this function will give 'upnpc' 1s to remove tha mapping,
+ * so while this function is non-blocking, a task will be
+ * left with the scheduler for up to 1s past this call.
+ * 
+ * @param mini the handle
+ */
+void
+GNUNET_NAT_mini_map_stop (struct GNUNET_NAT_MiniHandle *mini);
+
+
 #endif 
 
 /* end of gnunet_nat_lib.h */

Modified: gnunet/src/nat/Makefile.am
===================================================================
--- gnunet/src/nat/Makefile.am  2011-07-08 08:04:25 UTC (rev 15887)
+++ gnunet/src/nat/Makefile.am  2011-07-08 10:23:45 UTC (rev 15888)
@@ -57,6 +57,7 @@
 
 check_PROGRAMS = \
   test_nat \
+  test_nat_mini \
   test_nat_test
 
 if ENABLE_TEST_RUN
@@ -69,7 +70,13 @@
  $(top_builddir)/src/nat/libgnunetnat.la \
  $(top_builddir)/src/util/libgnunetutil.la 
 
+test_nat_mini_SOURCES = \
+  test_nat_mini.c
+test_nat_mini_LDADD = \
+ $(top_builddir)/src/nat/libgnunetnat.la \
+ $(top_builddir)/src/util/libgnunetutil.la 
 
+
 test_nat_test_SOURCES = \
   test_nat_test.c
 test_nat_test_LDADD = \

Modified: gnunet/src/nat/nat_mini.c
===================================================================
--- gnunet/src/nat/nat_mini.c   2011-07-08 08:04:25 UTC (rev 15887)
+++ gnunet/src/nat/nat_mini.c   2011-07-08 10:23:45 UTC (rev 15888)
@@ -28,8 +28,24 @@
 #include "gnunet_nat_lib.h"
 #include "nat.h"
 
+/**
+ * How long do we give upnpc to create a mapping?
+ */
+#define MAP_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 
15)
 
+
 /**
+ * How long do we give upnpc to remove a mapping?
+ */
+#define UNMAP_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 
1)
+
+/**
+ * How often do we check for changes in the mapping?
+ */
+#define MAP_REFRESH_FREQ GNUNET_TIME_relative_multiply 
(GNUNET_TIME_UNIT_MINUTES, 15)
+
+
+/**
  * Try to get the external IPv4 address of this peer.
  * Note: calling this function may block this process
  * for a few seconds (!).
@@ -89,5 +105,322 @@
 }
 
 
+/**
+ * Handle to a mapping created with upnpc.
+ */ 
+struct GNUNET_NAT_MiniHandle
+{
 
+  /**
+   * Function to call on mapping changes.
+   */
+  GNUNET_NAT_AddressCallback ac;
+
+  /**
+   * Closure for 'ac'.
+   */
+  void *ac_cls;
+
+  /**
+   * Command used to install the map.
+   */
+  struct GNUNET_OS_CommandHandle *map_cmd;
+
+  /**
+   * Command used to refresh our map information.
+   */
+  struct GNUNET_OS_CommandHandle *refresh_cmd;
+
+  /**
+   * Command used to remove the mapping.
+   */
+  struct GNUNET_OS_CommandHandle *unmap_cmd;
+
+  /**
+   * Our current external mapping (if we have one).
+   */
+  struct sockaddr_in current_addr;
+
+  /**
+   * We check the mapping periodically to see if it
+   * still works.  This task triggers the check.
+   */
+  GNUNET_SCHEDULER_TaskIdentifier refresh_task;
+
+  /**
+   * Are we mapping TCP or UDP?
+   */
+  int is_tcp;
+
+  /**
+   * Did we succeed with creating a mapping?
+   */
+  int did_map;
+
+  /**
+   * Which port are we mapping?
+   */
+  uint16_t port;
+
+};
+
+
+/**
+ * Run upnpc -l to find out if our mapping changed.
+ *
+ * @param cls the 'struct GNUNET_NAT_MiniHandle'
+ * @param tc scheduler context
+ */
+static void
+do_refresh (void *cls,
+           const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+
+/**
+ * Process the output from 'upnpc -l' to see if our
+ * external mapping changed.  If so, do the notifications.
+ *
+ * @param cls the 'struct GNUNET_NAT_MiniHandle'
+ * @param line line of output, NULL at the end
+ */
+static void
+process_refresh_output (void *cls,
+                       const char *line)
+{
+  struct GNUNET_NAT_MiniHandle *mini = cls;
+  enum GNUNET_OS_ProcessStatusType type;
+  unsigned long code;
+
+  if (NULL == line)
+    {
+      GNUNET_OS_command_stop (mini->refresh_cmd,
+                             &type, &code);
+      mini->refresh_cmd = NULL;
+      mini->refresh_task = GNUNET_SCHEDULER_add_delayed (MAP_REFRESH_FREQ,
+                                                        &do_refresh,
+                                                        mini);
+      return;
+    }
+  /* FIXME: parse 'line' */
+  fprintf (stderr,
+          "Refresh output: `%s'\n",
+          line);
+}
+
+
+/**
+ * Run upnpc -l to find out if our mapping changed.
+ *
+ * @param cls the 'struct GNUNET_NAT_MiniHandle'
+ * @param tc scheduler context
+ */
+static void
+do_refresh (void *cls,
+           const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  struct GNUNET_NAT_MiniHandle *mini = cls;
+
+  mini->refresh_task = GNUNET_SCHEDULER_NO_TASK;
+  mini->refresh_cmd = GNUNET_OS_command_run (&process_refresh_output,
+                                            mini,
+                                            MAP_TIMEOUT,
+                                            "upnpc",
+                                            "upnpc",
+                                            "-l",
+                                            NULL);
+}
+
+
+/**
+ * Process the output from the 'upnpc -r' command.
+ *
+ * @param cls the 'struct GNUNET_NAT_MiniHandle'
+ * @param line line of output, NULL at the end
+ */
+static void
+process_map_output (void *cls,
+                   const char *line)
+{
+  struct GNUNET_NAT_MiniHandle *mini = cls;
+  enum GNUNET_OS_ProcessStatusType type;
+  unsigned long code;
+  const char *ipaddr;
+  char *ipa;
+  const char *pstr;
+  unsigned int port;
+
+  if (NULL == line)
+    {
+      GNUNET_OS_command_stop (mini->map_cmd,
+                             &type, &code);
+      mini->map_cmd = NULL;
+      if (mini->did_map == GNUNET_YES)
+       mini->refresh_task = GNUNET_SCHEDULER_add_delayed (MAP_REFRESH_FREQ,
+                                                          &do_refresh,
+                                                          mini);
+      return;
+    }
+  /*
+    The upnpc output we're after looks like this:
+
+     "external 87.123.42.204:3000 TCP is redirected to internal 
192.168.2.150:3000"
+  */
+  if ( (NULL == (ipaddr = strstr (line, " "))) ||
+       (NULL == (pstr = strstr (ipaddr, ":"))) ||
+       (1 != sscanf (pstr + 1, "%u", &port)) )
+    {
+      fprintf (stderr,
+              "Skipping output `%s'\n",
+              line);
+      return; /* skip line */
+    }
+  ipa = GNUNET_strdup (ipaddr + 1);
+  strstr (ipa, ":")[0] = '\0';
+  if (1 != inet_pton (AF_INET,
+                     ipa, 
+                     &mini->current_addr.sin_addr))
+    {
+      GNUNET_free (ipa);
+      fprintf (stderr,
+              "Skipping output `%s'\n",
+              line);
+      return; /* skip line */
+    }
+  GNUNET_free (ipa);         
+
+  mini->current_addr.sin_port = htons (port);
+  mini->current_addr.sin_family = AF_INET;
+#if HAVE_SOCKADDR_IN_SIN_LEN
+  mini->current_addr.sin_len = sizeof (struct sockaddr_in);
+#endif
+  mini->did_map = GNUNET_YES;
+  mini->ac (mini->ac_cls, GNUNET_YES,
+           (const struct sockaddr*) &mini->current_addr,
+           sizeof (mini->current_addr));
+}
+
+
+/**
+ * Start mapping the given port using (mini)upnpc.  This function
+ * should typically not be used directly (it is used within the
+ * general-purpose 'GNUNET_NAT_register' code).  However, it can be
+ * used if specifically UPnP-based NAT traversal is to be used or
+ * tested.
+ * 
+ * @param port port to map
+ * @param is_tcp GNUNET_YES to map TCP, GNUNET_NO for UDP
+ * @param ac function to call with mapping result
+ * @param ac_cls closure for 'ac'
+ * @return NULL on error
+ */
+struct GNUNET_NAT_MiniHandle *
+GNUNET_NAT_mini_map_start (uint16_t port,
+                          int is_tcp,
+                          GNUNET_NAT_AddressCallback ac,
+                          void *ac_cls)
+{
+  struct GNUNET_NAT_MiniHandle *ret;
+  char pstr[6];
+
+  ret = GNUNET_malloc (sizeof (struct GNUNET_NAT_MiniHandle));
+  ret->ac = ac;
+  ret->ac_cls = ac_cls;
+  ret->is_tcp = is_tcp;
+  ret->port = port;
+  GNUNET_snprintf (pstr, sizeof (pstr),
+                  "%u",
+                  (unsigned int) port);
+  ret->map_cmd = GNUNET_OS_command_run (&process_map_output,
+                                       ret,
+                                       MAP_TIMEOUT,
+                                       "upnpc",
+                                       "upnpc",
+                                       "-r", pstr, 
+                                       is_tcp ? "tcp" : "udp",
+                                       NULL);
+  
+  return ret;
+}
+
+
+/**
+ * Process output from our 'unmap' command.
+ *
+ * @param cls the 'struct GNUNET_NAT_MiniHandle'
+ * @param line line of output, NULL at the end
+ */
+static void
+process_unmap_output (void *cls,
+                     const char *line)
+{
+  struct GNUNET_NAT_MiniHandle *mini = cls;
+  enum GNUNET_OS_ProcessStatusType type;
+  unsigned long code;
+
+  if (NULL == line)
+    {
+      GNUNET_OS_command_stop (mini->unmap_cmd,
+                             &type, &code);
+      mini->unmap_cmd = NULL;
+      GNUNET_free (mini);
+      return;
+    }
+  /* we don't really care about the output... */
+}
+
+
+/**
+ * Remove a mapping created with (mini)upnpc.  Calling
+ * this function will give 'upnpc' 1s to remove tha mapping,
+ * so while this function is non-blocking, a task will be
+ * left with the scheduler for up to 1s past this call.
+ * 
+ * @param mini the handle
+ */
+void
+GNUNET_NAT_mini_map_stop (struct GNUNET_NAT_MiniHandle *mini)
+{
+  char pstr[6];
+  enum GNUNET_OS_ProcessStatusType type;
+  unsigned long code;
+
+  if (! mini->did_map)
+    {
+      if (mini->map_cmd != NULL)
+       {
+         GNUNET_OS_command_stop (mini->map_cmd, 
+                                 &type, &code);
+         mini->map_cmd = NULL;
+       }
+      GNUNET_free (mini);
+      return;
+    }
+  if (GNUNET_SCHEDULER_NO_TASK != mini->refresh_task)
+    {
+      GNUNET_SCHEDULER_cancel (mini->refresh_task);
+      mini->refresh_task = GNUNET_SCHEDULER_NO_TASK;
+    }
+  if (mini->refresh_cmd != NULL)
+    {
+      GNUNET_OS_command_stop (mini->refresh_cmd,
+                             &type, &code);
+      mini->refresh_cmd = NULL;
+    }
+  mini->ac (mini->ac_cls, GNUNET_NO,
+           (const struct sockaddr*) &mini->current_addr,
+           sizeof (mini->current_addr));
+  GNUNET_snprintf (pstr, sizeof (pstr),
+                  "%u",
+                  (unsigned int) mini->port);
+  mini->unmap_cmd = GNUNET_OS_command_run (&process_unmap_output,
+                                          mini,
+                                          UNMAP_TIMEOUT,
+                                          "upnpc",
+                                          "upnpc",
+                                          "-d", pstr, 
+                                          mini->is_tcp ? "tcp" : "udp",
+                                          NULL);
+}
+
+
 /* end of nat_mini.c */

Added: gnunet/src/nat/test_nat_mini.c
===================================================================
--- gnunet/src/nat/test_nat_mini.c                              (rev 0)
+++ gnunet/src/nat/test_nat_mini.c      2011-07-08 10:23:45 UTC (rev 15888)
@@ -0,0 +1,142 @@
+/*
+     This file is part of GNUnet.
+     (C) 2009, 2011 Christian Grothoff (and other contributing authors)
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet 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
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+     Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * Testcase for port redirection and public IP address retrieval.
+ * This test never fails, because there need to be a NAT box set up for tha *
+ * @file nat/test_nat_mini.c
+ * @brief Testcase for NAT library - mini 
+ * @author Christian Grothoff
+ *
+ * TODO: actually use ARM to start resolver service to make DNS work!
+ */
+
+#include "platform.h"
+#include "gnunet_common.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_program_lib.h"
+#include "gnunet_scheduler_lib.h"
+#include "gnunet_nat_lib.h"
+
+
+#define VERBOSE GNUNET_YES
+
+
+/* Time to wait before stopping NAT, in seconds */
+#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
+
+
+
+
+
+/**
+ * Function called on each address that the NAT service
+ * believes to be valid for the transport.
+ */
+static void
+addr_callback (void *cls, int add_remove,
+               const struct sockaddr *addr, socklen_t addrlen)
+{
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, 
+             "Address changed: %s `%s' (%u bytes)\n",
+              add_remove == GNUNET_YES ? "added" : "removed",
+              GNUNET_a2s (addr, addrlen),
+             (unsigned int) addrlen);
+}
+
+
+/**
+ * Function that terminates the test.
+ */
+static void
+stop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  struct GNUNET_NAT_MiniHandle *mini = cls;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, 
+             "Stopping NAT and quitting...\n");
+  GNUNET_NAT_mini_map_stop (mini);
+}
+
+#define PORT 10000
+
+/**
+ * Main function run with scheduler.
+ */
+static void
+run (void *cls,
+     char *const *args,
+     const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+  struct GNUNET_NAT_MiniHandle *mini;
+
+  GNUNET_log_setup ("test-nat-mini", "DEBUG", NULL);
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "Requesting NAT redirection for port %u...\n",
+              PORT);
+  mini = GNUNET_NAT_mini_map_start (PORT,
+                                   GNUNET_YES /* tcp */,
+                                   &addr_callback, NULL);
+  if (NULL == mini)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                 "Could not start UPnP interaction\n");
+      return;
+    }
+  GNUNET_SCHEDULER_add_delayed (TIMEOUT, &stop, mini);
+}
+
+
+int
+main (int argc, char *const argv[])
+{
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+    GNUNET_GETOPT_OPTION_END
+  };
+
+  char *const argv_prog[] = {
+    "test-nat-mini",
+    "-c",
+    "test_nat_data.conf",
+    "-L",
+#if VERBOSE
+    "DEBUG",
+#else
+    "WARNING",
+#endif
+    NULL
+  };
+
+  GNUNET_log_setup ("test-nat-mini",
+#if VERBOSE
+                    "DEBUG",
+#else
+                    "WARNING",
+#endif
+                    NULL);
+
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "UPnP test for NAT library, timeout set to %d seconds\n", 
TIMEOUT);
+  GNUNET_PROGRAM_run (5, argv_prog, "test-nat-mini",
+                     "nohelp", options, &run, NULL);
+  return 0;
+}
+
+/* end of test_nat_mini.c */

Modified: gnunet/src/util/os_priority.c
===================================================================
--- gnunet/src/util/os_priority.c       2011-07-08 08:04:25 UTC (rev 15887)
+++ gnunet/src/util/os_priority.c       2011-07-08 10:23:45 UTC (rev 15888)
@@ -1075,6 +1075,7 @@
 #endif
 }
 
+
 /**
  * Retrieve the status of a process
  * @param proc process ID




reply via email to

[Prev in Thread] Current Thread [Next in Thread]