gnunet-svn
[Top][All Lists]
Advanced

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

[GNUnet-SVN] r9271 - in gnunet/src: . include nat nat/libnatpmp nat/mini


From: gnunet
Subject: [GNUnet-SVN] r9271 - in gnunet/src: . include nat nat/libnatpmp nat/miniupnp
Date: Sun, 25 Oct 2009 03:44:36 -0600

Author: moon
Date: 2009-10-25 03:44:36 -0600 (Sun, 25 Oct 2009)
New Revision: 9271

Added:
   gnunet/src/include/gnunet_nat_lib.h
   gnunet/src/nat/
   gnunet/src/nat/Makefile.am
   gnunet/src/nat/libnatpmp/
   gnunet/src/nat/libnatpmp/Makefile.am
   gnunet/src/nat/libnatpmp/README
   gnunet/src/nat/libnatpmp/declspec.h
   gnunet/src/nat/libnatpmp/getgateway.c
   gnunet/src/nat/libnatpmp/getgateway.h
   gnunet/src/nat/libnatpmp/natpmp.c
   gnunet/src/nat/libnatpmp/natpmp.h
   gnunet/src/nat/miniupnp/
   gnunet/src/nat/miniupnp/Makefile.am
   gnunet/src/nat/miniupnp/README
   gnunet/src/nat/miniupnp/bsdqueue.h
   gnunet/src/nat/miniupnp/codelength.h
   gnunet/src/nat/miniupnp/declspec.h
   gnunet/src/nat/miniupnp/igd_desc_parse.c
   gnunet/src/nat/miniupnp/igd_desc_parse.h
   gnunet/src/nat/miniupnp/minisoap.c
   gnunet/src/nat/miniupnp/minisoap.h
   gnunet/src/nat/miniupnp/minissdpc.c
   gnunet/src/nat/miniupnp/minissdpc.h
   gnunet/src/nat/miniupnp/miniupnpc.c
   gnunet/src/nat/miniupnp/miniupnpc.h
   gnunet/src/nat/miniupnp/miniupnpcstrings.h
   gnunet/src/nat/miniupnp/miniwget.c
   gnunet/src/nat/miniupnp/miniwget.h
   gnunet/src/nat/miniupnp/minixml.c
   gnunet/src/nat/miniupnp/minixml.h
   gnunet/src/nat/miniupnp/upnpcommands.c
   gnunet/src/nat/miniupnp/upnpcommands.h
   gnunet/src/nat/miniupnp/upnpreplyparse.c
   gnunet/src/nat/miniupnp/upnpreplyparse.h
   gnunet/src/nat/nat.c
   gnunet/src/nat/natpmp.c
   gnunet/src/nat/natpmp.h
   gnunet/src/nat/upnp.c
   gnunet/src/nat/upnp.h
Modified:
   gnunet/src/Makefile.am
Log:
initial NAT lib commit (UPnP and NAT-PMP support)


Modified: gnunet/src/Makefile.am
===================================================================
--- gnunet/src/Makefile.am      2009-10-24 22:43:04 UTC (rev 9270)
+++ gnunet/src/Makefile.am      2009-10-25 09:44:36 UTC (rev 9271)
@@ -13,6 +13,7 @@
   arm \
   fragmentation \
   hello \
+  nat \
   peerinfo \
   statistics \
   datacache \

Added: gnunet/src/include/gnunet_nat_lib.h
===================================================================
--- gnunet/src/include/gnunet_nat_lib.h                         (rev 0)
+++ gnunet/src/include/gnunet_nat_lib.h 2009-10-25 09:44:36 UTC (rev 9271)
@@ -0,0 +1,99 @@
+/*
+     This file is part of GNUnet.
+     (C) 2007, 2008, 2009 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 2, 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.
+*/
+
+/**
+ * @file include/gnunet_nat_lib.h
+ * @brief Library handling UPnP and NAT-PMP port forwarding and
+ *     external IP address retrieval
+ *
+ * @author Milan Bouchet-Valat
+ */
+
+#ifndef GNUNET_NAT_LIB_H
+#define GNUNET_NAT_LIB_H 1
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "upnp.h"
+#include "natpmp.h"
+
+#include <inttypes.h>
+
+/* Used to communicate with the UPnP and NAT-PMP plugins */
+typedef enum
+{
+  GNUNET_NAT_PORT_ERROR,
+  GNUNET_NAT_PORT_UNMAPPED,
+  GNUNET_NAT_PORT_UNMAPPING,
+  GNUNET_NAT_PORT_MAPPING,
+  GNUNET_NAT_PORT_MAPPED
+}
+GNUNET_NAT_port_forwarding;
+
+/**
+ * Signature of the callback passed to GNUNET_NAT_register.
+ *
+ * @cls closure
+ * @add_remove GNUNET_YES to mean the new public IP address, GNUNET_NO to mean
+ *     the previous (now invalid) one
+ * @addr either the previous or the new public IP address
+ * @addrlen actual lenght of the address
+ */
+typedef void (*GNUNET_NAT_AddressCallback) (void *cls, int add_remove,
+                                            const struct sockaddr * addr,
+                                            socklen_t addrlen);
+
+typedef struct GNUNET_NAT_Handle GNUNET_NAT_Handle;
+
+/**
+ * Attempt to enable port redirection and detect public IP address contacting
+ * UPnP or NAT-PMP routers on the local network. Use @addr to specify to which
+ * of the local host's addresses should the external port be mapped. The port
+ * is taken from the corresponding sockaddr_in[6] field.
+ *
+ * @sched the sheduler used in the program
+ * @addr the local address packets should be redirected to
+ * @addrlen actual lenght of the address
+ * @callback function to call everytime the public IP address changes
+ * @callback_cls closure for @callback
+ */
+struct GNUNET_NAT_Handle *GNUNET_NAT_register (struct GNUNET_SCHEDULER_Handle
+                                               *sched,
+                                               const struct sockaddr *addr,
+                                               socklen_t addrlen,
+                                               GNUNET_NAT_AddressCallback
+                                               callback, void *callback_cls);
+
+/**
+ * Stop port redirection and public IP address detection for the given handle.
+ * This frees the handle, after having sent the needed commands to close open 
ports.
+ *
+ * @h the handle to stop
+ */
+void GNUNET_NAT_unregister (struct GNUNET_NAT_Handle *h);
+
+/**
+ * Compare the sin(6)_addr fields of AF_INET or AF_INET(6) sockaddr.
+ * @param a first sockaddr
+ * @param second sockaddr
+ * @returns 0 if addresses are equal, non-null value otherwise */
+int GNUNET_NAT_cmp_addr (const struct sockaddr *a, const struct sockaddr *b);
+
+#endif /* GNUNET_NAT_LIB_H */

Added: gnunet/src/nat/Makefile.am
===================================================================
--- gnunet/src/nat/Makefile.am                          (rev 0)
+++ gnunet/src/nat/Makefile.am  2009-10-25 09:44:36 UTC (rev 9271)
@@ -0,0 +1,44 @@
+SUBDIRS = miniupnp libnatpmp
+
+INCLUDES = -I$(top_srcdir)/src/include
+
+if MINGW
+  WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols
+endif
+
+if USE_COVERAGE
+  AM_CFLAGS = -fprofile-arcs -ftest-coverage
+endif
+
+lib_LTLIBRARIES = libgnunetnat.la
+
+libgnunetnat_la_SOURCES = \
+  upnp.c upnp.h \
+  natpmp.c natpmp.h \
+  nat.c nat.h
+
+libgnunetnat_la_CFLAGS = \
+ -I$(top_scrdir)/include
+
+libgnunetnat_la_LIBADD = \
+  $(top_builddir)/src/util/libgnunetutil.la \
+  $(GN_LIBINTL) @EXT_LIBS@
+
+libgnunetnat_la_LDFLAGS = \
+  $(GN_LIB_LDFLAGS) $(WINFLAGS) \
+  -version-info 0:0:0
+
+check_PROGRAMS = \
+  test-nat
+
+TESTS = $(check_PROGRAMS)
+
+test_nat_SOURCES = \
+  test_nat.c
+
+test_nat_LDADD = \
+ $(top_builddir)/src/nat/libgnunetnat.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/nat/miniupnp/libminiupnp.a \
+ $(top_builddir)/src/nat/libnatpmp/libnatpmp.a
+

Added: gnunet/src/nat/libnatpmp/Makefile.am
===================================================================
--- gnunet/src/nat/libnatpmp/Makefile.am                                (rev 0)
+++ gnunet/src/nat/libnatpmp/Makefile.am        2009-10-25 09:44:36 UTC (rev 
9271)
@@ -0,0 +1,16 @@
+noinst_LIBRARIES = libnatpmp.a
+
+AM_CPPFLAGS = -DENABLE_STRNATPMPERR
+
+libnatpmp_a_SOURCES = \
+    getgateway.c \
+    natpmp.c
+
+noinst_HEADERS = \
+    declspec.h \
+    getgateway.h \
+    natpmp.h
+
+extra_DIST = \
+    README \
+    LICENSE

Added: gnunet/src/nat/libnatpmp/README
===================================================================
--- gnunet/src/nat/libnatpmp/README                             (rev 0)
+++ gnunet/src/nat/libnatpmp/README     2009-10-25 09:44:36 UTC (rev 9271)
@@ -0,0 +1,4 @@
+libnatpmp is written by Thomas Bernard.
+Its homepage is http://miniupnp.tuxfamily.org/libnatpmp.html
+This code is from the libnatpmp-20090310 snapshot
+

Added: gnunet/src/nat/libnatpmp/declspec.h
===================================================================
--- gnunet/src/nat/libnatpmp/declspec.h                         (rev 0)
+++ gnunet/src/nat/libnatpmp/declspec.h 2009-10-25 09:44:36 UTC (rev 9271)
@@ -0,0 +1,14 @@
+#ifndef __DECLSPEC_H__
+#define __DECLSPEC_H__
+
+#if defined(WIN32) && !defined(STATICLIB)
+#ifdef NATPMP_EXPORTS
+#define LIBSPEC __declspec(dllexport)
+#else
+#define LIBSPEC __declspec(dllimport)
+#endif
+#else
+#define LIBSPEC
+#endif
+
+#endif

Added: gnunet/src/nat/libnatpmp/getgateway.c
===================================================================
--- gnunet/src/nat/libnatpmp/getgateway.c                               (rev 0)
+++ gnunet/src/nat/libnatpmp/getgateway.c       2009-10-25 09:44:36 UTC (rev 
9271)
@@ -0,0 +1,530 @@
+/* $Id: getgateway.c,v 1.13 2009/03/10 10:15:31 nanard Exp $ */
+/* libnatpmp
+ * Copyright (c) 2007-2008, Thomas BERNARD <address@hidden>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#ifndef WIN32
+#include <netinet/in.h>
+#endif
+#include <sys/param.h>
+/* There is no portable method to get the default route gateway.
+ * So below are three differents functions implementing this.
+ * Parsing /proc/net/route is for linux.
+ * sysctl is the way to access such informations on BSD systems.
+ * Many systems should provide route information through raw PF_ROUTE
+ * sockets. */
+#ifdef __linux__
+#define USE_PROC_NET_ROUTE
+#undef USE_SOCKET_ROUTE
+#undef USE_SYSCTL_NET_ROUTE
+#endif
+
+#ifdef BSD
+#undef USE_PROC_NET_ROUTE
+#define USE_SOCKET_ROUTE
+#undef USE_SYSCTL_NET_ROUTE
+#endif
+
+#ifdef __APPLE__
+#undef USE_PROC_NET_ROUTE
+#undef USE_SOCKET_ROUTE
+#define USE_SYSCTL_NET_ROUTE
+#endif
+
+#if (defined(sun) && defined(__SVR4))
+#undef USE_PROC_NET_ROUTE
+#define USE_SOCKET_ROUTE
+#undef USE_SYSCTL_NET_ROUTE
+#endif
+
+#ifdef WIN32
+#undef USE_PROC_NET_ROUTE
+#undef USE_SOCKET_ROUTE
+#undef USE_SYSCTL_NET_ROUTE
+#define USE_WIN32_CODE
+#endif
+
+#ifdef USE_PROC_NET_ROUTE
+#include <arpa/inet.h>
+#endif
+#ifdef USE_SYSCTL_NET_ROUTE
+#include <stdlib.h>
+#include <sys/sysctl.h>
+#include <sys/socket.h>
+#include <net/route.h>
+#endif
+#ifdef USE_SOCKET_ROUTE
+#include <unistd.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <net/route.h>
+#endif
+#ifdef WIN32
+#include <unknwn.h>
+#include <winreg.h>
+#define MAX_KEY_LENGTH 255
+#define MAX_VALUE_LENGTH 16383
+#endif
+#include "getgateway.h"
+
+#ifndef WIN32
+#define SUCCESS (0)
+#define FAILED  (-1)
+#endif
+
+#ifdef USE_PROC_NET_ROUTE
+int
+getdefaultgateway (int *af, u_int8_t addr[16])
+{
+  unsigned int tmp;
+  u_int8_t d[16];
+  char buf[256];
+  int line = 0;
+  FILE *f;
+  char *p;
+  int i;
+  f = fopen ("/proc/net/route", "r");
+  if (!f)
+    return FAILED;
+  while (fgets (buf, sizeof (buf), f))
+    {
+      if (line > 0)
+        {
+          p = buf;
+          while (*p && !isspace (*p))
+            p++;
+          while (*p && isspace (*p))
+            p++;
+          for (i = 0; i < 16; i++)
+            {
+              if (sscanf (p, "%2X", &tmp) < 1)
+                d[i] = tmp;
+              else
+                break;
+            }
+
+          if (i == 8) /* IPv4 address on 8 hex chars */
+            {
+              /* Move the 32 bits address to the end of the array */
+              for (i = 4; i < 16; i++)
+                d[i] = 0;
+
+              for (i = 0; i < 4; i++)
+                {
+                  d[i+12] = d[i];
+                  d[i] = 0;
+                }
+              memcpy (addr, d, 16 * sizeof (u_int8_t));
+              *af = AF_INET;
+              fclose (f);
+              return SUCCESS;
+            }
+          else if (i == 16) /* IPv6 address on 16 hex chars,
+                             * or IPv4 address padded with 0 */
+            {
+              memcpy (addr, d, 16 * sizeof (u_int8_t));
+              /* Check at what byte the actual address starts */
+              for (i = 0; i <= 12; i++)
+                if (addr[i]) break;
+
+              if (i == 12)
+                {
+                  *af = AF_INET;
+                  fclose (f);
+                  return SUCCESS;
+                }
+              else if (i == 0)
+                {
+                  *af = AF_INET6;
+                  fclose (f);
+                  return SUCCESS;
+                }
+            }
+        }
+      line++;
+    }
+  /* default route not found ! */
+  if (f)
+    fclose (f);
+  return FAILED;
+}
+#endif /* #ifdef USE_PROC_NET_ROUTE */
+
+
+#ifdef USE_SYSCTL_NET_ROUTE
+
+#define ROUNDUP(a) \
+       ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
+
+int
+getdefaultgateway (int *af, u_int8_t addr[16])
+{
+#if 0
+  /* net.route.0.inet.dump.0.0 ? */
+  int mib[] = { CTL_NET, PF_ROUTE, 0, AF_INET,
+    NET_RT_DUMP, 0, 0           /*tableid */
+  };
+#endif
+  /* net.route.0.inet.flags.gateway */
+  int mib[] = { CTL_NET, PF_ROUTE, 0, AF_INET,
+    NET_RT_FLAGS, RTF_GATEWAY
+  };
+  size_t l;
+  char *buf, *p;
+  struct rt_msghdr *rt;
+  struct sockaddr *sa;
+  struct sockaddr *sa_tab[RTAX_MAX];
+  int i;
+  int r = FAILED;
+  if (sysctl (mib, sizeof (mib) / sizeof (int), 0, &l, 0, 0) < 0)
+    {
+      return FAILED;
+    }
+  if (l > 0)
+    {
+      buf = malloc (l);
+      if (sysctl (mib, sizeof (mib) / sizeof (int), buf, &l, 0, 0) < 0)
+        {
+          free (buf);
+          return FAILED;
+        }
+      for (p = buf; p < buf + l; p += rt->rtm_msglen)
+        {
+          rt = (struct rt_msghdr *) p;
+          sa = (struct sockaddr *) (rt + 1);
+          for (i = 0; i < RTAX_MAX; i++)
+            {
+              if (rt->rtm_addrs & (1 << i))
+                {
+                  sa_tab[i] = sa;
+                  sa =
+                    (struct sockaddr *) ((char *) sa + ROUNDUP (sa->sa_len));
+                }
+              else
+                {
+                  sa_tab[i] = NULL;
+                }
+            }
+          if (((rt->rtm_addrs & (RTA_DST | RTA_GATEWAY)) ==
+               (RTA_DST | RTA_GATEWAY))
+              && sa_tab[RTAX_DST]->sa_family == AF_INET
+              && sa_tab[RTAX_GATEWAY]->sa_family == AF_INET)
+            {
+              if (((struct sockaddr_in *) sa_tab[RTAX_DST])->sin_addr.
+                  s_addr == 0)
+                {
+                  *addr =
+                    ((struct sockaddr_in *) (sa_tab[RTAX_GATEWAY]))->sin_addr.
+                    s_addr;
+                  *af = AF_INET;
+                  r = SUCCESS;
+                }
+            }
+          else if (((rt->rtm_addrs & (RTA_DST | RTA_GATEWAY)) ==
+               (RTA_DST | RTA_GATEWAY))
+              && sa_tab[RTAX_DST]->sa_family == AF_INET6
+              && sa_tab[RTAX_GATEWAY]->sa_family == AF_INET6)
+            {
+              if (((struct sockaddr_in6 *) sa_tab[RTAX_DST])->sin6_addr == 0)
+                {
+                  *addr =
+                    ((struct sockaddr_in6 *) 
(sa_tab[RTAX_GATEWAY]))->sin6_addr;
+                  *af = AF_INET6;
+                  r = SUCCESS;
+                }
+            }
+        }
+      free (buf);
+    }
+  return r;
+}
+#endif /* #ifdef USE_SYSCTL_NET_ROUTE */
+
+
+#ifdef USE_SOCKET_ROUTE
+/* Thanks to Darren Kenny for this code */
+#define NEXTADDR(w, u) \
+        if (rtm_addrs & (w)) {\
+            l = sizeof(struct sockaddr); memmove(cp, &(u), l); cp += l;\
+        }
+
+#define rtm m_rtmsg.m_rtm
+
+struct
+{
+  struct rt_msghdr m_rtm;
+  char m_space[512];
+} m_rtmsg;
+
+int
+getdefaultgateway (int *af, u_int8_t addr[16])
+{
+  int s, seq, l, rtm_addrs, i;
+  pid_t pid;
+  struct sockaddr so_dst, so_mask;
+  char *cp = m_rtmsg.m_space;
+  struct sockaddr *gate = NULL, *sa;
+  struct rt_msghdr *msg_hdr;
+
+  pid = getpid ();
+  seq = 0;
+  rtm_addrs = RTA_DST | RTA_NETMASK;
+
+  memset (&so_dst, 0, sizeof (so_dst));
+  memset (&so_mask, 0, sizeof (so_mask));
+  memset (&rtm, 0, sizeof (struct rt_msghdr));
+
+  rtm.rtm_type = RTM_GET;
+  rtm.rtm_flags = RTF_UP | RTF_GATEWAY;
+  rtm.rtm_version = RTM_VERSION;
+  rtm.rtm_seq = ++seq;
+  rtm.rtm_addrs = rtm_addrs;
+
+  so_dst.sa_family = AF_INET;
+  so_mask.sa_family = AF_INET;
+
+  NEXTADDR (RTA_DST, so_dst);
+  NEXTADDR (RTA_NETMASK, so_mask);
+
+  rtm.rtm_msglen = l = cp - (char *) &m_rtmsg;
+
+  s = socket (PF_ROUTE, SOCK_RAW, 0);
+
+  if (write (s, (char *) &m_rtmsg, l) < 0)
+    {
+      close (s);
+      return FAILED;
+    }
+
+  do
+    {
+      l = read (s, (char *) &m_rtmsg, sizeof (m_rtmsg));
+    }
+  while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid));
+
+  close (s);
+
+  msg_hdr = &rtm;
+
+  cp = ((char *) (msg_hdr + 1));
+  if (msg_hdr->rtm_addrs)
+    {
+      for (i = 1; i; i <<= 1)
+        if (i & msg_hdr->rtm_addrs)
+          {
+            sa = (struct sockaddr *) cp;
+            if (i == RTA_GATEWAY)
+              gate = sa;
+
+            cp += sizeof (struct sockaddr);
+          }
+    }
+  else
+    {
+      return FAILED;
+    }
+
+
+  if (gate != NULL && ((struct sockaddr_in *) gate)->sa_family == AF_INET)
+    {
+      *addr = ((struct sockaddr_in *) gate)->sin_addr.s_addr;
+      *af = AF_INET;
+      return SUCCESS;
+    }
+  else if (gate != NULL && ((struct sockaddr_in *) gate)->sa_family == 
AF_INET6)
+    {
+      *addr = ((struct sockaddr_in6 *) gate)->sin6_addr.s6_addr;
+      *af = AF_INET6;
+      return SUCCESS;
+    }
+  else
+    {
+      return FAILED;
+    }
+}
+#endif /* #ifdef USE_SOCKET_ROUTE */
+
+#ifdef USE_WIN32_CODE
+int
+getdefaultgateway (int *af, u_int8_t addr[16])
+{
+  HKEY networkCardsKey;
+  HKEY networkCardKey;
+  HKEY interfacesKey;
+  HKEY interfaceKey;
+  DWORD i = 0;
+  DWORD numSubKeys = 0;
+  TCHAR keyName[MAX_KEY_LENGTH];
+  DWORD keyNameLength = MAX_KEY_LENGTH;
+  TCHAR keyValue[MAX_VALUE_LENGTH];
+  DWORD keyValueLength = MAX_VALUE_LENGTH;
+  DWORD keyValueType = REG_SZ;
+  TCHAR gatewayValue[MAX_VALUE_LENGTH];
+  DWORD gatewayValueLength = MAX_VALUE_LENGTH;
+  DWORD gatewayValueType = REG_MULTI_SZ;
+  int done = 0;
+
+  char networkCardsPath[] =
+    "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards";
+  char interfacesPath[] =
+    "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces";
+
+  // The windows registry lists its primary network devices in the following 
location:
+  // HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows 
NT\CurrentVersion\NetworkCards
+  // 
+  // Each network device has its own subfolder, named with an index, with 
various properties:
+  // -NetworkCards
+  //   -5
+  //     -Description = Broadcom 802.11n Network Adapter
+  //     -ServiceName = {E35A72F8-5065-4097-8DFE-C7790774EE4D}
+  //   -8
+  //     -Description = Marvell Yukon 88E8058 PCI-E Gigabit Ethernet Controller
+  //     -ServiceName = {86226414-5545-4335-A9D1-5BD7120119AD}
+  // 
+  // The above service name is the name of a subfolder within:
+  // 
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces
+  // 
+  // There may be more subfolders in this interfaces path than listed in the 
network cards path above:
+  // -Interfaces
+  //   -{3a539854-6a70-11db-887c-806e6f6e6963}
+  //     -DhcpIPAddress = 0.0.0.0
+  //     -[more]
+  //   -{E35A72F8-5065-4097-8DFE-C7790774EE4D}
+  //     -DhcpIPAddress = 10.0.1.4
+  //     -DhcpDefaultGateway = 10.0.1.1
+  //     -[more]
+  //   -{86226414-5545-4335-A9D1-5BD7120119AD}
+  //     -DhcpIpAddress = 10.0.1.5
+  //     -DhcpDefaultGateay = 10.0.1.1
+  //     -[more]
+  // 
+  // In order to extract this information, we enumerate each network card, and 
extract the ServiceName value.
+  // This is then used to open the interface subfolder, and attempt to extract 
a DhcpDefaultGateway value.
+  // Once one is found, we're done.
+  // 
+  // It may be possible to simply enumerate the interface folders until we 
find one with a DhcpDefaultGateway value.
+  // However, the technique used is the technique most cited on the web, and 
we assume it to be more correct.
+
+  if (ERROR_SUCCESS != RegOpenKeyEx (HKEY_LOCAL_MACHINE,        // Open 
registry key or predifined key 
+                                     networkCardsPath,  // Name of registry 
subkey to open
+                                     0, // Reserved - must be zero
+                                     KEY_READ,  // Mask - desired access rights
+                                     &networkCardsKey)) // Pointer to output 
key
+    {
+      // Unable to open network cards keys
+      return -1;
+    }
+
+  if (ERROR_SUCCESS != RegOpenKeyEx (HKEY_LOCAL_MACHINE,        // Open 
registry key or predefined key
+                                     interfacesPath,    // Name of registry 
subkey to open
+                                     0, // Reserved - must be zero
+                                     KEY_READ,  // Mask - desired access rights
+                                     &interfacesKey))   // Pointer to output 
key
+    {
+      // Unable to open interfaces key
+      RegCloseKey (networkCardsKey);
+      return -1;
+    }
+
+  // Figure out how many subfolders are within the NetworkCards folder
+  RegQueryInfoKey (networkCardsKey, NULL, NULL, NULL, &numSubKeys, NULL, NULL,
+                   NULL, NULL, NULL, NULL, NULL);
+
+  //printf( "Number of subkeys: %u\n", (unsigned int)numSubKeys);
+
+  // Enumrate through each subfolder within the NetworkCards folder
+  for (i = 0; i < numSubKeys && !done; i++)
+    {
+      keyNameLength = MAX_KEY_LENGTH;
+      if (ERROR_SUCCESS == RegEnumKeyEx (networkCardsKey,       // Open 
registry key
+                                         i,     // Index of subkey to retrieve
+                                         keyName,       // Buffer that 
receives the name of the subkey
+                                         &keyNameLength,        // Variable 
that receives the size of the above buffer
+                                         NULL,  // Reserved - must be NULL
+                                         NULL,  // Buffer that receives the 
class string
+                                         NULL,  // Variable that receives the 
size of the above buffer
+                                         NULL)) // Variable that receives the 
last write time of subkey
+        {
+          if (RegOpenKeyEx
+              (networkCardsKey, keyName, 0, KEY_READ,
+               &networkCardKey) == ERROR_SUCCESS)
+            {
+              keyValueLength = MAX_VALUE_LENGTH;
+              if (ERROR_SUCCESS == RegQueryValueEx (networkCardKey,     // 
Open registry key
+                                                    "ServiceName",      // 
Name of key to query
+                                                    NULL,       // Reserved - 
must be NULL
+                                                    &keyValueType,      // 
Receives value type
+                                                    keyValue,   // Receives 
value
+                                                    &keyValueLength))   // 
Receives value length in bytes
+                {
+                  //printf("keyValue: %s\n", keyValue);
+
+                  if (RegOpenKeyEx
+                      (interfacesKey, keyValue, 0, KEY_READ,
+                       &interfaceKey) == ERROR_SUCCESS)
+                    {
+                      gatewayValueLength = MAX_VALUE_LENGTH;
+                      if (ERROR_SUCCESS == RegQueryValueEx (interfaceKey,      
 // Open registry key
+                                                            
"DhcpDefaultGateway",       // Name of key to query
+                                                            NULL,       // 
Reserved - must be NULL
+                                                            &gatewayValueType, 
 // Receives value type
+                                                            gatewayValue,      
 // Receives value
+                                                            
&gatewayValueLength))       // Receives value length in bytes
+                        {
+                          // Check to make sure it's a string
+                          if (gatewayValueType == REG_MULTI_SZ
+                              || gatewayValueType == REG_SZ)
+                            {
+                              //printf("gatewayValue: %s\n", gatewayValue);
+                              done = 1;
+                            }
+                        }
+                      else if (ERROR_SUCCESS == RegQueryValueEx (interfaceKey, 
 // Open registry key
+                                                                 
"DefaultGateway",      // Name of key to query
+                                                                 NULL,  // 
Reserved - must be NULL
+                                                                 
&gatewayValueType,     // Receives value type
+                                                                 gatewayValue, 
 // Receives value
+                                                                 
&gatewayValueLength))  // Receives value length in bytes
+                        {
+                          // Check to make sure it's a string
+                          if (gatewayValueType == REG_MULTI_SZ
+                              || gatewayValueType == REG_SZ)
+                            {
+                              //printf("gatewayValue: %s\n", gatewayValue);
+                              done = 1;
+                            }
+                        }
+                      RegCloseKey (interfaceKey);
+                    }
+                }
+              RegCloseKey (networkCardKey);
+            }
+        }
+    }
+
+  RegCloseKey (interfacesKey);
+  RegCloseKey (networkCardsKey);
+
+  if (done)
+    {
+      *addr = inet_addr (gatewayValue);
+      return 0;
+    }
+
+  return -1;
+}
+#endif /* #ifdef USE_WIN32_CODE */

Added: gnunet/src/nat/libnatpmp/getgateway.h
===================================================================
--- gnunet/src/nat/libnatpmp/getgateway.h                               (rev 0)
+++ gnunet/src/nat/libnatpmp/getgateway.h       2009-10-25 09:44:36 UTC (rev 
9271)
@@ -0,0 +1,32 @@
+/* $Id: getgateway.h,v 1.3 2008/07/02 22:33:06 nanard Exp $ */
+/* libnatpmp
+ * Copyright (c) 2007, Thomas BERNARD <address@hidden>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#ifndef __GETGATEWAY_H__
+#define __GETGATEWAY_H__
+
+#ifdef WIN32
+#include <stdint.h>
+#define in_addr_t uint32_t
+#endif
+#include "declspec.h"
+
+/* getdefaultgateway() :
+ * addr must point to an array of at least 16 u_int8 elements
+ * return value :
+ *    0 : success
+ *   -1 : failure    */
+LIBSPEC int getdefaultgateway (int *af, u_int8_t addr[16]);
+
+#endif

Added: gnunet/src/nat/libnatpmp/natpmp.c
===================================================================
--- gnunet/src/nat/libnatpmp/natpmp.c                           (rev 0)
+++ gnunet/src/nat/libnatpmp/natpmp.c   2009-10-25 09:44:36 UTC (rev 9271)
@@ -0,0 +1,405 @@
+/* $Id: natpmp.c,v 1.8 2008/07/02 22:33:06 nanard Exp $ */
+/* libnatpmp
+ * Copyright (c) 2007-2008, Thomas BERNARD <address@hidden>
+ * http://miniupnp.free.fr/libnatpmp.html
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#include <string.h>
+#include <time.h>
+#include <sys/time.h>
+#ifdef WIN32
+#include <winsock2.h>
+#include <Ws2tcpip.h>
+#include <io.h>
+#define EWOULDBLOCK WSAEWOULDBLOCK
+#define ECONNREFUSED WSAECONNREFUSED
+#else
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#define closesocket close
+#endif
+#include "natpmp.h"
+#include "getgateway.h"
+
+int
+initnatpmp (natpmp_t * p)
+{
+#ifdef WIN32
+  u_long ioctlArg = 1;
+#else
+  int flags;
+#endif
+  int domain = AF_INET;
+  int gw_domain;
+  struct sockaddr_in addr;
+  struct sockaddr_in6 addr6;
+
+  if (!p)
+    return NATPMP_ERR_INVALIDARGS;
+
+  if (p->addr)
+    domain = (p->addr->sa_family == AF_INET) ? PF_INET : PF_INET6;
+
+  memset (p, 0, sizeof (natpmp_t));
+  p->s = socket (domain, SOCK_DGRAM, 0);
+  if (p->s < 0)
+    return NATPMP_ERR_SOCKETERROR;
+  /* If addr has been set, use it, else get the default from connect() */
+  if (p->addr && bind (p->s, p->addr, p->addrlen) < 0)
+    return NATPMP_ERR_BINDERROR;
+#ifdef WIN32
+  if (ioctlsocket (p->s, FIONBIO, &ioctlArg) == SOCKET_ERROR)
+    return NATPMP_ERR_FCNTLERROR;
+#else
+  if ((flags = fcntl (p->s, F_GETFL, 0)) < 0)
+    return NATPMP_ERR_FCNTLERROR;
+  if (fcntl (p->s, F_SETFL, flags | O_NONBLOCK) < 0)
+    return NATPMP_ERR_FCNTLERROR;
+#endif
+
+  if (getdefaultgateway (&gw_domain, p->gateway) < 0)
+    return NATPMP_ERR_CANNOTGETGATEWAY;
+
+  if (domain != gw_domain)
+    return NATPMP_ERR_ADDRERROR;
+
+  if (domain == AF_INET)
+    {
+      memset (&addr, 0, sizeof (addr));
+      addr.sin_family = AF_INET;
+      addr.sin_port = htons (NATPMP_PORT);
+      memcpy (&addr.sin_addr.s_addr, p->gateway, 4 * sizeof (u_int8_t));
+#ifdef HAVE_SOCKADDR_IN_SIN_LEN
+      addr.sin_len = sizeof (addr);
+#endif
+      if (connect (p->s, (struct sockaddr *) &addr, sizeof (addr)) < 0)
+        return NATPMP_ERR_CONNECTERR;
+    }
+  else
+    {
+      memset (&addr6, 0, sizeof (addr6));
+      addr6.sin6_family = AF_INET6;
+      addr6.sin6_port = htons (NATPMP_PORT);
+      memcpy (addr6.sin6_addr.s6_addr, p->gateway, 16 * sizeof (u_int8_t));
+#ifdef HAVE_SOCKADDR_IN_SIN_LEN
+      addr6.sin6_len = sizeof (addr6);
+#endif
+      if (connect (p->s, (struct sockaddr *) &addr6, sizeof (addr6)) < 0)
+        return NATPMP_ERR_CONNECTERR;
+    }
+  
+  return 0;
+}
+
+int
+closenatpmp (natpmp_t * p)
+{
+  if (!p)
+    return NATPMP_ERR_INVALIDARGS;
+  if (closesocket (p->s) < 0)
+    return NATPMP_ERR_CLOSEERR;
+  return 0;
+}
+
+static int
+sendpendingrequest (natpmp_t * p)
+{
+  int r;
+/*     struct sockaddr_in addr;*/
+  if (!p)
+    return NATPMP_ERR_INVALIDARGS;
+/*     memset(&addr, 0, sizeof(addr));
+       addr.sin_family = AF_INET;
+       addr.sin_port = htons(NATPMP_PORT);
+       addr.sin_addr.s_addr = p->gateway;
+       r = (int)sendto(p->s, p->pending_request, p->pending_request_len, 0,
+                          (struct sockaddr *)&addr, sizeof(addr));*/
+  r = (int) send (p->s, p->pending_request, p->pending_request_len, 0);
+  return (r < 0) ? NATPMP_ERR_SENDERR : r;
+}
+
+static int
+sendnatpmprequest (natpmp_t * p)
+{
+  int n;
+  if (!p)
+    return NATPMP_ERR_INVALIDARGS;
+  /* TODO : check if no request is allready pending */
+  p->has_pending_request = 1;
+  p->try_number = 1;
+  n = sendpendingrequest (p);
+  gettimeofday (&p->retry_time, NULL);  // check errors !
+  p->retry_time.tv_usec += 250000;      /* add 250ms */
+  if (p->retry_time.tv_usec >= 1000000)
+    {
+      p->retry_time.tv_usec -= 1000000;
+      p->retry_time.tv_sec++;
+    }
+  return n;
+}
+
+int
+getnatpmprequesttimeout (natpmp_t * p, struct timeval *timeout)
+{
+  struct timeval now;
+  if (!p || !timeout)
+    return NATPMP_ERR_INVALIDARGS;
+  if (!p->has_pending_request)
+    return NATPMP_ERR_NOPENDINGREQ;
+  if (gettimeofday (&now, NULL) < 0)
+    return NATPMP_ERR_GETTIMEOFDAYERR;
+  timeout->tv_sec = p->retry_time.tv_sec - now.tv_sec;
+  timeout->tv_usec = p->retry_time.tv_usec - now.tv_usec;
+  if (timeout->tv_usec < 0)
+    {
+      timeout->tv_usec += 1000000;
+      timeout->tv_sec--;
+    }
+  return 0;
+}
+
+int
+sendpublicaddressrequest (natpmp_t * p)
+{
+  if (!p)
+    return NATPMP_ERR_INVALIDARGS;
+  //static const unsigned char request[] = { 0, 0 };
+  p->pending_request[0] = 0;
+  p->pending_request[1] = 0;
+  p->pending_request_len = 2;
+  // TODO: return 0 instead of sizeof(request) ??
+  return sendnatpmprequest (p);
+}
+
+int
+sendnewportmappingrequest (natpmp_t * p, int protocol,
+                           uint16_t privateport, uint16_t publicport,
+                           uint32_t lifetime)
+{
+  if (!p
+      || (protocol != NATPMP_PROTOCOL_TCP && protocol != NATPMP_PROTOCOL_UDP))
+    return NATPMP_ERR_INVALIDARGS;
+  p->pending_request[0] = 0;
+  p->pending_request[1] = protocol;
+  p->pending_request[2] = 0;
+  p->pending_request[3] = 0;
+  *((uint16_t *) (p->pending_request + 4)) = htons (privateport);
+  *((uint16_t *) (p->pending_request + 6)) = htons (publicport);
+  *((uint32_t *) (p->pending_request + 8)) = htonl (lifetime);
+  p->pending_request_len = 12;
+  return sendnatpmprequest (p);
+}
+
+static int
+readnatpmpresponse (natpmp_t * p, natpmpresp_t * response)
+{
+  unsigned char buf[16];
+  struct sockaddr_storage addr;
+  socklen_t addrlen = sizeof (addr);
+  int n;
+  if (!p)
+    return NATPMP_ERR_INVALIDARGS;
+  n = recvfrom (p->s, buf, sizeof (buf), 0,
+                (struct sockaddr *) &addr, &addrlen);
+  if (n < 0)
+    switch (errno)
+      {
+        /*case EAGAIN: */
+      case EWOULDBLOCK:
+        n = NATPMP_TRYAGAIN;
+        break;
+      case ECONNREFUSED:
+        n = NATPMP_ERR_NOGATEWAYSUPPORT;
+        break;
+      default:
+        n = NATPMP_ERR_RECVFROM;
+      }
+  /* check that addr is correct (= gateway) */
+  else if (addr.ss_family == AF_INET && memcmp (&((struct sockaddr_in *) 
&addr)->sin_addr.s_addr, p->gateway, 4 * sizeof (u_int8_t)) == 0)
+    n = NATPMP_ERR_WRONGPACKETSOURCE;
+  else if (addr.ss_family == AF_INET6 && memcmp (((struct sockaddr_in6 *) 
&addr)->sin6_addr.s6_addr, p->gateway, 16 * sizeof (u_int8_t)) == 0)
+    n = NATPMP_ERR_WRONGPACKETSOURCE;
+  else
+    {
+      response->resultcode = ntohs (*((uint16_t *) (buf + 2)));
+      response->epoch = ntohl (*((uint32_t *) (buf + 4)));
+      if (buf[0] != 0)
+        n = NATPMP_ERR_UNSUPPORTEDVERSION;
+      else if (buf[1] < 128 || buf[1] > 130)
+        n = NATPMP_ERR_UNSUPPORTEDOPCODE;
+      else if (response->resultcode != 0)
+        {
+          switch (response->resultcode)
+            {
+            case 1:
+              n = NATPMP_ERR_UNSUPPORTEDVERSION;
+              break;
+            case 2:
+              n = NATPMP_ERR_NOTAUTHORIZED;
+              break;
+            case 3:
+              n = NATPMP_ERR_NETWORKFAILURE;
+              break;
+            case 4:
+              n = NATPMP_ERR_OUTOFRESOURCES;
+              break;
+            case 5:
+              n = NATPMP_ERR_UNSUPPORTEDOPCODE;
+              break;
+            default:
+              n = NATPMP_ERR_UNDEFINEDERROR;
+            }
+        }
+      else
+        {
+          response->type = buf[1] & 0x7f;
+          if (buf[1] == 128)
+            //response->publicaddress.addr = *((uint32_t *)(buf + 8));
+            response->pnu.publicaddress.addr.s_addr =
+              *((uint32_t *) (buf + 8));
+          else
+            {
+              response->pnu.newportmapping.privateport =
+                ntohs (*((uint16_t *) (buf + 8)));
+              response->pnu.newportmapping.mappedpublicport =
+                ntohs (*((uint16_t *) (buf + 10)));
+              response->pnu.newportmapping.lifetime =
+                ntohl (*((uint32_t *) (buf + 12)));
+            }
+          n = 0;
+        }
+    }
+  return n;
+}
+
+int
+readnatpmpresponseorretry (natpmp_t * p, natpmpresp_t * response)
+{
+  int n;
+  if (!p || !response)
+    return NATPMP_ERR_INVALIDARGS;
+  if (!p->has_pending_request)
+    return NATPMP_ERR_NOPENDINGREQ;
+  n = readnatpmpresponse (p, response);
+  if (n < 0)
+    {
+      if (n == NATPMP_TRYAGAIN)
+        {
+          struct timeval now;
+          gettimeofday (&now, NULL);    // check errors !
+          if (timercmp (&now, &p->retry_time, >=))
+            {
+              int delay, r;
+              if (p->try_number >= 9)
+                {
+                  return NATPMP_ERR_NOGATEWAYSUPPORT;
+                }
+              /*printf("retry! %d\n", p->try_number); */
+              delay = 250 * (1 << p->try_number);       // ms
+              /*for(i=0; i<p->try_number; i++)
+                 delay += delay; */
+              p->retry_time.tv_sec += (delay / 1000);
+              p->retry_time.tv_usec += (delay % 1000) * 1000;
+              if (p->retry_time.tv_usec >= 1000000)
+                {
+                  p->retry_time.tv_usec -= 1000000;
+                  p->retry_time.tv_sec++;
+                }
+              p->try_number++;
+              r = sendpendingrequest (p);
+              if (r < 0)
+                return r;
+            }
+        }
+    }
+  else
+    {
+      p->has_pending_request = 0;
+    }
+  return n;
+}
+
+#ifdef ENABLE_STRNATPMPERR
+const char *
+strnatpmperr (int r)
+{
+  const char *s;
+  switch (r)
+    {
+    case NATPMP_ERR_INVALIDARGS:
+      s = "invalid arguments";
+      break;
+    case NATPMP_ERR_SOCKETERROR:
+      s = "socket() failed";
+      break;
+    case NATPMP_ERR_CANNOTGETGATEWAY:
+      s = "cannot get default gateway ip address";
+      break;
+    case NATPMP_ERR_CLOSEERR:
+#ifdef WIN32
+      s = "closesocket() failed";
+#else
+      s = "close() failed";
+#endif
+      break;
+    case NATPMP_ERR_RECVFROM:
+      s = "recvfrom() failed";
+      break;
+    case NATPMP_ERR_NOPENDINGREQ:
+      s = "no pending request";
+      break;
+    case NATPMP_ERR_NOGATEWAYSUPPORT:
+      s = "the gateway does not support nat-pmp";
+      break;
+    case NATPMP_ERR_CONNECTERR:
+      s = "connect() failed";
+      break;
+    case NATPMP_ERR_WRONGPACKETSOURCE:
+      s = "packet not received from the default gateway";
+      break;
+    case NATPMP_ERR_SENDERR:
+      s = "send() failed";
+      break;
+    case NATPMP_ERR_FCNTLERROR:
+      s = "fcntl() failed";
+      break;
+    case NATPMP_ERR_GETTIMEOFDAYERR:
+      s = "gettimeofday() failed";
+      break;
+    case NATPMP_ERR_UNSUPPORTEDVERSION:
+      s = "unsupported nat-pmp version error from server";
+      break;
+    case NATPMP_ERR_UNSUPPORTEDOPCODE:
+      s = "unsupported nat-pmp opcode error from server";
+      break;
+    case NATPMP_ERR_UNDEFINEDERROR:
+      s = "undefined nat-pmp server error";
+      break;
+    case NATPMP_ERR_NOTAUTHORIZED:
+      s = "not authorized";
+      break;
+    case NATPMP_ERR_NETWORKFAILURE:
+      s = "network failure";
+      break;
+    case NATPMP_ERR_OUTOFRESOURCES:
+      s = "nat-pmp server out of resources";
+      break;
+    default:
+      s = "Unknown libnatpmp error";
+    }
+  return s;
+}
+#endif

Added: gnunet/src/nat/libnatpmp/natpmp.h
===================================================================
--- gnunet/src/nat/libnatpmp/natpmp.h                           (rev 0)
+++ gnunet/src/nat/libnatpmp/natpmp.h   2009-10-25 09:44:36 UTC (rev 9271)
@@ -0,0 +1,200 @@
+/* $Id: natpmp.h,v 1.11 2009/02/27 22:38:05 nanard Exp $ */
+/* libnatpmp
+ * Copyright (c) 2007-2008, Thomas BERNARD <address@hidden>
+ * http://miniupnp.free.fr/libnatpmp.html
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#ifndef __NATPMP_H__
+#define __NATPMP_H__
+
+/* NAT-PMP Port as defined by the NAT-PMP draft */
+#define NATPMP_PORT (5351)
+
+#include <time.h>
+#include <sys/time.h>
+#ifdef WIN32
+#include <winsock2.h>
+#include <stdint.h>
+#define in_addr_t uint32_t
+#include "declspec.h"
+#else
+#define LIBSPEC
+#include <netinet/in.h>
+#include <sys/socket.h>
+#endif
+
+typedef struct
+{
+  int s;                        /* socket */
+  struct sockaddr *addr;
+  socklen_t addrlen;
+  u_int8_t gateway[16];       /* default gateway (IPv4 or IPv6) */
+  int has_pending_request;
+  unsigned char pending_request[12];
+  int pending_request_len;
+  int try_number;
+  struct timeval retry_time;
+} natpmp_t;
+
+typedef struct
+{
+  uint16_t type;                /* NATPMP_RESPTYPE_* */
+  uint16_t resultcode;          /* NAT-PMP response code */
+  uint32_t epoch;               /* Seconds since start of epoch */
+  union
+  {
+    struct
+    {
+      //in_addr_t addr;
+      struct in_addr addr;
+    } publicaddress;
+    struct
+    {
+      uint16_t privateport;
+      uint16_t mappedpublicport;
+      uint32_t lifetime;
+    } newportmapping;
+  } pnu;
+} natpmpresp_t;
+
+/* possible values for type field of natpmpresp_t */
+#define NATPMP_RESPTYPE_PUBLICADDRESS (0)
+#define NATPMP_RESPTYPE_UDPPORTMAPPING (1)
+#define NATPMP_RESPTYPE_TCPPORTMAPPING (2)
+
+/* Values to pass to sendnewportmappingrequest() */
+#define NATPMP_PROTOCOL_UDP (1)
+#define NATPMP_PROTOCOL_TCP (2)
+
+/* return values */
+/* NATPMP_ERR_INVALIDARGS : invalid arguments passed to the function */
+#define NATPMP_ERR_INVALIDARGS (-1)
+/* NATPMP_ERR_SOCKETERROR : socket() failed. check errno for details */
+#define NATPMP_ERR_SOCKETERROR (-2)
+/* NATPMP_ERR_CANNOTGETGATEWAY : can't get default gateway IP */
+#define NATPMP_ERR_CANNOTGETGATEWAY (-3)
+/* NATPMP_ERR_CLOSEERR : close() failed. check errno for details */
+#define NATPMP_ERR_CLOSEERR (-4)
+/* NATPMP_ERR_RECVFROM : recvfrom() failed. check errno for details */
+#define NATPMP_ERR_RECVFROM (-5)
+/* NATPMP_ERR_NOPENDINGREQ : readnatpmpresponseorretry() called while
+ * no NAT-PMP request was pending */
+#define NATPMP_ERR_NOPENDINGREQ (-6)
+/* NATPMP_ERR_NOGATEWAYSUPPORT : the gateway does not support NAT-PMP */
+#define NATPMP_ERR_NOGATEWAYSUPPORT (-7)
+/* NATPMP_ERR_CONNECTERR : connect() failed. check errno for details */
+#define NATPMP_ERR_CONNECTERR (-8)
+/* NATPMP_ERR_WRONGPACKETSOURCE : packet not received from the network gateway 
*/
+#define NATPMP_ERR_WRONGPACKETSOURCE (-9)
+/* NATPMP_ERR_SENDERR : send() failed. check errno for details */
+#define NATPMP_ERR_SENDERR (-10)
+/* NATPMP_ERR_FCNTLERROR : fcntl() failed. check errno for details */
+#define NATPMP_ERR_FCNTLERROR (-11)
+/* NATPMP_ERR_GETTIMEOFDAYERR : gettimeofday() failed. check errno for details 
*/
+#define NATPMP_ERR_GETTIMEOFDAYERR (-12)
+/* NATPMP_ERR_BINDERROR : bind() failed. check errno for details */
+#define NATPMP_ERR_BINDERROR (-13)
+/* NATPMP_ERR_ADDRERROR : gateway does not use the same inet protocol as the 
passed address */
+#define NATPMP_ERR_ADDRERROR (-14)
+
+/* */
+#define NATPMP_ERR_UNSUPPORTEDVERSION (-15)
+#define NATPMP_ERR_UNSUPPORTEDOPCODE (-16)
+
+/* Errors from the server : */
+#define NATPMP_ERR_UNDEFINEDERROR (-49)
+#define NATPMP_ERR_NOTAUTHORIZED (-51)
+#define NATPMP_ERR_NETWORKFAILURE (-52)
+#define NATPMP_ERR_OUTOFRESOURCES (-53)
+
+/* NATPMP_TRYAGAIN : no data available for the moment. try again later */
+#define NATPMP_TRYAGAIN (-100)
+
+/* initnatpmp()
+ * initialize a natpmp_t object
+ * Return values :
+ * 0 = OK
+ * NATPMP_ERR_INVALIDARGS
+ * NATPMP_ERR_SOCKETERROR
+ * NATPMP_ERR_FCNTLERROR
+ * NATPMP_ERR_CANNOTGETGATEWAY
+ * NATPMP_ERR_CONNECTERR */
+LIBSPEC int initnatpmp (natpmp_t * p);
+
+/* closenatpmp()
+ * close resources associated with a natpmp_t object
+ * Return values :
+ * 0 = OK
+ * NATPMP_ERR_INVALIDARGS
+ * NATPMP_ERR_CLOSEERR */
+LIBSPEC int closenatpmp (natpmp_t * p);
+
+/* sendpublicaddressrequest()
+ * send a public address NAT-PMP request to the network gateway
+ * Return values :
+ * 2 = OK (size of the request)
+ * NATPMP_ERR_INVALIDARGS
+ * NATPMP_ERR_SENDERR */
+LIBSPEC int sendpublicaddressrequest (natpmp_t * p);
+
+/* sendnewportmappingrequest()
+ * send a new port mapping NAT-PMP request to the network gateway
+ * Arguments :
+ * protocol is either NATPMP_PROTOCOL_TCP or NATPMP_PROTOCOL_UDP,
+ * lifetime is in seconds.
+ * To remove a port mapping, set lifetime to zero.
+ * To remove all port mappings to the host, set lifetime and both ports
+ * to zero.
+ * Return values :
+ * 12 = OK (size of the request)
+ * NATPMP_ERR_INVALIDARGS
+ * NATPMP_ERR_SENDERR */
+LIBSPEC int sendnewportmappingrequest (natpmp_t * p, int protocol,
+                                       uint16_t privateport,
+                                       uint16_t publicport,
+                                       uint32_t lifetime);
+
+/* getnatpmprequesttimeout()
+ * fills the timeval structure with the timeout duration of the
+ * currently pending NAT-PMP request.
+ * Return values :
+ * 0 = OK
+ * NATPMP_ERR_INVALIDARGS
+ * NATPMP_ERR_GETTIMEOFDAYERR
+ * NATPMP_ERR_NOPENDINGREQ */
+LIBSPEC int getnatpmprequesttimeout (natpmp_t * p, struct timeval *timeout);
+
+/* readnatpmpresponseorretry()
+ * fills the natpmpresp_t structure if possible
+ * Return values :
+ * 0 = OK
+ * NATPMP_TRYAGAIN
+ * NATPMP_ERR_INVALIDARGS
+ * NATPMP_ERR_NOPENDINGREQ
+ * NATPMP_ERR_NOGATEWAYSUPPORT
+ * NATPMP_ERR_RECVFROM
+ * NATPMP_ERR_WRONGPACKETSOURCE
+ * NATPMP_ERR_UNSUPPORTEDVERSION
+ * NATPMP_ERR_UNSUPPORTEDOPCODE
+ * NATPMP_ERR_NOTAUTHORIZED
+ * NATPMP_ERR_NETWORKFAILURE
+ * NATPMP_ERR_OUTOFRESOURCES
+ * NATPMP_ERR_UNSUPPORTEDOPCODE
+ * NATPMP_ERR_UNDEFINEDERROR */
+LIBSPEC int readnatpmpresponseorretry (natpmp_t * p, natpmpresp_t * response);
+
+#ifdef ENABLE_STRNATPMPERR
+LIBSPEC const char *strnatpmperr (int t);
+#endif
+
+#endif

Added: gnunet/src/nat/miniupnp/Makefile.am
===================================================================
--- gnunet/src/nat/miniupnp/Makefile.am                         (rev 0)
+++ gnunet/src/nat/miniupnp/Makefile.am 2009-10-25 09:44:36 UTC (rev 9271)
@@ -0,0 +1,31 @@
+noinst_LIBRARIES = libminiupnp.a
+
+AM_CPPFLAGS = -DNDEBUG
+
+libminiupnp_a_SOURCES = \
+    igd_desc_parse.c \
+    minisoap.c \
+    minissdpc.c \
+    miniupnpc.c \
+    miniwget.c \
+    minixml.c \
+    upnpcommands.c \
+    upnpreplyparse.c
+
+noinst_HEADERS = \
+    bsdqueue.h \
+    codelength.h \
+    declspec.h \
+    igd_desc_parse.h \
+    minisoap.h \
+    minissdpc.h \
+    miniupnpc.h \
+    miniupnpcstrings.h \
+    miniwget.h \
+    minixml.h \
+    upnpcommands.h \
+    upnpreplyparse.h
+
+extra_DIST = \
+    README \
+    LICENSE

Added: gnunet/src/nat/miniupnp/README
===================================================================
--- gnunet/src/nat/miniupnp/README                              (rev 0)
+++ gnunet/src/nat/miniupnp/README      2009-10-25 09:44:36 UTC (rev 9271)
@@ -0,0 +1,3 @@
+MiniUPnP is written by Thomas Bernard.
+Its homepage is http://miniupnp.free.fr/
+This is from miniupnpc-1.3.tar.gz

Added: gnunet/src/nat/miniupnp/bsdqueue.h
===================================================================
--- gnunet/src/nat/miniupnp/bsdqueue.h                          (rev 0)
+++ gnunet/src/nat/miniupnp/bsdqueue.h  2009-10-25 09:44:36 UTC (rev 9271)
@@ -0,0 +1,531 @@
+/*     $OpenBSD: queue.h,v 1.31 2005/11/25 08:06:25 otto Exp $ */
+/*     $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $       */
+
+/*
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)queue.h     8.5 (Berkeley) 8/20/94
+ */
+
+#ifndef        _SYS_QUEUE_H_
+#define        _SYS_QUEUE_H_
+
+/*
+ * This file defines five types of data structures: singly-linked lists, 
+ * lists, simple queues, tail queues, and circular queues.
+ *
+ *
+ * A singly-linked list is headed by a single forward pointer. The elements
+ * are singly linked for minimum space and pointer manipulation overhead at
+ * the expense of O(n) removal for arbitrary elements. New elements can be
+ * added to the list after an existing element or at the head of the list.
+ * Elements being removed from the head of the list should use the explicit
+ * macro for this purpose for optimum efficiency. A singly-linked list may
+ * only be traversed in the forward direction.  Singly-linked lists are ideal
+ * for applications with large datasets and few or no removals or for
+ * implementing a LIFO queue.
+ *
+ * A list is headed by a single forward pointer (or an array of forward
+ * pointers for a hash table header). The elements are doubly linked
+ * so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before
+ * or after an existing element or at the head of the list. A list
+ * may only be traversed in the forward direction.
+ *
+ * A simple queue is headed by a pair of pointers, one the head of the
+ * list and the other to the tail of the list. The elements are singly
+ * linked to save space, so elements can only be removed from the
+ * head of the list. New elements can be added to the list before or after
+ * an existing element, at the head of the list, or at the end of the
+ * list. A simple queue may only be traversed in the forward direction.
+ *
+ * A tail queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or
+ * after an existing element, at the head of the list, or at the end of
+ * the list. A tail queue may be traversed in either direction.
+ *
+ * A circle queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or after
+ * an existing element, at the head of the list, or at the end of the list.
+ * A circle queue may be traversed in either direction, but has a more
+ * complex end of list detection.
+ *
+ * For details on the use of these macros, see the queue(3) manual page.
+ */
+
+#ifdef QUEUE_MACRO_DEBUG
+#define _Q_INVALIDATE(a) (a) = ((void *)-1)
+#else
+#define _Q_INVALIDATE(a)
+#endif
+
+/*
+ * Singly-linked List definitions.
+ */
+#define SLIST_HEAD(name, type)                                         \
+struct name {                                                          \
+       struct type *slh_first; /* first element */                     \
+}
+
+#define        SLIST_HEAD_INITIALIZER(head)                                    
\
+       { NULL }
+
+#ifdef SLIST_ENTRY
+#undef SLIST_ENTRY
+#endif
+
+#define SLIST_ENTRY(type)                                              \
+struct {                                                               \
+       struct type *sle_next;  /* next element */                      \
+}
+
+/*
+ * Singly-linked List access methods.
+ */
+#define        SLIST_FIRST(head)       ((head)->slh_first)
+#define        SLIST_END(head)         NULL
+#define        SLIST_EMPTY(head)       (SLIST_FIRST(head) == SLIST_END(head))
+#define        SLIST_NEXT(elm, field)  ((elm)->field.sle_next)
+
+#define        SLIST_FOREACH(var, head, field)                                 
\
+       for((var) = SLIST_FIRST(head);                                  \
+           (var) != SLIST_END(head);                                   \
+           (var) = SLIST_NEXT(var, field))
+
+#define        SLIST_FOREACH_PREVPTR(var, varp, head, field)                   
\
+       for ((varp) = &SLIST_FIRST((head));                             \
+           ((var) = *(varp)) != SLIST_END(head);                       \
+           (varp) = &SLIST_NEXT((var), field))
+
+/*
+ * Singly-linked List functions.
+ */
+#define        SLIST_INIT(head) {                                              
\
+       SLIST_FIRST(head) = SLIST_END(head);                            \
+}
+
+#define        SLIST_INSERT_AFTER(slistelm, elm, field) do {                   
\
+       (elm)->field.sle_next = (slistelm)->field.sle_next;             \
+       (slistelm)->field.sle_next = (elm);                             \
+} while (0)
+
+#define        SLIST_INSERT_HEAD(head, elm, field) do {                        
\
+       (elm)->field.sle_next = (head)->slh_first;                      \
+       (head)->slh_first = (elm);                                      \
+} while (0)
+
+#define        SLIST_REMOVE_NEXT(head, elm, field) do {                        
\
+       (elm)->field.sle_next = (elm)->field.sle_next->field.sle_next;  \
+} while (0)
+
+#define        SLIST_REMOVE_HEAD(head, field) do {                             
\
+       (head)->slh_first = (head)->slh_first->field.sle_next;          \
+} while (0)
+
+#define SLIST_REMOVE(head, elm, type, field) do {                      \
+       if ((head)->slh_first == (elm)) {                               \
+               SLIST_REMOVE_HEAD((head), field);                       \
+       } else {                                                        \
+               struct type *curelm = (head)->slh_first;                \
+                                                                       \
+               while (curelm->field.sle_next != (elm))                 \
+                       curelm = curelm->field.sle_next;                \
+               curelm->field.sle_next =                                \
+                   curelm->field.sle_next->field.sle_next;             \
+               _Q_INVALIDATE((elm)->field.sle_next);                   \
+       }                                                               \
+} while (0)
+
+/*
+ * List definitions.
+ */
+#define LIST_HEAD(name, type)                                          \
+struct name {                                                          \
+       struct type *lh_first;  /* first element */                     \
+}
+
+#define LIST_HEAD_INITIALIZER(head)                                    \
+       { NULL }
+
+#define LIST_ENTRY(type)                                               \
+struct {                                                               \
+       struct type *le_next;   /* next element */                      \
+       struct type **le_prev;  /* address of previous next element */  \
+}
+
+/*
+ * List access methods
+ */
+#define        LIST_FIRST(head)                ((head)->lh_first)
+#define        LIST_END(head)                  NULL
+#define        LIST_EMPTY(head)                (LIST_FIRST(head) == 
LIST_END(head))
+#define        LIST_NEXT(elm, field)           ((elm)->field.le_next)
+
+#define LIST_FOREACH(var, head, field)                                 \
+       for((var) = LIST_FIRST(head);                                   \
+           (var)!= LIST_END(head);                                     \
+           (var) = LIST_NEXT(var, field))
+
+/*
+ * List functions.
+ */
+#define        LIST_INIT(head) do {                                            
\
+       LIST_FIRST(head) = LIST_END(head);                              \
+} while (0)
+
+#define LIST_INSERT_AFTER(listelm, elm, field) do {                    \
+       if (((elm)->field.le_next = (listelm)->field.le_next) != NULL)  \
+               (listelm)->field.le_next->field.le_prev =               \
+                   &(elm)->field.le_next;                              \
+       (listelm)->field.le_next = (elm);                               \
+       (elm)->field.le_prev = &(listelm)->field.le_next;               \
+} while (0)
+
+#define        LIST_INSERT_BEFORE(listelm, elm, field) do {                    
\
+       (elm)->field.le_prev = (listelm)->field.le_prev;                \
+       (elm)->field.le_next = (listelm);                               \
+       *(listelm)->field.le_prev = (elm);                              \
+       (listelm)->field.le_prev = &(elm)->field.le_next;               \
+} while (0)
+
+#define LIST_INSERT_HEAD(head, elm, field) do {                                
\
+       if (((elm)->field.le_next = (head)->lh_first) != NULL)          \
+               (head)->lh_first->field.le_prev = &(elm)->field.le_next;\
+       (head)->lh_first = (elm);                                       \
+       (elm)->field.le_prev = &(head)->lh_first;                       \
+} while (0)
+
+#define LIST_REMOVE(elm, field) do {                                   \
+       if ((elm)->field.le_next != NULL)                               \
+               (elm)->field.le_next->field.le_prev =                   \
+                   (elm)->field.le_prev;                               \
+       *(elm)->field.le_prev = (elm)->field.le_next;                   \
+       _Q_INVALIDATE((elm)->field.le_prev);                            \
+       _Q_INVALIDATE((elm)->field.le_next);                            \
+} while (0)
+
+#define LIST_REPLACE(elm, elm2, field) do {                            \
+       if (((elm2)->field.le_next = (elm)->field.le_next) != NULL)     \
+               (elm2)->field.le_next->field.le_prev =                  \
+                   &(elm2)->field.le_next;                             \
+       (elm2)->field.le_prev = (elm)->field.le_prev;                   \
+       *(elm2)->field.le_prev = (elm2);                                \
+       _Q_INVALIDATE((elm)->field.le_prev);                            \
+       _Q_INVALIDATE((elm)->field.le_next);                            \
+} while (0)
+
+/*
+ * Simple queue definitions.
+ */
+#define SIMPLEQ_HEAD(name, type)                                       \
+struct name {                                                          \
+       struct type *sqh_first; /* first element */                     \
+       struct type **sqh_last; /* addr of last next element */         \
+}
+
+#define SIMPLEQ_HEAD_INITIALIZER(head)                                 \
+       { NULL, &(head).sqh_first }
+
+#define SIMPLEQ_ENTRY(type)                                            \
+struct {                                                               \
+       struct type *sqe_next;  /* next element */                      \
+}
+
+/*
+ * Simple queue access methods.
+ */
+#define        SIMPLEQ_FIRST(head)         ((head)->sqh_first)
+#define        SIMPLEQ_END(head)           NULL
+#define        SIMPLEQ_EMPTY(head)         (SIMPLEQ_FIRST(head) == 
SIMPLEQ_END(head))
+#define        SIMPLEQ_NEXT(elm, field)    ((elm)->field.sqe_next)
+
+#define SIMPLEQ_FOREACH(var, head, field)                              \
+       for((var) = SIMPLEQ_FIRST(head);                                \
+           (var) != SIMPLEQ_END(head);                                 \
+           (var) = SIMPLEQ_NEXT(var, field))
+
+/*
+ * Simple queue functions.
+ */
+#define        SIMPLEQ_INIT(head) do {                                         
\
+       (head)->sqh_first = NULL;                                       \
+       (head)->sqh_last = &(head)->sqh_first;                          \
+} while (0)
+
+#define SIMPLEQ_INSERT_HEAD(head, elm, field) do {                     \
+       if (((elm)->field.sqe_next = (head)->sqh_first) == NULL)        \
+               (head)->sqh_last = &(elm)->field.sqe_next;              \
+       (head)->sqh_first = (elm);                                      \
+} while (0)
+
+#define SIMPLEQ_INSERT_TAIL(head, elm, field) do {                     \
+       (elm)->field.sqe_next = NULL;                                   \
+       *(head)->sqh_last = (elm);                                      \
+       (head)->sqh_last = &(elm)->field.sqe_next;                      \
+} while (0)
+
+#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do {           \
+       if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
+               (head)->sqh_last = &(elm)->field.sqe_next;              \
+       (listelm)->field.sqe_next = (elm);                              \
+} while (0)
+
+#define SIMPLEQ_REMOVE_HEAD(head, field) do {                  \
+       if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
+               (head)->sqh_last = &(head)->sqh_first;                  \
+} while (0)
+
+/*
+ * Tail queue definitions.
+ */
+#define TAILQ_HEAD(name, type)                                         \
+struct name {                                                          \
+       struct type *tqh_first; /* first element */                     \
+       struct type **tqh_last; /* addr of last next element */         \
+}
+
+#define TAILQ_HEAD_INITIALIZER(head)                                   \
+       { NULL, &(head).tqh_first }
+
+#define TAILQ_ENTRY(type)                                              \
+struct {                                                               \
+       struct type *tqe_next;  /* next element */                      \
+       struct type **tqe_prev; /* address of previous next element */  \
+}
+
+/* 
+ * tail queue access methods 
+ */
+#define        TAILQ_FIRST(head)               ((head)->tqh_first)
+#define        TAILQ_END(head)                 NULL
+#define        TAILQ_NEXT(elm, field)          ((elm)->field.tqe_next)
+#define TAILQ_LAST(head, headname)                                     \
+       (*(((struct headname *)((head)->tqh_last))->tqh_last))
+/* XXX */
+#define TAILQ_PREV(elm, headname, field)                               \
+       (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
+#define        TAILQ_EMPTY(head)                                               
\
+       (TAILQ_FIRST(head) == TAILQ_END(head))
+
+#define TAILQ_FOREACH(var, head, field)                                        
\
+       for((var) = TAILQ_FIRST(head);                                  \
+           (var) != TAILQ_END(head);                                   \
+           (var) = TAILQ_NEXT(var, field))
+
+#define TAILQ_FOREACH_REVERSE(var, head, headname, field)              \
+       for((var) = TAILQ_LAST(head, headname);                         \
+           (var) != TAILQ_END(head);                                   \
+           (var) = TAILQ_PREV(var, headname, field))
+
+/*
+ * Tail queue functions.
+ */
+#define        TAILQ_INIT(head) do {                                           
\
+       (head)->tqh_first = NULL;                                       \
+       (head)->tqh_last = &(head)->tqh_first;                          \
+} while (0)
+
+#define TAILQ_INSERT_HEAD(head, elm, field) do {                       \
+       if (((elm)->field.tqe_next = (head)->tqh_first) != NULL)        \
+               (head)->tqh_first->field.tqe_prev =                     \
+                   &(elm)->field.tqe_next;                             \
+       else                                                            \
+               (head)->tqh_last = &(elm)->field.tqe_next;              \
+       (head)->tqh_first = (elm);                                      \
+       (elm)->field.tqe_prev = &(head)->tqh_first;                     \
+} while (0)
+
+#define TAILQ_INSERT_TAIL(head, elm, field) do {                       \
+       (elm)->field.tqe_next = NULL;                                   \
+       (elm)->field.tqe_prev = (head)->tqh_last;                       \
+       *(head)->tqh_last = (elm);                                      \
+       (head)->tqh_last = &(elm)->field.tqe_next;                      \
+} while (0)
+
+#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do {             \
+       if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
+               (elm)->field.tqe_next->field.tqe_prev =                 \
+                   &(elm)->field.tqe_next;                             \
+       else                                                            \
+               (head)->tqh_last = &(elm)->field.tqe_next;              \
+       (listelm)->field.tqe_next = (elm);                              \
+       (elm)->field.tqe_prev = &(listelm)->field.tqe_next;             \
+} while (0)
+
+#define        TAILQ_INSERT_BEFORE(listelm, elm, field) do {                   
\
+       (elm)->field.tqe_prev = (listelm)->field.tqe_prev;              \
+       (elm)->field.tqe_next = (listelm);                              \
+       *(listelm)->field.tqe_prev = (elm);                             \
+       (listelm)->field.tqe_prev = &(elm)->field.tqe_next;             \
+} while (0)
+
+#define TAILQ_REMOVE(head, elm, field) do {                            \
+       if (((elm)->field.tqe_next) != NULL)                            \
+               (elm)->field.tqe_next->field.tqe_prev =                 \
+                   (elm)->field.tqe_prev;                              \
+       else                                                            \
+               (head)->tqh_last = (elm)->field.tqe_prev;               \
+       *(elm)->field.tqe_prev = (elm)->field.tqe_next;                 \
+       _Q_INVALIDATE((elm)->field.tqe_prev);                           \
+       _Q_INVALIDATE((elm)->field.tqe_next);                           \
+} while (0)
+
+#define TAILQ_REPLACE(head, elm, elm2, field) do {                     \
+       if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL)   \
+               (elm2)->field.tqe_next->field.tqe_prev =                \
+                   &(elm2)->field.tqe_next;                            \
+       else                                                            \
+               (head)->tqh_last = &(elm2)->field.tqe_next;             \
+       (elm2)->field.tqe_prev = (elm)->field.tqe_prev;                 \
+       *(elm2)->field.tqe_prev = (elm2);                               \
+       _Q_INVALIDATE((elm)->field.tqe_prev);                           \
+       _Q_INVALIDATE((elm)->field.tqe_next);                           \
+} while (0)
+
+/*
+ * Circular queue definitions.
+ */
+#define CIRCLEQ_HEAD(name, type)                                       \
+struct name {                                                          \
+       struct type *cqh_first;         /* first element */             \
+       struct type *cqh_last;          /* last element */              \
+}
+
+#define CIRCLEQ_HEAD_INITIALIZER(head)                                 \
+       { CIRCLEQ_END(&head), CIRCLEQ_END(&head) }
+
+#define CIRCLEQ_ENTRY(type)                                            \
+struct {                                                               \
+       struct type *cqe_next;          /* next element */              \
+       struct type *cqe_prev;          /* previous element */          \
+}
+
+/*
+ * Circular queue access methods 
+ */
+#define        CIRCLEQ_FIRST(head)             ((head)->cqh_first)
+#define        CIRCLEQ_LAST(head)              ((head)->cqh_last)
+#define        CIRCLEQ_END(head)               ((void *)(head))
+#define        CIRCLEQ_NEXT(elm, field)        ((elm)->field.cqe_next)
+#define        CIRCLEQ_PREV(elm, field)        ((elm)->field.cqe_prev)
+#define        CIRCLEQ_EMPTY(head)                                             
\
+       (CIRCLEQ_FIRST(head) == CIRCLEQ_END(head))
+
+#define CIRCLEQ_FOREACH(var, head, field)                              \
+       for((var) = CIRCLEQ_FIRST(head);                                \
+           (var) != CIRCLEQ_END(head);                                 \
+           (var) = CIRCLEQ_NEXT(var, field))
+
+#define CIRCLEQ_FOREACH_REVERSE(var, head, field)                      \
+       for((var) = CIRCLEQ_LAST(head);                                 \
+           (var) != CIRCLEQ_END(head);                                 \
+           (var) = CIRCLEQ_PREV(var, field))
+
+/*
+ * Circular queue functions.
+ */
+#define        CIRCLEQ_INIT(head) do {                                         
\
+       (head)->cqh_first = CIRCLEQ_END(head);                          \
+       (head)->cqh_last = CIRCLEQ_END(head);                           \
+} while (0)
+
+#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do {           \
+       (elm)->field.cqe_next = (listelm)->field.cqe_next;              \
+       (elm)->field.cqe_prev = (listelm);                              \
+       if ((listelm)->field.cqe_next == CIRCLEQ_END(head))             \
+               (head)->cqh_last = (elm);                               \
+       else                                                            \
+               (listelm)->field.cqe_next->field.cqe_prev = (elm);      \
+       (listelm)->field.cqe_next = (elm);                              \
+} while (0)
+
+#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do {          \
+       (elm)->field.cqe_next = (listelm);                              \
+       (elm)->field.cqe_prev = (listelm)->field.cqe_prev;              \
+       if ((listelm)->field.cqe_prev == CIRCLEQ_END(head))             \
+               (head)->cqh_first = (elm);                              \
+       else                                                            \
+               (listelm)->field.cqe_prev->field.cqe_next = (elm);      \
+       (listelm)->field.cqe_prev = (elm);                              \
+} while (0)
+
+#define CIRCLEQ_INSERT_HEAD(head, elm, field) do {                     \
+       (elm)->field.cqe_next = (head)->cqh_first;                      \
+       (elm)->field.cqe_prev = CIRCLEQ_END(head);                      \
+       if ((head)->cqh_last == CIRCLEQ_END(head))                      \
+               (head)->cqh_last = (elm);                               \
+       else                                                            \
+               (head)->cqh_first->field.cqe_prev = (elm);              \
+       (head)->cqh_first = (elm);                                      \
+} while (0)
+
+#define CIRCLEQ_INSERT_TAIL(head, elm, field) do {                     \
+       (elm)->field.cqe_next = CIRCLEQ_END(head);                      \
+       (elm)->field.cqe_prev = (head)->cqh_last;                       \
+       if ((head)->cqh_first == CIRCLEQ_END(head))                     \
+               (head)->cqh_first = (elm);                              \
+       else                                                            \
+               (head)->cqh_last->field.cqe_next = (elm);               \
+       (head)->cqh_last = (elm);                                       \
+} while (0)
+
+#define        CIRCLEQ_REMOVE(head, elm, field) do {                           
\
+       if ((elm)->field.cqe_next == CIRCLEQ_END(head))                 \
+               (head)->cqh_last = (elm)->field.cqe_prev;               \
+       else                                                            \
+               (elm)->field.cqe_next->field.cqe_prev =                 \
+                   (elm)->field.cqe_prev;                              \
+       if ((elm)->field.cqe_prev == CIRCLEQ_END(head))                 \
+               (head)->cqh_first = (elm)->field.cqe_next;              \
+       else                                                            \
+               (elm)->field.cqe_prev->field.cqe_next =                 \
+                   (elm)->field.cqe_next;                              \
+       _Q_INVALIDATE((elm)->field.cqe_prev);                           \
+       _Q_INVALIDATE((elm)->field.cqe_next);                           \
+} while (0)
+
+#define CIRCLEQ_REPLACE(head, elm, elm2, field) do {                   \
+       if (((elm2)->field.cqe_next = (elm)->field.cqe_next) ==         \
+           CIRCLEQ_END(head))                                          \
+               (head).cqh_last = (elm2);                               \
+       else                                                            \
+               (elm2)->field.cqe_next->field.cqe_prev = (elm2);        \
+       if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) ==         \
+           CIRCLEQ_END(head))                                          \
+               (head).cqh_first = (elm2);                              \
+       else                                                            \
+               (elm2)->field.cqe_prev->field.cqe_next = (elm2);        \
+       _Q_INVALIDATE((elm)->field.cqe_prev);                           \
+       _Q_INVALIDATE((elm)->field.cqe_next);                           \
+} while (0)
+
+#endif /* !_SYS_QUEUE_H_ */

Added: gnunet/src/nat/miniupnp/codelength.h
===================================================================
--- gnunet/src/nat/miniupnp/codelength.h                                (rev 0)
+++ gnunet/src/nat/miniupnp/codelength.h        2009-10-25 09:44:36 UTC (rev 
9271)
@@ -0,0 +1,23 @@
+/* $Id: codelength.h,v 1.1 2008/10/06 22:04:06 nanard Exp $ */
+/* Project : miniupnp
+ * Author : Thomas BERNARD
+ * copyright (c) 2005-2008 Thomas Bernard
+ * This software is subjet to the conditions detailed in the
+ * provided LICENCE file. */
+#ifndef __CODELENGTH_H__
+#define __CODELENGTH_H__
+
+/* Encode length by using 7bit per Byte :
+ * Most significant bit of each byte specifies that the
+ * following byte is part of the code */
+#define DECODELENGTH(n, p) n = 0; \
+                           do { n = (n << 7) | (*p & 0x7f); } \
+                           while(*(p++)&0x80);
+
+#define CODELENGTH(n, p) if(n>=268435456) *(p++) = (n >> 28) | 0x80; \
+                         if(n>=2097152) *(p++) = (n >> 21) | 0x80; \
+                         if(n>=16384) *(p++) = (n >> 14) | 0x80; \
+                         if(n>=128) *(p++) = (n >> 7) | 0x80; \
+                         *(p++) = n & 0x7f;
+
+#endif

Added: gnunet/src/nat/miniupnp/declspec.h
===================================================================
--- gnunet/src/nat/miniupnp/declspec.h                          (rev 0)
+++ gnunet/src/nat/miniupnp/declspec.h  2009-10-25 09:44:36 UTC (rev 9271)
@@ -0,0 +1,14 @@
+#ifndef __DECLSPEC_H__
+#define __DECLSPEC_H__
+
+#if defined(WIN32) && !defined(STATICLIB)
+#ifdef MINIUPNP_EXPORTS
+#define LIBSPEC __declspec(dllexport)
+#else
+#define LIBSPEC __declspec(dllimport)
+#endif
+#else
+#define LIBSPEC
+#endif
+
+#endif

Added: gnunet/src/nat/miniupnp/igd_desc_parse.c
===================================================================
--- gnunet/src/nat/miniupnp/igd_desc_parse.c                            (rev 0)
+++ gnunet/src/nat/miniupnp/igd_desc_parse.c    2009-10-25 09:44:36 UTC (rev 
9271)
@@ -0,0 +1,126 @@
+/* $Id: igd_desc_parse.c,v 1.8 2008/04/23 11:51:06 nanard Exp $ */
+/* Project : miniupnp
+ * http://miniupnp.free.fr/
+ * Author : Thomas Bernard
+ * Copyright (c) 2005-2008 Thomas Bernard
+ * This software is subject to the conditions detailed in the
+ * LICENCE file provided in this distribution.
+ * */
+#include "igd_desc_parse.h"
+#include <stdio.h>
+#include <string.h>
+
+/* TODO : rewrite this code so it correctly handle descriptions with
+ * both WANIPConnection and/or WANPPPConnection */
+
+/* Start element handler :
+ * update nesting level counter and copy element name */
+void
+IGDstartelt (void *d, const char *name, int l)
+{
+  struct IGDdatas *datas = (struct IGDdatas *) d;
+  memcpy (datas->cureltname, name, l);
+  datas->cureltname[l] = '\0';
+  datas->level++;
+  if ((l == 7) && !memcmp (name, "service", l))
+    {
+      datas->controlurl_tmp[0] = '\0';
+      datas->eventsuburl_tmp[0] = '\0';
+      datas->scpdurl_tmp[0] = '\0';
+      datas->servicetype_tmp[0] = '\0';
+    }
+}
+
+/* End element handler :
+ * update nesting level counter and update parser state if
+ * service element is parsed */
+void
+IGDendelt (void *d, const char *name, int l)
+{
+  struct IGDdatas *datas = (struct IGDdatas *) d;
+  datas->level--;
+  /*printf("endelt %2d %.*s\n", datas->level, l, name); */
+  if ((l == 7) && !memcmp (name, "service", l))
+    {
+      /*
+         if( datas->state < 1
+         && !strcmp(datas->servicetype,
+         //   "urn:schemas-upnp-org:service:WANIPConnection:1") )
+         "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1"))
+         datas->state ++;
+       */
+      if (0 == strcmp (datas->servicetype_tmp,
+                       
"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1"))
+        {
+          memcpy (datas->controlurl_CIF, datas->controlurl_tmp,
+                  MINIUPNPC_URL_MAXSIZE);
+          memcpy (datas->eventsuburl_CIF, datas->eventsuburl_tmp,
+                  MINIUPNPC_URL_MAXSIZE);
+          memcpy (datas->scpdurl_CIF, datas->scpdurl_tmp,
+                  MINIUPNPC_URL_MAXSIZE);
+          memcpy (datas->servicetype_CIF, datas->servicetype_tmp,
+                  MINIUPNPC_URL_MAXSIZE);
+        }
+      else if (0 == strcmp (datas->servicetype_tmp,
+                            "urn:schemas-upnp-org:service:WANIPConnection:1")
+               || 0 == strcmp (datas->servicetype_tmp,
+                               
"urn:schemas-upnp-org:service:WANPPPConnection:1"))
+        {
+          memcpy (datas->controlurl, datas->controlurl_tmp,
+                  MINIUPNPC_URL_MAXSIZE);
+          memcpy (datas->eventsuburl, datas->eventsuburl_tmp,
+                  MINIUPNPC_URL_MAXSIZE);
+          memcpy (datas->scpdurl, datas->scpdurl_tmp, MINIUPNPC_URL_MAXSIZE);
+          memcpy (datas->servicetype, datas->servicetype_tmp,
+                  MINIUPNPC_URL_MAXSIZE);
+        }
+    }
+}
+
+/* Data handler :
+ * copy data depending on the current element name and state */
+void
+IGDdata (void *d, const char *data, int l)
+{
+  struct IGDdatas *datas = (struct IGDdatas *) d;
+  char *dstmember = 0;
+  /*printf("%2d %s : %.*s\n",
+     datas->level, datas->cureltname, l, data);   */
+  if (!strcmp (datas->cureltname, "URLBase"))
+    dstmember = datas->urlbase;
+  else if (!strcmp (datas->cureltname, "serviceType"))
+    dstmember = datas->servicetype_tmp;
+  else if (!strcmp (datas->cureltname, "controlURL"))
+    dstmember = datas->controlurl_tmp;
+  else if (!strcmp (datas->cureltname, "eventSubURL"))
+    dstmember = datas->eventsuburl_tmp;
+  else if (!strcmp (datas->cureltname, "SCPDURL"))
+    dstmember = datas->scpdurl_tmp;
+/*     else if( !strcmp(datas->cureltname, "deviceType") )
+               dstmember = datas->devicetype_tmp;*/
+  if (dstmember)
+    {
+      if (l >= MINIUPNPC_URL_MAXSIZE)
+        l = MINIUPNPC_URL_MAXSIZE - 1;
+      memcpy (dstmember, data, l);
+      dstmember[l] = '\0';
+    }
+}
+
+void
+printIGD (struct IGDdatas *d)
+{
+  printf ("urlbase = %s\n", d->urlbase);
+  printf ("WAN Device (Common interface config) :\n");
+  /*printf(" deviceType = %s\n", d->devicetype_CIF); */
+  printf (" serviceType = %s\n", d->servicetype_CIF);
+  printf (" controlURL = %s\n", d->controlurl_CIF);
+  printf (" eventSubURL = %s\n", d->eventsuburl_CIF);
+  printf (" SCPDURL = %s\n", d->scpdurl_CIF);
+  printf ("WAN Connection Device (IP or PPP Connection):\n");
+  /*printf(" deviceType = %s\n", d->devicetype); */
+  printf (" servicetype = %s\n", d->servicetype);
+  printf (" controlURL = %s\n", d->controlurl);
+  printf (" eventSubURL = %s\n", d->eventsuburl);
+  printf (" SCPDURL = %s\n", d->scpdurl);
+}

Added: gnunet/src/nat/miniupnp/igd_desc_parse.h
===================================================================
--- gnunet/src/nat/miniupnp/igd_desc_parse.h                            (rev 0)
+++ gnunet/src/nat/miniupnp/igd_desc_parse.h    2009-10-25 09:44:36 UTC (rev 
9271)
@@ -0,0 +1,47 @@
+/* $Id: igd_desc_parse.h,v 1.6 2008/04/23 11:51:07 nanard Exp $ */
+/* Project : miniupnp
+ * http://miniupnp.free.fr/
+ * Author : Thomas Bernard
+ * Copyright (c) 2005-2008 Thomas Bernard
+ * This software is subject to the conditions detailed in the
+ * LICENCE file provided in this distribution.
+ * */
+#ifndef __IGD_DESC_PARSE_H__
+#define __IGD_DESC_PARSE_H__
+
+/* Structure to store the result of the parsing of UPnP
+ * descriptions of Internet Gateway Devices */
+#define MINIUPNPC_URL_MAXSIZE (128)
+struct IGDdatas
+{
+  char cureltname[MINIUPNPC_URL_MAXSIZE];
+  char urlbase[MINIUPNPC_URL_MAXSIZE];
+  int level;
+  /*int state; */
+  /* "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1" */
+  char controlurl_CIF[MINIUPNPC_URL_MAXSIZE];
+  char eventsuburl_CIF[MINIUPNPC_URL_MAXSIZE];
+  char scpdurl_CIF[MINIUPNPC_URL_MAXSIZE];
+  char servicetype_CIF[MINIUPNPC_URL_MAXSIZE];
+  /*char devicetype_CIF[MINIUPNPC_URL_MAXSIZE]; */
+  /* "urn:schemas-upnp-org:service:WANIPConnection:1"
+   * "urn:schemas-upnp-org:service:WANPPPConnection:1" */
+  char controlurl[MINIUPNPC_URL_MAXSIZE];
+  char eventsuburl[MINIUPNPC_URL_MAXSIZE];
+  char scpdurl[MINIUPNPC_URL_MAXSIZE];
+  char servicetype[MINIUPNPC_URL_MAXSIZE];
+  /*char devicetype[MINIUPNPC_URL_MAXSIZE]; */
+  /* tmp */
+  char controlurl_tmp[MINIUPNPC_URL_MAXSIZE];
+  char eventsuburl_tmp[MINIUPNPC_URL_MAXSIZE];
+  char scpdurl_tmp[MINIUPNPC_URL_MAXSIZE];
+  char servicetype_tmp[MINIUPNPC_URL_MAXSIZE];
+  /*char devicetype_tmp[MINIUPNPC_URL_MAXSIZE]; */
+};
+
+void IGDstartelt (void *, const char *, int);
+void IGDendelt (void *, const char *, int);
+void IGDdata (void *, const char *, int);
+void printIGD (struct IGDdatas *);
+
+#endif

Added: gnunet/src/nat/miniupnp/minisoap.c
===================================================================
--- gnunet/src/nat/miniupnp/minisoap.c                          (rev 0)
+++ gnunet/src/nat/miniupnp/minisoap.c  2009-10-25 09:44:36 UTC (rev 9271)
@@ -0,0 +1,106 @@
+/* $Id: minisoap.c,v 1.16 2008/10/11 16:39:29 nanard Exp $ */
+/* Project : miniupnp
+ * Author : Thomas Bernard
+ * Copyright (c) 2005 Thomas Bernard
+ * This software is subject to the conditions detailed in the
+ * LICENCE file provided in this distribution.
+ *
+ * Minimal SOAP implementation for UPnP protocol.
+ */
+#include <stdio.h>
+#include <string.h>
+#ifdef WIN32
+#include <io.h>
+#include <winsock2.h>
+#define snprintf _snprintf
+#else
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#endif
+#include "minisoap.h"
+#include "miniupnpcstrings.h"
+
+/* only for malloc */
+#include <stdlib.h>
+
+#ifdef WIN32
+#define PRINT_SOCKET_ERROR(x)    printf("Socket error: %s, %d\n", x, 
WSAGetLastError());
+#else
+#define PRINT_SOCKET_ERROR(x) perror(x)
+#endif
+
+/* httpWrite sends the headers and the body to the socket
+ * and returns the number of bytes sent */
+static int
+httpWrite (int fd, const char *body, int bodysize,
+           const char *headers, int headerssize)
+{
+  int n = 0;
+  /*n = write(fd, headers, headerssize); */
+  /*if(bodysize>0)
+     n += write(fd, body, bodysize); */
+  /* Note : my old linksys router only took into account
+   * soap request that are sent into only one packet */
+  char *p;
+  /* TODO: AVOID MALLOC */
+  p = malloc (headerssize + bodysize);
+  if (!p)
+    return 0;
+  memcpy (p, headers, headerssize);
+  memcpy (p + headerssize, body, bodysize);
+  /*n = write(fd, p, headerssize+bodysize); */
+  n = send (fd, p, headerssize + bodysize, 0);
+  if (n < 0)
+    {
+      PRINT_SOCKET_ERROR ("send");
+    }
+  /* disable send on the socket */
+  /* draytek routers dont seems to like that... */
+#if 0
+#ifdef WIN32
+  if (shutdown (fd, SD_SEND) < 0)
+    {
+#else
+  if (shutdown (fd, SHUT_WR) < 0)
+    {                           /*SD_SEND */
+#endif
+      PRINT_SOCKET_ERROR ("shutdown");
+    }
+#endif
+  free (p);
+  return n;
+}
+
+/* self explanatory  */
+int
+soapPostSubmit (int fd,
+                const char *url,
+                const char *host,
+                unsigned short port, const char *action, const char *body)
+{
+  int bodysize;
+  char headerbuf[512];
+  int headerssize;
+  char portstr[8];
+  bodysize = (int) strlen (body);
+  /* We are not using keep-alive HTTP connections.
+   * HTTP/1.1 needs the header Connection: close to do that.
+   * This is the default with HTTP/1.0 */
+  /* Connection: Close is normally there only in HTTP/1.1 but who knows */
+  portstr[0] = '\0';
+  if (port != 80)
+    snprintf (portstr, sizeof (portstr), ":%hu", port);
+  headerssize = snprintf (headerbuf, sizeof (headerbuf),
+                          "POST %s HTTP/1.1\r\n"
+/*                       "POST %s HTTP/1.0\r\n"*/
+                          "Host: %s%s\r\n" "User-Agent: " OS_STRING ", 
UPnP/1.0, MiniUPnPc/" MINIUPNPC_VERSION_STRING "\r\n" "Content-Length: %d\r\n" 
"Content-Type: text/xml\r\n" "SOAPAction: \"%s\"\r\n" "Connection: Close\r\n" 
"Cache-Control: no-cache\r\n"       /* ??? */
+                          "Pragma: no-cache\r\n"
+                          "\r\n", url, host, portstr, bodysize, action);
+#ifdef DEBUG
+  printf ("SOAP request : headersize=%d bodysize=%d\n",
+          headerssize, bodysize);
+  /*printf("%s", headerbuf); */
+#endif
+  return httpWrite (fd, body, bodysize, headerbuf, headerssize);
+}

Added: gnunet/src/nat/miniupnp/minisoap.h
===================================================================
--- gnunet/src/nat/miniupnp/minisoap.h                          (rev 0)
+++ gnunet/src/nat/miniupnp/minisoap.h  2009-10-25 09:44:36 UTC (rev 9271)
@@ -0,0 +1,14 @@
+/* $Id: minisoap.h,v 1.3 2006/11/19 22:32:34 nanard Exp $ */
+/* Project : miniupnp
+ * Author : Thomas Bernard
+ * Copyright (c) 2005 Thomas Bernard
+ * This software is subject to the conditions detailed in the
+ * LICENCE file provided in this distribution. */
+#ifndef __MINISOAP_H__
+#define __MINISOAP_H__
+
+/*int httpWrite(int, const char *, int, const char *);*/
+int soapPostSubmit (int, const char *, const char *, unsigned short,
+                    const char *, const char *);
+
+#endif

Added: gnunet/src/nat/miniupnp/minissdpc.c
===================================================================
--- gnunet/src/nat/miniupnp/minissdpc.c                         (rev 0)
+++ gnunet/src/nat/miniupnp/minissdpc.c 2009-10-25 09:44:36 UTC (rev 9271)
@@ -0,0 +1,111 @@
+/* $Id: minissdpc.c,v 1.7 2008/12/18 17:45:48 nanard Exp $ */
+/* Project : miniupnp
+ * Author : Thomas BERNARD
+ * copyright (c) 2005-2008 Thomas Bernard
+ * This software is subjet to the conditions detailed in the
+ * provided LICENCE file. */
+/*#include <syslog.h>*/
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#ifdef WIN32
+#include <winsock2.h>
+#include <Ws2tcpip.h>
+#include <io.h>
+#else
+#include <sys/socket.h>
+#include <sys/un.h>
+#endif
+
+#include "minissdpc.h"
+#include "miniupnpc.h"
+
+#include "codelength.h"
+
+struct UPNPDev *
+getDevicesFromMiniSSDPD (const char *devtype, const char *socketpath)
+{
+  struct UPNPDev *tmp;
+  struct UPNPDev *devlist = NULL;
+  unsigned char buffer[2048];
+  ssize_t n;
+  unsigned char *p;
+  unsigned char *url;
+  unsigned int i;
+  unsigned int urlsize, stsize, usnsize, l;
+  int s;
+  struct sockaddr_un addr;
+
+  s = socket (AF_UNIX, SOCK_STREAM, 0);
+  if (s < 0)
+    {
+      /*syslog(LOG_ERR, "socket(unix): %m"); */
+      perror ("socket(unix)");
+      return NULL;
+    }
+  addr.sun_family = AF_UNIX;
+  strncpy (addr.sun_path, socketpath, sizeof (addr.sun_path));
+  if (connect (s, (struct sockaddr *) &addr, sizeof (struct sockaddr_un)) < 0)
+    {
+      /*syslog(LOG_WARNING, "connect(\"%s\"): %m", socketpath); */
+      close (s);
+      return NULL;
+    }
+  stsize = strlen (devtype);
+  buffer[0] = 1;                /* request type 1 : request devices/services 
by type */
+  p = buffer + 1;
+  l = stsize;
+  CODELENGTH (l, p);
+  memcpy (p, devtype, stsize);
+  p += stsize;
+  if (write (s, buffer, p - buffer) < 0)
+    {
+      /*syslog(LOG_ERR, "write(): %m"); */
+      perror ("minissdpc.c: write()");
+      close (s);
+      return NULL;
+    }
+  n = read (s, buffer, sizeof (buffer));
+  if (n <= 0)
+    {
+      perror ("minissdpc.c: read()");
+      close (s);
+      return NULL;
+    }
+  p = buffer + 1;
+  for (i = 0; i < buffer[0]; i++)
+    {
+      if (p + 2 >= buffer + sizeof (buffer))
+        break;
+      DECODELENGTH (urlsize, p);
+      if (p + urlsize + 2 >= buffer + sizeof (buffer))
+        break;
+      url = p;
+      p += urlsize;
+      DECODELENGTH (stsize, p);
+      if (p + stsize + 2 >= buffer + sizeof (buffer))
+        break;
+      tmp =
+        (struct UPNPDev *) malloc (sizeof (struct UPNPDev) + urlsize +
+                                   stsize);
+      tmp->pNext = devlist;
+      tmp->descURL = tmp->buffer;
+      tmp->st = tmp->buffer + 1 + urlsize;
+      memcpy (tmp->buffer, url, urlsize);
+      tmp->buffer[urlsize] = '\0';
+      memcpy (tmp->buffer + urlsize + 1, p, stsize);
+      p += stsize;
+      tmp->buffer[urlsize + 1 + stsize] = '\0';
+      devlist = tmp;
+      /* added for compatibility with recent versions of MiniSSDPd 
+       * >= 2007/12/19 */
+      DECODELENGTH (usnsize, p);
+      p += usnsize;
+      if (p > buffer + sizeof (buffer))
+        break;
+    }
+  close (s);
+  return devlist;
+}

Added: gnunet/src/nat/miniupnp/minissdpc.h
===================================================================
--- gnunet/src/nat/miniupnp/minissdpc.h                         (rev 0)
+++ gnunet/src/nat/miniupnp/minissdpc.h 2009-10-25 09:44:36 UTC (rev 9271)
@@ -0,0 +1,14 @@
+/* $Id: minissdpc.h,v 1.1 2007/08/31 15:15:33 nanard Exp $ */
+/* Project: miniupnp
+ * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
+ * Author: Thomas Bernard
+ * Copyright (c) 2005-2007 Thomas Bernard
+ * This software is subjects to the conditions detailed
+ * in the LICENCE file provided within this distribution */
+#ifndef __MINISSDPC_H__
+#define __MINISSDPC_H__
+
+struct UPNPDev *getDevicesFromMiniSSDPD (const char *devtype,
+                                         const char *socketpath);
+
+#endif

Added: gnunet/src/nat/miniupnp/miniupnpc.c
===================================================================
--- gnunet/src/nat/miniupnp/miniupnpc.c                         (rev 0)
+++ gnunet/src/nat/miniupnp/miniupnpc.c 2009-10-25 09:44:36 UTC (rev 9271)
@@ -0,0 +1,890 @@
+/* $Id: miniupnpc.c,v 1.57 2008/12/18 17:46:36 nanard Exp $ */
+/* Project : miniupnp
+ * Author : Thomas BERNARD
+ * copyright (c) 2005-2007 Thomas Bernard
+ * This software is subjet to the conditions detailed in the
+ * provided LICENCE file. */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef WIN32
+/* Win32 Specific includes and defines */
+#include <winsock2.h>
+#include <Ws2tcpip.h>
+#include <Iphlpapi.h>
+#include <io.h>
+#define snprintf _snprintf
+#if defined(_MSC_VER) && (_MSC_VER >= 1400)
+#define strncasecmp _memicmp
+#else
+#define strncasecmp memicmp
+#endif
+#define MAXHOSTNAMELEN 64
+#else
+/* Standard POSIX includes */
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <arpa/inet.h>
+#include <poll.h>
+#include <netdb.h>
+#define closesocket close
+#endif
+#include "miniupnpc.h"
+#include "minissdpc.h"
+#include "miniwget.h"
+#include "minisoap.h"
+#include "minixml.h"
+#include "upnpcommands.h"
+
+#ifdef WIN32
+#define PRINT_SOCKET_ERROR(x)    printf("Socket error: %s, %d\n", x, 
WSAGetLastError());
+#else
+#define PRINT_SOCKET_ERROR(x) perror(x)
+#endif
+
+#define SOAPPREFIX "s"
+#define SERVICEPREFIX "u"
+#define SERVICEPREFIX2 'u'
+
+/* root description parsing */
+void
+parserootdesc (const char *buffer, int bufsize, struct IGDdatas *data)
+{
+  struct xmlparser parser;
+  /* xmlparser object */
+  parser.xmlstart = buffer;
+  parser.xmlsize = bufsize;
+  parser.data = data;
+  parser.starteltfunc = IGDstartelt;
+  parser.endeltfunc = IGDendelt;
+  parser.datafunc = IGDdata;
+  parser.attfunc = 0;
+  parsexml (&parser);
+#ifdef DEBUG
+  printIGD (data);
+#endif
+}
+
+/* Content-length: nnn */
+static int
+getcontentlenfromline (const char *p, int n)
+{
+  static const char contlenstr[] = "content-length";
+  const char *p2 = contlenstr;
+  int a = 0;
+  while (*p2)
+    {
+      if (n == 0)
+        return -1;
+      if (*p2 != *p && *p2 != (*p + 32))
+        return -1;
+      p++;
+      p2++;
+      n--;
+    }
+  if (n == 0)
+    return -1;
+  if (*p != ':')
+    return -1;
+  p++;
+  n--;
+  while (*p == ' ')
+    {
+      if (n == 0)
+        return -1;
+      p++;
+      n--;
+    }
+  while (*p >= '0' && *p <= '9')
+    {
+      if (n == 0)
+        return -1;
+      a = (a * 10) + (*p - '0');
+      p++;
+      n--;
+    }
+  return a;
+}
+
+static void
+getContentLengthAndHeaderLength (char *p, int n,
+                                 int *contentlen, int *headerlen)
+{
+  char *line;
+  int linelen;
+  int r;
+  line = p;
+  while (line < p + n)
+    {
+      linelen = 0;
+      while (line[linelen] != '\r' && line[linelen] != '\r')
+        {
+          if (line + linelen >= p + n)
+            return;
+          linelen++;
+        }
+      r = getcontentlenfromline (line, linelen);
+      if (r > 0)
+        *contentlen = r;
+      line = line + linelen + 2;
+      if (line[0] == '\r' && line[1] == '\n')
+        {
+          *headerlen = (line - p) + 2;
+          return;
+        }
+    }
+}
+
+/* simpleUPnPcommand :
+ * not so simple !
+ * return values :
+ *   0 - OK
+ *  -1 - error */
+int
+simpleUPnPcommand (int s, const char *url, const char *service,
+                   const char *action, struct UPNParg *args,
+                   char *buffer, int *bufsize)
+{
+  struct sockaddr_in dest;
+  struct sockaddr_in6 dest6;
+  char hostname[MAXHOSTNAMELEN + 1];
+  unsigned short port = 0;
+  char *path;
+  char soapact[128];
+  char soapbody[2048];
+  char *buf;
+  int buffree;
+  int n;
+  int err;
+  int contentlen, headerlen;    /* for the response */
+  snprintf (soapact, sizeof (soapact), "%s#%s", service, action);
+  if (args == NULL)
+    {
+      /*soapbodylen = */ snprintf (soapbody, sizeof (soapbody),
+                                   "<?xml version=\"1.0\"?>\r\n"
+                                   "<" SOAPPREFIX ":Envelope "
+                                   "xmlns:" SOAPPREFIX
+                                   
"=\"http://schemas.xmlsoap.org/soap/envelope/\"; "
+                                   SOAPPREFIX
+                                   
":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\";>"
+                                   "<" SOAPPREFIX ":Body>" "<" SERVICEPREFIX
+                                   ":%s xmlns:" SERVICEPREFIX "=\"%s\">" "</"
+                                   SERVICEPREFIX ":%s>" "</" SOAPPREFIX
+                                   ":Body></" SOAPPREFIX ":Envelope>" "\r\n",
+                                   action, service, action);
+    }
+  else
+    {
+      char *p;
+      const char *pe, *pv;
+      int soapbodylen;
+      soapbodylen = snprintf (soapbody, sizeof (soapbody),
+                              "<?xml version=\"1.0\"?>\r\n"
+                              "<" SOAPPREFIX ":Envelope "
+                              "xmlns:" SOAPPREFIX
+                              "=\"http://schemas.xmlsoap.org/soap/envelope/\"; "
+                              SOAPPREFIX
+                              
":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\";>"
+                              "<" SOAPPREFIX ":Body>" "<" SERVICEPREFIX
+                              ":%s xmlns:" SERVICEPREFIX "=\"%s\">", action,
+                              service);
+      p = soapbody + soapbodylen;
+      while (args->elt)
+        {
+          /* check that we are never overflowing the string... */
+          if (soapbody + sizeof (soapbody) <= p + 100)
+            {
+              /* we keep a margin of at least 100 bytes */
+              *bufsize = 0;
+              return -1;
+            }
+          *(p++) = '<';
+          pe = args->elt;
+          while (*pe)
+            *(p++) = *(pe++);
+          *(p++) = '>';
+          if ((pv = args->val))
+            {
+              while (*pv)
+                *(p++) = *(pv++);
+            }
+          *(p++) = '<';
+          *(p++) = '/';
+          pe = args->elt;
+          while (*pe)
+            *(p++) = *(pe++);
+          *(p++) = '>';
+          args++;
+        }
+      *(p++) = '<';
+      *(p++) = '/';
+      *(p++) = SERVICEPREFIX2;
+      *(p++) = ':';
+      pe = action;
+      while (*pe)
+        *(p++) = *(pe++);
+      strncpy (p, "></" SOAPPREFIX ":Body></" SOAPPREFIX ":Envelope>\r\n",
+               soapbody + sizeof (soapbody) - p);
+    }
+  if (!parseURL (url, hostname, &port, &path))
+    return -1;
+
+  if (s < 0)
+    {
+      /* Test IPv4 address, else use IPv6 */
+      if (inet_pton (AF_INET, hostname, &dest.sin_addr) == 1)
+        {
+          dest.sin_family = AF_INET;
+          dest.sin_port = htons (port);
+#ifdef HAVE_SOCKADDR_IN_SIN_LEN
+          dest.sin_len = sizeof (dest);
+#endif
+          if ((s = socket (PF_INET, SOCK_STREAM, 0)) < 0)
+            {
+              PRINT_SOCKET_ERROR ("socket");
+              *bufsize = 0;
+              return -1;
+            }
+          err = connect (s, (struct sockaddr *) &dest, sizeof (dest));
+        }
+      else if (inet_pton (AF_INET6, hostname, &dest6.sin6_addr) == 1)
+        {
+          dest6.sin6_family = AF_INET6;
+          dest6.sin6_port = htons (port);
+          dest6.sin6_flowinfo = 0;
+#ifdef HAVE_SOCKADDR_IN_SIN_LEN
+          dest6.sin6_len = sizeof (dest6);
+#endif
+          if ((s = socket (PF_INET6, SOCK_STREAM, 0)) < 0)
+            {
+              PRINT_SOCKET_ERROR ("socket");
+              *bufsize = 0;
+              return -1;
+            }
+          err = connect (s, (struct sockaddr *) &dest6, sizeof (dest6));
+        }
+      else
+        {
+          PRINT_SOCKET_ERROR ("inet_pton");
+          closesocket (s);
+          *bufsize = 0;
+          return -1;
+        }
+
+      if (err < 0)
+        {
+          PRINT_SOCKET_ERROR ("connect");
+          closesocket (s);
+          *bufsize = 0;
+          return -1;
+        }
+    }
+  n = soapPostSubmit (s, path, hostname, port, soapact, soapbody);
+  if (n <= 0)
+    {
+#ifdef DEBUG
+      printf ("Error sending SOAP request\n");
+#endif
+      closesocket (s);
+      return -1;
+    }
+
+  contentlen = -1;
+  headerlen = -1;
+  buf = buffer;
+  buffree = *bufsize;
+  *bufsize = 0;
+  while ((n = ReceiveData (s, buf, buffree, 5000)) > 0)
+    {
+      buffree -= n;
+      buf += n;
+      *bufsize += n;
+      getContentLengthAndHeaderLength (buffer, *bufsize,
+                                       &contentlen, &headerlen);
+#ifdef DEBUG
+      printf ("received n=%dbytes bufsize=%d ContLen=%d HeadLen=%d\n",
+              n, *bufsize, contentlen, headerlen);
+#endif
+      /* break if we received everything */
+      if (contentlen > 0 && headerlen > 0
+          && *bufsize >= contentlen + headerlen)
+        break;
+    }
+
+  closesocket (s);
+  return 0;
+}
+
+/* parseMSEARCHReply()
+ * the last 4 arguments are filled during the parsing :
+ *    - location/locationsize : "location:" field of the SSDP reply packet
+ *    - st/stsize : "st:" field of the SSDP reply packet.
+ * The strings are NOT null terminated */
+static void
+parseMSEARCHReply (const char *reply, int size,
+                   const char **location, int *locationsize,
+                   const char **st, int *stsize)
+{
+  int a, b, i;
+  i = 0;
+  a = i;                        /* start of the line */
+  b = 0;
+  while (i < size)
+    {
+      switch (reply[i])
+        {
+        case ':':
+          if (b == 0)
+            {
+              b = i;            /* end of the "header" */
+              /*for(j=a; j<b; j++)
+                 {
+                 putchar(reply[j]);
+                 }
+               */
+            }
+          break;
+        case '\x0a':
+        case '\x0d':
+          if (b != 0)
+            {
+              /*for(j=b+1; j<i; j++)
+                 {
+                 putchar(reply[j]);
+                 }
+                 putchar('\n'); */
+              do
+                {
+                  b++;
+                }
+              while (reply[b] == ' ');
+              if (0 == strncasecmp (reply + a, "location", 8))
+                {
+                  *location = reply + b;
+                  *locationsize = i - b;
+                }
+              else if (0 == strncasecmp (reply + a, "st", 2))
+                {
+                  *st = reply + b;
+                  *stsize = i - b;
+                }
+              b = 0;
+            }
+          a = i + 1;
+          break;
+        default:
+          break;
+        }
+      i++;
+    }
+}
+
+/* port upnp discover : SSDP protocol */
+#define PORT 1900
+#define XSTR(s) STR(s)
+#define STR(s) #s
+#define UPNP_MCAST_ADDR "239.255.255.250"
+#define UPNP_MCAST_ADDR6 "FF02:0:0:0:0:0:0:F"
+
+/* upnpDiscover() :
+ * return a chained list of all devices found or NULL if
+ * no devices was found.
+ * It is up to the caller to free the chained list
+ * delay is in millisecond (poll) */
+struct UPNPDev *
+upnpDiscover (int delay, const char *multicastif,
+              const struct sockaddr *addr,
+              const char *minissdpdsock, int sameport)
+{
+  struct UPNPDev *tmp;
+  struct UPNPDev *devlist = 0;
+  int opt = 1;
+  static const char MSearchMsgFmt[] =
+    "M-SEARCH * HTTP/1.1\r\n"
+    "HOST: " UPNP_MCAST_ADDR ":" XSTR (PORT) "\r\n"
+    "ST: %s\r\n" "MAN: \"ssdp:discover\"\r\n" "MX: 3\r\n" "\r\n";
+  static const char *const deviceList[] = {
+    "urn:schemas-upnp-org:device:InternetGatewayDevice:1",
+    "urn:schemas-upnp-org:service:WANIPConnection:1",
+    "urn:schemas-upnp-org:service:WANPPPConnection:1",
+    "upnp:rootdevice",
+    0
+  };
+  int deviceIndex = 0;
+  char bufr[1536];              /* reception and emission buffer */
+  int sudp;
+  int n;
+  int domain = PF_INET;
+  int if_index;
+  struct in6_addr any_addr = IN6ADDR_ANY_INIT;
+  struct sockaddr_in sockudp_r, sockudp_w;
+  struct sockaddr_in6 sockudp6_r, sockudp6_w;
+
+#ifndef WIN32
+  /* first try to get infos from minissdpd ! */
+  if (!minissdpdsock)
+    minissdpdsock = "/var/run/minissdpd.sock";
+  while (!devlist && deviceList[deviceIndex])
+    {
+      devlist = getDevicesFromMiniSSDPD (deviceList[deviceIndex],
+                                         minissdpdsock);
+      /* We return what we have found if it was not only a rootdevice */
+      if (devlist && !strstr (deviceList[deviceIndex], "rootdevice"))
+        return devlist;
+      deviceIndex++;
+    }
+  deviceIndex = 0;
+#endif
+
+  if (addr && addr->sa_family == AF_INET)
+    domain = PF_INET;
+  else if (addr && addr->sa_family == AF_INET6)
+    domain = PF_INET6;
+  else if (addr)
+    return NULL;
+
+  /* fallback to direct discovery */
+#ifdef WIN32
+  sudp = socket (domain, SOCK_DGRAM, IPPROTO_UDP);
+#else
+  sudp = socket (domain, SOCK_DGRAM, 0);
+#endif
+  if (sudp < 0)
+    {
+      PRINT_SOCKET_ERROR ("socket");
+      return NULL;
+    }
+
+  if (domain == PF_INET)
+    {
+      /* receive */
+      memset (&sockudp_r, 0, sizeof (struct sockaddr_in));
+      sockudp_r.sin_family = AF_INET;
+#ifdef HAVE_SOCKADDR_IN_SIN_LEN
+      sockudp_r.sin_len = sizeof (struct sockaddr_in);
+#endif
+      if (sameport)
+        sockudp_r.sin_port = htons (PORT);
+      sockudp_r.sin_addr.s_addr = INADDR_ANY;
+      /* send */
+      memset (&sockudp_w, 0, sizeof (struct sockaddr_in));
+      sockudp_w.sin_family = AF_INET;
+      sockudp_w.sin_port = htons (PORT);
+      sockudp_w.sin_addr.s_addr = inet_addr (UPNP_MCAST_ADDR);
+#ifdef HAVE_SOCKADDR_IN_SIN_LEN
+      sockudp_w.sin_len = sizeof (struct sockaddr_in);
+#endif
+    }
+  else
+    {
+      /* receive */
+      memcpy (&sockudp6_r, addr, sizeof (struct sockaddr_in6));
+      if (sameport)
+        sockudp6_r.sin6_port = htons (PORT);
+      else
+        sockudp6_r.sin6_port = 0;
+      sockudp6_r.sin6_addr = any_addr;
+#ifdef HAVE_SOCKADDR_IN_SIN_LEN
+      sockudp6_r.sin6_len = sizeof (struct sockaddr_in6);
+#endif
+      /* send */
+      memset (&sockudp6_w, 0, sizeof (struct sockaddr_in6));
+      sockudp6_w.sin6_family = AF_INET6;
+      sockudp6_w.sin6_port = htons (PORT);
+      inet_pton (AF_INET6, UPNP_MCAST_ADDR6, &sockudp6_w.sin6_addr);
+#ifdef HAVE_SOCKADDR_IN_SIN_LEN
+      sockudp6_w.sin6_len = sizeof (struct sockaddr_in6);
+#endif
+    }
+
+#ifdef WIN32
+  if (setsockopt
+      (sudp, SOL_SOCKET, SO_REUSEADDR, (const char *) &opt, sizeof (opt)) < 0)
+#else
+  if (setsockopt (sudp, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)) < 0)
+#endif
+    {
+      PRINT_SOCKET_ERROR ("setsockopt");
+      return NULL;
+    }
+
+  if (addr)
+    {
+      if (domain == PF_INET)
+        {
+          sockudp_r.sin_addr.s_addr = ((struct sockaddr_in *) 
addr)->sin_addr.s_addr;
+          if (setsockopt
+              (sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *) 
&sockudp_r.sin_addr,
+               sizeof (struct in_addr)) < 0)
+            {
+              PRINT_SOCKET_ERROR ("setsockopt");
+            }
+
+          /* Bind to receive response before sending packet */
+          if (bind (sudp, (struct sockaddr *) &sockudp_r, sizeof (struct 
sockaddr_in))
+              != 0)
+            {
+              PRINT_SOCKET_ERROR ("bind");
+              closesocket (sudp);
+              return NULL;
+            }
+        }
+      else
+        {
+          if (multicastif && !(if_index = if_nametoindex (multicastif)))
+              PRINT_SOCKET_ERROR ("if_nametoindex");
+
+          if (setsockopt
+              (sudp, IPPROTO_IPV6, IPV6_MULTICAST_IF, &if_index, sizeof 
(if_index)) < 0)
+            {
+              PRINT_SOCKET_ERROR ("setsockopt");
+            }
+
+          /* Bind to receive response before sending packet */
+          memcpy (&sockudp6_r.sin6_addr, &((struct sockaddr_in6 *) 
addr)->sin6_addr,
+                  sizeof (sockudp6_r.sin6_addr));
+          if (bind (sudp, (struct sockaddr *) &sockudp6_r, sizeof (struct 
sockaddr_in6))
+              != 0)
+            {
+              PRINT_SOCKET_ERROR ("bind");
+              closesocket (sudp);
+              return NULL;
+            }
+        }
+    }
+
+  /* receiving SSDP response packet */
+  for (n = 0;;)
+    {
+      if (n == 0)
+        {
+          /* sending the SSDP M-SEARCH packet */
+          n = snprintf (bufr, sizeof (bufr),
+                        MSearchMsgFmt, deviceList[deviceIndex++]);
+          /*printf("Sending %s", bufr); */
+          if (domain == PF_INET)
+            n = sendto (sudp, bufr, n, 0,
+                        (struct sockaddr *) &sockudp_w,
+                        sizeof (struct sockaddr_in));
+          else
+            n = sendto (sudp, bufr, n, 0,
+                        (struct sockaddr *) &sockudp6_w,
+                        sizeof (struct sockaddr_in6));
+
+          if (n < 0)
+            {
+              PRINT_SOCKET_ERROR ("sendto");
+              closesocket (sudp);
+              return devlist;
+            }
+        }
+      /* Waiting for SSDP REPLY packet to M-SEARCH */
+      n = ReceiveData (sudp, bufr, sizeof (bufr), delay);
+
+      if (n < 0)
+        {
+          /* error */
+          closesocket (sudp);
+          return devlist;
+        }
+      else if (n == 0)
+        {
+          /* no data or Time Out */
+          if (devlist || (deviceList[deviceIndex] == 0))
+            {
+              /* no more device type to look for... */
+              closesocket (sudp);
+              return devlist;
+            }
+        }
+      else
+        {
+          const char *descURL = NULL;
+          int urlsize = 0;
+          const char *st = NULL;
+          int stsize = 0;
+          /*printf("%d byte(s) :\n%s\n", n, bufr); *//* affichage du message */
+          parseMSEARCHReply (bufr, n, &descURL, &urlsize, &st, &stsize);
+          if (st && descURL)
+            {
+              /*printf("M-SEARCH Reply:\nST: %.*s\nLocation: %.*s\n",
+                 stsize, st, urlsize, descURL); */
+              tmp =
+                (struct UPNPDev *) malloc (sizeof (struct UPNPDev) + urlsize +
+                                           stsize);
+              tmp->pNext = devlist;
+              tmp->descURL = tmp->buffer;
+              tmp->st = tmp->buffer + 1 + urlsize;
+              memcpy (tmp->buffer, descURL, urlsize);
+              tmp->buffer[urlsize] = '\0';
+              memcpy (tmp->buffer + urlsize + 1, st, stsize);
+              tmp->buffer[urlsize + 1 + stsize] = '\0';
+              devlist = tmp;
+            }
+        }
+    }
+}
+
+/* freeUPNPDevlist() should be used to
+ * free the chained list returned by upnpDiscover() */
+void
+freeUPNPDevlist (struct UPNPDev *devlist)
+{
+  struct UPNPDev *next;
+  while (devlist)
+    {
+      next = devlist->pNext;
+      free (devlist);
+      devlist = next;
+    }
+}
+
+static void
+url_cpy_or_cat (char *dst, const char *src, int n)
+{
+  if ((src[0] == 'h')
+      && (src[1] == 't')
+      && (src[2] == 't')
+      && (src[3] == 'p')
+      && (src[4] == ':') && (src[5] == '/') && (src[6] == '/'))
+    {
+      strncpy (dst, src, n);
+    }
+  else
+    {
+      int l = strlen (dst);
+      if (src[0] != '/')
+        dst[l++] = '/';
+      if (l <= n)
+        strncpy (dst + l, src, n - l);
+    }
+}
+
+/* Prepare the Urls for usage...
+ */
+void
+GetUPNPUrls (struct UPNPUrls *urls, struct IGDdatas *data,
+             const char *descURL)
+{
+  char *p;
+  int n1, n2, n3;
+  n1 = strlen (data->urlbase);
+  if (n1 == 0)
+    n1 = strlen (descURL);
+  n1 += 2;                      /* 1 byte more for Null terminator, 1 byte for 
'/' if needed */
+  n2 = n1;
+  n3 = n1;
+  n1 += strlen (data->scpdurl);
+  n2 += strlen (data->controlurl);
+  n3 += strlen (data->controlurl_CIF);
+
+  urls->ipcondescURL = (char *) malloc (n1);
+  urls->controlURL = (char *) malloc (n2);
+  urls->controlURL_CIF = (char *) malloc (n3);
+  /* maintenant on chope la desc du WANIPConnection */
+  if (data->urlbase[0] != '\0')
+    strncpy (urls->ipcondescURL, data->urlbase, n1);
+  else
+    strncpy (urls->ipcondescURL, descURL, n1);
+  p = strchr (urls->ipcondescURL + 7, '/');
+  if (p)
+    p[0] = '\0';
+  strncpy (urls->controlURL, urls->ipcondescURL, n2);
+  strncpy (urls->controlURL_CIF, urls->ipcondescURL, n3);
+
+  url_cpy_or_cat (urls->ipcondescURL, data->scpdurl, n1);
+
+  url_cpy_or_cat (urls->controlURL, data->controlurl, n2);
+
+  url_cpy_or_cat (urls->controlURL_CIF, data->controlurl_CIF, n3);
+
+#ifdef DEBUG
+  printf ("urls->ipcondescURL='%s' %d n1=%d\n", urls->ipcondescURL,
+          strlen (urls->ipcondescURL), n1);
+  printf ("urls->controlURL='%s' %d n2=%d\n", urls->controlURL,
+          strlen (urls->controlURL), n2);
+  printf ("urls->controlURL_CIF='%s' %d n3=%d\n", urls->controlURL_CIF,
+          strlen (urls->controlURL_CIF), n3);
+#endif
+}
+
+void
+FreeUPNPUrls (struct UPNPUrls *urls)
+{
+  if (!urls)
+    return;
+  free (urls->controlURL);
+  urls->controlURL = 0;
+  free (urls->ipcondescURL);
+  urls->ipcondescURL = 0;
+  free (urls->controlURL_CIF);
+  urls->controlURL_CIF = 0;
+}
+
+
+int
+ReceiveData (int socket, char *data, int length, int timeout)
+{
+  int n;
+#ifndef WIN32
+  struct pollfd fds[1];         /* for the poll */
+  fds[0].fd = socket;
+  fds[0].events = POLLIN;
+  n = poll (fds, 1, timeout);
+  if (n < 0)
+    {
+      PRINT_SOCKET_ERROR ("poll");
+      return -1;
+    }
+  else if (n == 0)
+    {
+      return 0;
+    }
+#else
+  fd_set socketSet;
+  TIMEVAL timeval;
+  FD_ZERO (&socketSet);
+  FD_SET (socket, &socketSet);
+  timeval.tv_sec = timeout / 1000;
+  timeval.tv_usec = (timeout % 1000) * 1000;
+  /*n = select(0, &socketSet, NULL, NULL, &timeval); */
+  n = select (FD_SETSIZE, &socketSet, NULL, NULL, &timeval);
+  if (n < 0)
+    {
+      PRINT_SOCKET_ERROR ("select");
+      return -1;
+    }
+  else if (n == 0)
+    {
+      return 0;
+    }
+#endif
+  n = recv (socket, data, length, 0);
+  if (n < 0)
+    {
+      PRINT_SOCKET_ERROR ("recv");
+    }
+  return n;
+}
+
+int
+UPNPIGD_IsConnected (struct UPNPUrls *urls, struct IGDdatas *data)
+{
+  char status[64];
+  unsigned int uptime;
+  status[0] = '\0';
+  UPNP_GetStatusInfo (urls->controlURL, data->servicetype,
+                      status, &uptime, NULL);
+  if (0 == strcmp ("Connected", status))
+    {
+      return 1;
+    }
+  else
+    return 0;
+}
+
+
+/* UPNP_GetValidIGD() :
+ * return values :
+ *     0 = NO IGD found
+ *     1 = A valid connected IGD has been found
+ *     2 = A valid IGD has been found but it reported as
+ *         not connected
+ *     3 = an UPnP device has been found but was not recognized as an IGD
+ *
+ * In any non zero return case, the urls and data structures
+ * passed as parameters are set. Donc forget to call FreeUPNPUrls(urls) to
+ * free allocated memory.
+ */
+int
+UPNP_GetValidIGD (struct UPNPDev *devlist,
+                  struct UPNPUrls *urls,
+                  struct IGDdatas *data, char *lanaddr, int lanaddrlen)
+{
+  char *descXML;
+  int descXMLsize = 0;
+  struct UPNPDev *dev;
+  int ndev = 0;
+  int state;                    /* state 1 : IGD connected. State 2 : IGD. 
State 3 : anything */
+  if (!devlist)
+    {
+#ifdef DEBUG
+      printf ("Empty devlist\n");
+#endif
+      return 0;
+    }
+  for (state = 1; state <= 3; state++)
+    {
+      for (dev = devlist; dev; dev = dev->pNext)
+        {
+          /* we should choose an internet gateway device.
+           * with st == urn:schemas-upnp-org:device:InternetGatewayDevice:1 */
+          descXML = miniwget_getaddr (dev->descURL, &descXMLsize,
+                                      lanaddr, lanaddrlen);
+          if (descXML)
+            {
+              ndev++;
+              memset (data, 0, sizeof (struct IGDdatas));
+              memset (urls, 0, sizeof (struct UPNPUrls));
+              parserootdesc (descXML, descXMLsize, data);
+              free (descXML);
+              descXML = NULL;
+              if (0 == strcmp (data->servicetype_CIF,
+                               
"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1")
+                  || state >= 3)
+                {
+                  GetUPNPUrls (urls, data, dev->descURL);
+
+#ifdef DEBUG
+                  printf ("UPNPIGD_IsConnected(%s) = %d\n",
+                          urls->controlURL, UPNPIGD_IsConnected (urls, data));
+#endif
+                  if ((state >= 2) || UPNPIGD_IsConnected (urls, data))
+                    return state;
+                  FreeUPNPUrls (urls);
+                }
+              memset (data, 0, sizeof (struct IGDdatas));
+            }
+#ifdef DEBUG
+          else
+            {
+              printf ("error getting XML description %s\n", dev->descURL);
+            }
+#endif
+        }
+    }
+  return 0;
+}
+
+/* UPNP_GetIGDFromUrl()
+ * Used when skipping the discovery process.
+ * return value :
+ *   0 - Not ok
+ *   1 - OK */
+int
+UPNP_GetIGDFromUrl (const char *rootdescurl,
+                    struct UPNPUrls *urls,
+                    struct IGDdatas *data, char *lanaddr, int lanaddrlen)
+{
+  char *descXML;
+  int descXMLsize = 0;
+  descXML = miniwget_getaddr (rootdescurl, &descXMLsize, lanaddr, lanaddrlen);
+  if (descXML)
+    {
+      memset (data, 0, sizeof (struct IGDdatas));
+      memset (urls, 0, sizeof (struct UPNPUrls));
+      parserootdesc (descXML, descXMLsize, data);
+      free (descXML);
+      descXML = NULL;
+      GetUPNPUrls (urls, data, rootdescurl);
+      return 1;
+    }
+  else
+    {
+      return 0;
+    }
+}

Added: gnunet/src/nat/miniupnp/miniupnpc.h
===================================================================
--- gnunet/src/nat/miniupnp/miniupnpc.h                         (rev 0)
+++ gnunet/src/nat/miniupnp/miniupnpc.h 2009-10-25 09:44:36 UTC (rev 9271)
@@ -0,0 +1,120 @@
+/* $Id: miniupnpc.h,v 1.18 2008/09/25 18:02:50 nanard Exp $ */
+/* Project: miniupnp
+ * http://miniupnp.free.fr/
+ * Author: Thomas Bernard
+ * Copyright (c) 2005-2006 Thomas Bernard
+ * This software is subjects to the conditions detailed
+ * in the LICENCE file provided within this distribution */
+#ifndef __MINIUPNPC_H__
+#define __MINIUPNPC_H__
+
+#include "declspec.h"
+#include "igd_desc_parse.h"
+
+#ifdef WIN32
+#include <winsock2.h>
+#else
+#include <sys/socket.h>
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* Structures definitions : */
+  struct UPNParg
+  {
+    const char *elt;
+    const char *val;
+  };
+
+  int simpleUPnPcommand (int s, const char *, const char *,
+                         const char *, struct UPNParg *, char *, int *);
+
+  struct UPNPDev
+  {
+    struct UPNPDev *pNext;
+    char *descURL;
+    char *st;
+    char buffer[2];
+  };
+
+/* upnpDiscover()
+ * discover UPnP devices on the network.
+ * The discovered devices are returned as a chained list.
+ * It is up to the caller to free the list with freeUPNPDevlist().
+ * delay (in millisecond) is the maximum time for waiting any device
+ * response.
+ * If available, device list will be obtained from MiniSSDPd.
+ * Default path for minissdpd socket will be used if minissdpdsock argument
+ * is NULL.
+ * If multicastif is not NULL, it will be used instead of the default
+ * multicast interface for sending SSDP discover packets.
+ * If sameport is not null, SSDP packets will be sent from the source port
+ * 1900 (same as destination port) otherwise system assign a source port. */
+  LIBSPEC struct UPNPDev *upnpDiscover (int delay, const char *multicastif, 
const struct sockaddr *addr,
+                                                     const char 
*minissdpdsock, int sameport);
+/* freeUPNPDevlist()
+ * free list returned by upnpDiscover() */
+  LIBSPEC void freeUPNPDevlist (struct UPNPDev *devlist);
+
+/* parserootdesc() :
+ * parse root XML description of a UPnP device and fill the IGDdatas
+ * structure. */
+  LIBSPEC void parserootdesc (const char *, int, struct IGDdatas *);
+
+/* structure used to get fast access to urls
+ * controlURL: controlURL of the WANIPConnection
+ * ipcondescURL: url of the description of the WANIPConnection
+ * controlURL_CIF: controlURL of the WANCommonInterfaceConfig
+ */
+  struct UPNPUrls
+  {
+    char *controlURL;
+    char *ipcondescURL;
+    char *controlURL_CIF;
+  };
+
+/* UPNP_GetValidIGD() :
+ * return values :
+ *     0 = NO IGD found
+ *     1 = A valid connected IGD has been found
+ *     2 = A valid IGD has been found but it reported as
+ *         not connected
+ *     3 = an UPnP device has been found but was not recognized as an IGD
+ *
+ * In any non zero return case, the urls and data structures
+ * passed as parameters are set. Donc forget to call FreeUPNPUrls(urls) to
+ * free allocated memory.
+ */
+  LIBSPEC int
+    UPNP_GetValidIGD (struct UPNPDev *devlist,
+                      struct UPNPUrls *urls,
+                      struct IGDdatas *data, char *lanaddr, int lanaddrlen);
+
+/* UPNP_GetIGDFromUrl()
+ * Used when skipping the discovery process.
+ * return value :
+ *   0 - Not ok
+ *   1 - OK */
+  LIBSPEC int
+    UPNP_GetIGDFromUrl (const char *rootdescurl,
+                        struct UPNPUrls *urls,
+                        struct IGDdatas *data, char *lanaddr, int lanaddrlen);
+
+  LIBSPEC void GetUPNPUrls (struct UPNPUrls *, struct IGDdatas *,
+                            const char *);
+
+  LIBSPEC void FreeUPNPUrls (struct UPNPUrls *);
+
+/* Reads data from the specified socket. 
+ * Returns the number of bytes read if successful, zero if no bytes were 
+ * read or if we timed out. Returns negative if there was an error. */
+  int ReceiveData (int socket, char *data, int length, int timeout);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

Added: gnunet/src/nat/miniupnp/miniupnpcstrings.h
===================================================================
--- gnunet/src/nat/miniupnp/miniupnpcstrings.h                          (rev 0)
+++ gnunet/src/nat/miniupnp/miniupnpcstrings.h  2009-10-25 09:44:36 UTC (rev 
9271)
@@ -0,0 +1,14 @@
+/* $Id: miniupnpcstrings.h,v 1.2 2008/10/14 17:39:04 nanard Exp $ */
+/* Project: miniupnp
+ * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
+ * Author: Thomas Bernard
+ * Copyright (c) 2005-2008 Thomas Bernard
+ * This software is subjects to the conditions detailed
+ * in the LICENCE file provided within this distribution */
+#ifndef __MINIUPNPCSTRINGS_H__
+#define __MINIUPNPCSTRINGS_H__
+
+#define OS_STRING "Debian/4.0"
+#define MINIUPNPC_VERSION_STRING "1.2"
+
+#endif

Added: gnunet/src/nat/miniupnp/miniwget.c
===================================================================
--- gnunet/src/nat/miniupnp/miniwget.c                          (rev 0)
+++ gnunet/src/nat/miniupnp/miniwget.c  2009-10-25 09:44:36 UTC (rev 9271)
@@ -0,0 +1,224 @@
+/* $Id: miniwget.c,v 1.22 2009/02/28 10:36:35 nanard Exp $ */
+/* Project : miniupnp
+ * Author : Thomas Bernard
+ * Copyright (c) 2005 Thomas Bernard
+ * This software is subject to the conditions detailed in the
+ * LICENCE file provided in this distribution.
+ * */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "miniupnpc.h"
+#ifdef WIN32
+#include <winsock2.h>
+#include <io.h>
+#define MAXHOSTNAMELEN 64
+#define MIN(x,y) (((x)<(y))?(x):(y))
+#define snprintf _snprintf
+#define herror
+#define socklen_t int
+#else
+#include <unistd.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#define closesocket close
+#endif
+#if defined(__sun) || defined(sun)
+#define MIN(x,y) (((x)<(y))?(x):(y))
+#endif
+
+#include "miniupnpcstrings.h"
+
+/* miniwget2() :
+ * */
+static void *
+miniwget2 (const char *url, const char *host,
+           unsigned short port, const char *path,
+           int *size, char *addr_str, int addr_str_len)
+{
+  char buf[2048];
+  int s;
+  struct sockaddr_in dest;
+  struct hostent *hp;
+  *size = 0;
+  hp = gethostbyname (host);
+  if (hp == NULL)
+    {
+      herror (host);
+      return NULL;
+    }
+  /*  memcpy((char *)&dest.sin_addr, hp->h_addr, hp->h_length);  */
+  memcpy (&dest.sin_addr, hp->h_addr, sizeof (dest.sin_addr));
+  memset (dest.sin_zero, 0, sizeof (dest.sin_zero));
+  s = socket (PF_INET, SOCK_STREAM, 0);
+  if (s < 0)
+    {
+      perror ("socket");
+      return NULL;
+    }
+  dest.sin_family = AF_INET;
+  dest.sin_port = htons (port);
+  if (connect (s, (struct sockaddr *) &dest, sizeof (struct sockaddr_in)) < 0)
+    {
+      perror ("connect");
+      closesocket (s);
+      return NULL;
+    }
+
+  /* get address for caller ! */
+  if (addr_str)
+    {
+      struct sockaddr_in saddr;
+      socklen_t len;
+
+      len = sizeof (saddr);
+      getsockname (s, (struct sockaddr *) &saddr, &len);
+#ifndef WIN32
+      inet_ntop (AF_INET, &saddr.sin_addr, addr_str, addr_str_len);
+#else
+      /* using INT WINAPI WSAAddressToStringA(LPSOCKADDR, DWORD, 
LPWSAPROTOCOL_INFOA, LPSTR, LPDWORD);
+       * But his function make a string with the port :  nn.nn.nn.nn:port */
+/*             if(WSAAddressToStringA((SOCKADDR *)&saddr, sizeof(saddr),
+                            NULL, addr_str, (DWORD *)&addr_str_len))
+               {
+                   printf("WSAAddressToStringA() failed : %d\n", 
WSAGetLastError());
+               }*/
+      strncpy (addr_str, inet_ntoa (saddr.sin_addr), addr_str_len);
+#endif
+#ifdef DEBUG
+      printf ("address miniwget : %s\n", addr_str);
+#endif
+    }
+
+  snprintf (buf, sizeof (buf),
+            "GET %s HTTP/1.1\r\n"
+            "Host: %s:%d\r\n"
+            "Connection: Close\r\n"
+            "User-Agent: " OS_STRING ", UPnP/1.0, MiniUPnPc/"
+            MINIUPNPC_VERSION_STRING "\r\n" "\r\n", path, host, port);
+  /*write(s, buf, strlen(buf)); */
+  send (s, buf, strlen (buf), 0);
+  {
+    int n, headers = 1;
+    char *respbuffer = NULL;
+    int allreadyread = 0;
+    /*while((n = recv(s, buf, 2048, 0)) > 0) */
+    while ((n = ReceiveData (s, buf, 2048, 5000)) > 0)
+      {
+        if (headers)
+          {
+            int i = 0;
+            while (i < n - 3)
+              {
+                if (buf[i] == '\r' && buf[i + 1] == '\n'
+                    && buf[i + 2] == '\r' && buf[i + 3] == '\n')
+                  {
+                    headers = 0;        /* end */
+                    if (i < n - 4)
+                      {
+                        respbuffer = (char *) realloc ((void *) respbuffer,
+                                                       allreadyread + (n - i -
+                                                                       4));
+                        memcpy (respbuffer + allreadyread, buf + i + 4,
+                                n - i - 4);
+                        allreadyread += (n - i - 4);
+                      }
+                    break;
+                  }
+                i++;
+              }
+          }
+        else
+          {
+            respbuffer = (char *) realloc ((void *) respbuffer,
+                                           allreadyread + n);
+            memcpy (respbuffer + allreadyread, buf, n);
+            allreadyread += n;
+          }
+      }
+    *size = allreadyread;
+#ifdef DEBUG
+    printf ("%d bytes read\n", *size);
+#endif
+    closesocket (s);
+    return respbuffer;
+  }
+}
+
+/* parseURL()
+ * arguments :
+ *   url :             source string not modified
+ *   hostname :        hostname destination string (size of MAXHOSTNAMELEN+1)
+ *   port :            port (destination)
+ *   path :            pointer to the path part of the URL 
+ *
+ * Return values :
+ *    0 - Failure
+ *    1 - Success         */
+int
+parseURL (const char *url, char *hostname, unsigned short *port, char **path)
+{
+  char *p1, *p2, *p3;
+  p1 = strstr (url, "://");
+  if (!p1)
+    return 0;
+  p1 += 3;
+  if ((url[0] != 'h') || (url[1] != 't')
+      || (url[2] != 't') || (url[3] != 'p'))
+    return 0;
+  p2 = strchr (p1, ':');
+  p3 = strchr (p1, '/');
+  if (!p3)
+    return 0;
+  memset (hostname, 0, MAXHOSTNAMELEN + 1);
+  if (!p2 || (p2 > p3))
+    {
+      strncpy (hostname, p1, MIN (MAXHOSTNAMELEN, (int) (p3 - p1)));
+      *port = 80;
+    }
+  else
+    {
+      strncpy (hostname, p1, MIN (MAXHOSTNAMELEN, (int) (p2 - p1)));
+      *port = 0;
+      p2++;
+      while ((*p2 >= '0') && (*p2 <= '9'))
+        {
+          *port *= 10;
+          *port += (unsigned short) (*p2 - '0');
+          p2++;
+        }
+    }
+  *path = p3;
+  return 1;
+}
+
+void *
+miniwget (const char *url, int *size)
+{
+  unsigned short port;
+  char *path;
+  /* protocol://host:port/chemin */
+  char hostname[MAXHOSTNAMELEN + 1];
+  *size = 0;
+  if (!parseURL (url, hostname, &port, &path))
+    return NULL;
+  return miniwget2 (url, hostname, port, path, size, 0, 0);
+}
+
+void *
+miniwget_getaddr (const char *url, int *size, char *addr, int addrlen)
+{
+  unsigned short port;
+  char *path;
+  /* protocol://host:port/chemin */
+  char hostname[MAXHOSTNAMELEN + 1];
+  *size = 0;
+  if (addr)
+    addr[0] = '\0';
+  if (!parseURL (url, hostname, &port, &path))
+    return NULL;
+  return miniwget2 (url, hostname, port, path, size, addr, addrlen);
+}

Added: gnunet/src/nat/miniupnp/miniwget.h
===================================================================
--- gnunet/src/nat/miniupnp/miniwget.h                          (rev 0)
+++ gnunet/src/nat/miniupnp/miniwget.h  2009-10-25 09:44:36 UTC (rev 9271)
@@ -0,0 +1,28 @@
+/* $Id: miniwget.h,v 1.5 2007/01/29 20:27:23 nanard Exp $ */
+/* Project : miniupnp
+ * Author : Thomas Bernard
+ * Copyright (c) 2005 Thomas Bernard
+ * This software is subject to the conditions detailed in the
+ * LICENCE file provided in this distribution.
+ * */
+#ifndef __MINIWGET_H__
+#define __MINIWGET_H__
+
+#include "declspec.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+  LIBSPEC void *miniwget (const char *, int *);
+
+  LIBSPEC void *miniwget_getaddr (const char *, int *, char *, int);
+
+  int parseURL (const char *, char *, unsigned short *, char **);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

Added: gnunet/src/nat/miniupnp/minixml.c
===================================================================
--- gnunet/src/nat/miniupnp/minixml.c                           (rev 0)
+++ gnunet/src/nat/miniupnp/minixml.c   2009-10-25 09:44:36 UTC (rev 9271)
@@ -0,0 +1,200 @@
+/* $Id: minixml.c,v 1.6 2007/05/15 18:14:08 nanard Exp $ */
+/* minixml.c : the minimum size a xml parser can be ! */
+/* Project : miniupnp
+ * webpage: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
+ * Author : Thomas Bernard
+
+Copyright (c) 2005-2007, Thomas BERNARD 
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+    * The name of the author may not be used to endorse or promote products
+         derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "minixml.h"
+
+/* parseatt : used to parse the argument list
+ * return 0 (false) in case of success and -1 (true) if the end
+ * of the xmlbuffer is reached. */
+int
+parseatt (struct xmlparser *p)
+{
+  const char *attname;
+  int attnamelen;
+  const char *attvalue;
+  int attvaluelen;
+  while (p->xml < p->xmlend)
+    {
+      if (*p->xml == '/' || *p->xml == '>')
+        return 0;
+      if (!IS_WHITE_SPACE (*p->xml))
+        {
+          char sep;
+          attname = p->xml;
+          attnamelen = 0;
+          while (*p->xml != '=' && !IS_WHITE_SPACE (*p->xml))
+            {
+              attnamelen++;
+              p->xml++;
+              if (p->xml >= p->xmlend)
+                return -1;
+            }
+          while (*(p->xml++) != '=')
+            {
+              if (p->xml >= p->xmlend)
+                return -1;
+            }
+          while (IS_WHITE_SPACE (*p->xml))
+            {
+              p->xml++;
+              if (p->xml >= p->xmlend)
+                return -1;
+            }
+          sep = *p->xml;
+          if (sep == '\'' || sep == '\"')
+            {
+              p->xml++;
+              if (p->xml >= p->xmlend)
+                return -1;
+              attvalue = p->xml;
+              attvaluelen = 0;
+              while (*p->xml != sep)
+                {
+                  attvaluelen++;
+                  p->xml++;
+                  if (p->xml >= p->xmlend)
+                    return -1;
+                }
+            }
+          else
+            {
+              attvalue = p->xml;
+              attvaluelen = 0;
+              while (!IS_WHITE_SPACE (*p->xml)
+                     && *p->xml != '>' && *p->xml != '/')
+                {
+                  attvaluelen++;
+                  p->xml++;
+                  if (p->xml >= p->xmlend)
+                    return -1;
+                }
+            }
+          /*printf("%.*s='%.*s'\n",
+             attnamelen, attname, attvaluelen, attvalue); */
+          if (p->attfunc)
+            p->attfunc (p->data, attname, attnamelen, attvalue, attvaluelen);
+        }
+      p->xml++;
+    }
+  return -1;
+}
+
+/* parseelt parse the xml stream and
+ * call the callback functions when needed... */
+void
+parseelt (struct xmlparser *p)
+{
+  int i;
+  const char *elementname;
+  while (p->xml < (p->xmlend - 1))
+    {
+      if ((p->xml)[0] == '<' && (p->xml)[1] != '?')
+        {
+          i = 0;
+          elementname = ++p->xml;
+          while (!IS_WHITE_SPACE (*p->xml)
+                 && (*p->xml != '>') && (*p->xml != '/'))
+            {
+              i++;
+              p->xml++;
+              if (p->xml >= p->xmlend)
+                return;
+              /* to ignore namespace : */
+              if (*p->xml == ':')
+                {
+                  i = 0;
+                  elementname = ++p->xml;
+                }
+            }
+          if (i > 0)
+            {
+              if (p->starteltfunc)
+                p->starteltfunc (p->data, elementname, i);
+              if (parseatt (p))
+                return;
+              if (*p->xml != '/')
+                {
+                  const char *data;
+                  i = 0;
+                  data = ++p->xml;
+                  if (p->xml >= p->xmlend)
+                    return;
+                  while (IS_WHITE_SPACE (*p->xml))
+                    {
+                      p->xml++;
+                      if (p->xml >= p->xmlend)
+                        return;
+                    }
+                  while (*p->xml != '<')
+                    {
+                      i++;
+                      p->xml++;
+                      if (p->xml >= p->xmlend)
+                        return;
+                    }
+                  if (i > 0 && p->datafunc)
+                    p->datafunc (p->data, data, i);
+                }
+            }
+          else if (*p->xml == '/')
+            {
+              i = 0;
+              elementname = ++p->xml;
+              if (p->xml >= p->xmlend)
+                return;
+              while ((*p->xml != '>'))
+                {
+                  i++;
+                  p->xml++;
+                  if (p->xml >= p->xmlend)
+                    return;
+                }
+              if (p->endeltfunc)
+                p->endeltfunc (p->data, elementname, i);
+              p->xml++;
+            }
+        }
+      else
+        {
+          p->xml++;
+        }
+    }
+}
+
+/* the parser must be initialized before calling this function */
+void
+parsexml (struct xmlparser *parser)
+{
+  parser->xml = parser->xmlstart;
+  parser->xmlend = parser->xmlstart + parser->xmlsize;
+  parseelt (parser);
+}

Added: gnunet/src/nat/miniupnp/minixml.h
===================================================================
--- gnunet/src/nat/miniupnp/minixml.h                           (rev 0)
+++ gnunet/src/nat/miniupnp/minixml.h   2009-10-25 09:44:36 UTC (rev 9271)
@@ -0,0 +1,37 @@
+/* $Id: minixml.h,v 1.6 2006/11/30 11:47:21 nanard Exp $ */
+/* minimal xml parser
+ *
+ * Project : miniupnp
+ * Website : http://miniupnp.free.fr/
+ * Author : Thomas Bernard
+ * Copyright (c) 2005 Thomas Bernard
+ * This software is subject to the conditions detailed in the
+ * LICENCE file provided in this distribution.
+ * */
+#ifndef __MINIXML_H__
+#define __MINIXML_H__
+#define IS_WHITE_SPACE(c) ((c==' ') || (c=='\t') || (c=='\r') || (c=='\n'))
+
+/* if a callback function pointer is set to NULL,
+ * the function is not called */
+struct xmlparser
+{
+  const char *xmlstart;
+  const char *xmlend;
+  const char *xml;              /* pointer to current character */
+  int xmlsize;
+  void *data;
+  void (*starteltfunc) (void *, const char *, int);
+  void (*endeltfunc) (void *, const char *, int);
+  void (*datafunc) (void *, const char *, int);
+  void (*attfunc) (void *, const char *, int, const char *, int);
+};
+
+/* parsexml()
+ * the xmlparser structure must be initialized before the call
+ * the following structure members have to be initialized :
+ * xmlstart, xmlsize, data, *func
+ * xml is for internal usage, xmlend is computed automatically */
+void parsexml (struct xmlparser *);
+
+#endif

Added: gnunet/src/nat/miniupnp/upnpcommands.c
===================================================================
--- gnunet/src/nat/miniupnp/upnpcommands.c                              (rev 0)
+++ gnunet/src/nat/miniupnp/upnpcommands.c      2009-10-25 09:44:36 UTC (rev 
9271)
@@ -0,0 +1,606 @@
+/* $Id: upnpcommands.c,v 1.24 2009/04/17 21:21:19 nanard Exp $ */
+/* Project : miniupnp
+ * Author : Thomas Bernard
+ * Copyright (c) 2005-2009 Thomas Bernard
+ * This software is subject to the conditions detailed in the
+ * LICENCE file provided in this distribution.
+ * */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "upnpcommands.h"
+#include "miniupnpc.h"
+
+static UNSIGNED_INTEGER
+my_atoui (const char *s)
+{
+  return s ? ((UNSIGNED_INTEGER) STRTOUI (s, NULL, 0)) : 0;
+}
+
+/*
+ * */
+UNSIGNED_INTEGER
+UPNP_GetTotalBytesSent (const char *controlURL, const char *servicetype)
+{
+  struct NameValueParserData pdata;
+  char buffer[4096];
+  int bufsize = 4096;
+  unsigned int r = 0;
+  char *p;
+  simpleUPnPcommand (-1, controlURL, servicetype, "GetTotalBytesSent", 0,
+                     buffer, &bufsize);
+  ParseNameValue (buffer, bufsize, &pdata);
+  /*DisplayNameValueList(buffer, bufsize); */
+  p = GetValueFromNameValueList (&pdata, "NewTotalBytesSent");
+  r = my_atoui (p);
+  ClearNameValueList (&pdata);
+  return r;
+}
+
+/*
+ * */
+UNSIGNED_INTEGER
+UPNP_GetTotalBytesReceived (const char *controlURL, const char *servicetype)
+{
+  struct NameValueParserData pdata;
+  char buffer[4096];
+  int bufsize = 4096;
+  unsigned int r = 0;
+  char *p;
+  simpleUPnPcommand (-1, controlURL, servicetype, "GetTotalBytesReceived", 0,
+                     buffer, &bufsize);
+  ParseNameValue (buffer, bufsize, &pdata);
+  /*DisplayNameValueList(buffer, bufsize); */
+  p = GetValueFromNameValueList (&pdata, "NewTotalBytesReceived");
+  r = my_atoui (p);
+  ClearNameValueList (&pdata);
+  return r;
+}
+
+/*
+ * */
+UNSIGNED_INTEGER
+UPNP_GetTotalPacketsSent (const char *controlURL, const char *servicetype)
+{
+  struct NameValueParserData pdata;
+  char buffer[4096];
+  int bufsize = 4096;
+  unsigned int r = 0;
+  char *p;
+  simpleUPnPcommand (-1, controlURL, servicetype, "GetTotalPacketsSent", 0,
+                     buffer, &bufsize);
+  ParseNameValue (buffer, bufsize, &pdata);
+  /*DisplayNameValueList(buffer, bufsize); */
+  p = GetValueFromNameValueList (&pdata, "NewTotalPacketsSent");
+  r = my_atoui (p);
+  ClearNameValueList (&pdata);
+  return r;
+}
+
+/*
+ * */
+UNSIGNED_INTEGER
+UPNP_GetTotalPacketsReceived (const char *controlURL, const char *servicetype)
+{
+  struct NameValueParserData pdata;
+  char buffer[4096];
+  int bufsize = 4096;
+  unsigned int r = 0;
+  char *p;
+  simpleUPnPcommand (-1, controlURL, servicetype, "GetTotalPacketsReceived",
+                     0, buffer, &bufsize);
+  ParseNameValue (buffer, bufsize, &pdata);
+  /*DisplayNameValueList(buffer, bufsize); */
+  p = GetValueFromNameValueList (&pdata, "NewTotalPacketsReceived");
+  r = my_atoui (p);
+  ClearNameValueList (&pdata);
+  return r;
+}
+
+/* UPNP_GetStatusInfo() call the corresponding UPNP method
+ * returns the current status and uptime */
+int
+UPNP_GetStatusInfo (const char *controlURL,
+                    const char *servicetype,
+                    char *status, unsigned int *uptime, char *lastconnerror)
+{
+  struct NameValueParserData pdata;
+  char buffer[4096];
+  int bufsize = 4096;
+  char *p;
+  char *up;
+  char *err;
+  int ret = UPNPCOMMAND_UNKNOWN_ERROR;
+
+  if (!status && !uptime)
+    return UPNPCOMMAND_INVALID_ARGS;
+
+  simpleUPnPcommand (-1, controlURL, servicetype, "GetStatusInfo", 0, buffer,
+                     &bufsize);
+  ParseNameValue (buffer, bufsize, &pdata);
+  /*DisplayNameValueList(buffer, bufsize); */
+  up = GetValueFromNameValueList (&pdata, "NewUptime");
+  p = GetValueFromNameValueList (&pdata, "NewConnectionStatus");
+  err = GetValueFromNameValueList (&pdata, "NewLastConnectionError");
+  if (p && up)
+    ret = UPNPCOMMAND_SUCCESS;
+
+  if (status)
+    {
+      if (p)
+        {
+          strncpy (status, p, 64);
+          status[63] = '\0';
+        }
+      else
+        status[0] = '\0';
+    }
+
+  if (uptime)
+    {
+      if (up)
+        sscanf (up, "%u", uptime);
+      else
+        uptime = 0;
+    }
+
+  if (lastconnerror)
+    {
+      if (err)
+        {
+          strncpy (lastconnerror, err, 64);
+          lastconnerror[63] = '\0';
+        }
+      else
+        lastconnerror[0] = '\0';
+    }
+
+  p = GetValueFromNameValueList (&pdata, "errorCode");
+  if (p)
+    {
+      ret = UPNPCOMMAND_UNKNOWN_ERROR;
+      sscanf (p, "%d", &ret);
+    }
+  ClearNameValueList (&pdata);
+  return ret;
+}
+
+/* UPNP_GetConnectionTypeInfo() call the corresponding UPNP method
+ * returns the connection type */
+int
+UPNP_GetConnectionTypeInfo (const char *controlURL,
+                            const char *servicetype, char *connectionType)
+{
+  struct NameValueParserData pdata;
+  char buffer[4096];
+  int bufsize = 4096;
+  char *p;
+  int ret = UPNPCOMMAND_UNKNOWN_ERROR;
+
+  if (!connectionType)
+    return UPNPCOMMAND_INVALID_ARGS;
+
+  simpleUPnPcommand (-1, controlURL, servicetype,
+                     "GetConnectionTypeInfo", 0, buffer, &bufsize);
+  ParseNameValue (buffer, bufsize, &pdata);
+  p = GetValueFromNameValueList (&pdata, "NewConnectionType");
+  /*p = GetValueFromNameValueList(&pdata, "NewPossibleConnectionTypes"); */
+  /* PossibleConnectionTypes will have several values.... */
+  if (p)
+    {
+      strncpy (connectionType, p, 64);
+      connectionType[63] = '\0';
+      ret = UPNPCOMMAND_SUCCESS;
+    }
+  else
+    connectionType[0] = '\0';
+  p = GetValueFromNameValueList (&pdata, "errorCode");
+  if (p)
+    {
+      ret = UPNPCOMMAND_UNKNOWN_ERROR;
+      sscanf (p, "%d", &ret);
+    }
+  ClearNameValueList (&pdata);
+  return ret;
+}
+
+/* UPNP_GetLinkLayerMaxBitRate() call the corresponding UPNP method.
+ * Returns 2 values: Downloadlink bandwidth and Uplink bandwidth.
+ * One of the values can be null 
+ * Note : GetLinkLayerMaxBitRates belongs to WANPPPConnection:1 only 
+ * We can use the GetCommonLinkProperties from WANCommonInterfaceConfig:1 */
+int
+UPNP_GetLinkLayerMaxBitRates (const char *controlURL, const char *servicetype,
+                              unsigned int *bitrateDown,
+                              unsigned int *bitrateUp)
+{
+  struct NameValueParserData pdata;
+  char buffer[4096];
+  int bufsize = 4096;
+  int ret = UPNPCOMMAND_UNKNOWN_ERROR;
+  char *down;
+  char *up;
+  char *p;
+
+  if (!bitrateDown && !bitrateUp)
+    return UPNPCOMMAND_INVALID_ARGS;
+
+  /* shouldn't we use GetCommonLinkProperties ? */
+  simpleUPnPcommand (-1, controlURL, servicetype,
+                     "GetCommonLinkProperties", 0, buffer, &bufsize);
+  /*"GetLinkLayerMaxBitRates", 0, buffer, &bufsize); */
+  /*DisplayNameValueList(buffer, bufsize); */
+  ParseNameValue (buffer, bufsize, &pdata);
+  /*down = GetValueFromNameValueList(&pdata, "NewDownstreamMaxBitRate"); */
+  /*up = GetValueFromNameValueList(&pdata, "NewUpstreamMaxBitRate"); */
+  down = GetValueFromNameValueList (&pdata, "NewLayer1DownstreamMaxBitRate");
+  up = GetValueFromNameValueList (&pdata, "NewLayer1UpstreamMaxBitRate");
+  /*GetValueFromNameValueList(&pdata, "NewWANAccessType"); */
+  /*GetValueFromNameValueList(&pdata, "NewPhysicalLinkSatus"); */
+  if (down && up)
+    ret = UPNPCOMMAND_SUCCESS;
+
+  if (bitrateDown)
+    {
+      if (down)
+        sscanf (down, "%u", bitrateDown);
+      else
+        *bitrateDown = 0;
+    }
+
+  if (bitrateUp)
+    {
+      if (up)
+        sscanf (up, "%u", bitrateUp);
+      else
+        *bitrateUp = 0;
+    }
+  p = GetValueFromNameValueList (&pdata, "errorCode");
+  if (p)
+    {
+      ret = UPNPCOMMAND_UNKNOWN_ERROR;
+      sscanf (p, "%d", &ret);
+    }
+  ClearNameValueList (&pdata);
+  return ret;
+}
+
+
+/* UPNP_GetExternalIPAddress() call the corresponding UPNP method.
+ * if the third arg is not null the value is copied to it.
+ * at least 128 bytes must be available
+ * 
+ * Return values :
+ * 0 : SUCCESS
+ * NON ZERO : ERROR Either an UPnP error code or an unknown error.
+ *
+ * 402 Invalid Args - See UPnP Device Architecture section on Control.
+ * 501 Action Failed - See UPnP Device Architecture section on Control.
+ */
+int
+UPNP_GetExternalIPAddress (const char *controlURL,
+                           const char *servicetype, char *extIpAdd)
+{
+  struct NameValueParserData pdata;
+  char buffer[4096];
+  int bufsize = 4096;
+  char *p;
+  int ret = UPNPCOMMAND_UNKNOWN_ERROR;
+
+  if (!extIpAdd || !controlURL || !servicetype)
+    return UPNPCOMMAND_INVALID_ARGS;
+
+  simpleUPnPcommand (-1, controlURL, servicetype, "GetExternalIPAddress", 0,
+                     buffer, &bufsize);
+  /*DisplayNameValueList(buffer, bufsize); */
+  ParseNameValue (buffer, bufsize, &pdata);
+  /*printf("external ip = %s\n", GetValueFromNameValueList(&pdata, 
"NewExternalIPAddress") ); */
+  p = GetValueFromNameValueList (&pdata, "NewExternalIPAddress");
+  if (p)
+    {
+      strncpy (extIpAdd, p, 128);
+      extIpAdd[127] = '\0';
+      ret = UPNPCOMMAND_SUCCESS;
+    }
+  else
+    extIpAdd[0] = '\0';
+
+  p = GetValueFromNameValueList (&pdata, "errorCode");
+  if (p)
+    {
+      ret = UPNPCOMMAND_UNKNOWN_ERROR;
+      sscanf (p, "%d", &ret);
+    }
+
+  ClearNameValueList (&pdata);
+  return ret;
+}
+
+int
+UPNP_AddPortMapping (const char *controlURL, const char *servicetype,
+                     const char *extPort,
+                     const char *inPort,
+                     const char *inClient,
+                     const char *desc,
+                     const char *proto, const char *remoteHost)
+{
+  struct UPNParg *AddPortMappingArgs;
+  char buffer[4096];
+  int bufsize = 4096;
+  struct NameValueParserData pdata;
+  const char *resVal;
+  int ret;
+
+  if (!inPort || !inClient || !proto || !extPort)
+    return UPNPCOMMAND_INVALID_ARGS;
+
+  AddPortMappingArgs = calloc (9, sizeof (struct UPNParg));
+  AddPortMappingArgs[0].elt = "NewRemoteHost";
+  AddPortMappingArgs[0].val = remoteHost;
+  AddPortMappingArgs[1].elt = "NewExternalPort";
+  AddPortMappingArgs[1].val = extPort;
+  AddPortMappingArgs[2].elt = "NewProtocol";
+  AddPortMappingArgs[2].val = proto;
+  AddPortMappingArgs[3].elt = "NewInternalPort";
+  AddPortMappingArgs[3].val = inPort;
+  AddPortMappingArgs[4].elt = "NewInternalClient";
+  AddPortMappingArgs[4].val = inClient;
+  AddPortMappingArgs[5].elt = "NewEnabled";
+  AddPortMappingArgs[5].val = "1";
+  AddPortMappingArgs[6].elt = "NewPortMappingDescription";
+  AddPortMappingArgs[6].val = desc ? desc : "libminiupnpc";
+  AddPortMappingArgs[7].elt = "NewLeaseDuration";
+  AddPortMappingArgs[7].val = "0";
+  simpleUPnPcommand (-1, controlURL, servicetype, "AddPortMapping",
+                     AddPortMappingArgs, buffer, &bufsize);
+  /*DisplayNameValueList(buffer, bufsize); */
+  /*buffer[bufsize] = '\0'; */
+  /*puts(buffer); */
+  ParseNameValue (buffer, bufsize, &pdata);
+  resVal = GetValueFromNameValueList (&pdata, "errorCode");
+  if (resVal)
+    {
+      /* printf("AddPortMapping errorCode = '%s'\n", resVal); */
+      ret = UPNPCOMMAND_UNKNOWN_ERROR;
+      sscanf (resVal, "%d", &ret);
+    }
+  else
+    {
+      ret = UPNPCOMMAND_SUCCESS;
+    }
+  ClearNameValueList (&pdata);
+  free (AddPortMappingArgs);
+  return ret;
+}
+
+int
+UPNP_DeletePortMapping (const char *controlURL, const char *servicetype,
+                        const char *extPort, const char *proto,
+                        const char *remoteHost)
+{
+  /*struct NameValueParserData pdata; */
+  struct UPNParg *DeletePortMappingArgs;
+  char buffer[4096];
+  int bufsize = 4096;
+  struct NameValueParserData pdata;
+  const char *resVal;
+  int ret;
+
+  if (!extPort || !proto)
+    return UPNPCOMMAND_INVALID_ARGS;
+
+  DeletePortMappingArgs = calloc (4, sizeof (struct UPNParg));
+  DeletePortMappingArgs[0].elt = "NewRemoteHost";
+  DeletePortMappingArgs[0].val = remoteHost;
+  DeletePortMappingArgs[1].elt = "NewExternalPort";
+  DeletePortMappingArgs[1].val = extPort;
+  DeletePortMappingArgs[2].elt = "NewProtocol";
+  DeletePortMappingArgs[2].val = proto;
+  simpleUPnPcommand (-1, controlURL, servicetype,
+                     "DeletePortMapping",
+                     DeletePortMappingArgs, buffer, &bufsize);
+  /*DisplayNameValueList(buffer, bufsize); */
+  ParseNameValue (buffer, bufsize, &pdata);
+  resVal = GetValueFromNameValueList (&pdata, "errorCode");
+  if (resVal)
+    {
+      ret = UPNPCOMMAND_UNKNOWN_ERROR;
+      sscanf (resVal, "%d", &ret);
+    }
+  else
+    {
+      ret = UPNPCOMMAND_SUCCESS;
+    }
+  ClearNameValueList (&pdata);
+  free (DeletePortMappingArgs);
+  return ret;
+}
+
+int
+UPNP_GetGenericPortMappingEntry (const char *controlURL,
+                                 const char *servicetype,
+                                 const char *index,
+                                 char *extPort,
+                                 char *intClient,
+                                 char *intPort,
+                                 char *protocol,
+                                 char *desc,
+                                 char *enabled, char *rHost, char *duration)
+{
+  struct NameValueParserData pdata;
+  struct UPNParg *GetPortMappingArgs;
+  char buffer[4096];
+  int bufsize = 4096;
+  char *p;
+  int r = UPNPCOMMAND_UNKNOWN_ERROR;
+  if (!index)
+    return UPNPCOMMAND_INVALID_ARGS;
+  intClient[0] = '\0';
+  intPort[0] = '\0';
+  GetPortMappingArgs = calloc (2, sizeof (struct UPNParg));
+  GetPortMappingArgs[0].elt = "NewPortMappingIndex";
+  GetPortMappingArgs[0].val = index;
+  simpleUPnPcommand (-1, controlURL, servicetype,
+                     "GetGenericPortMappingEntry",
+                     GetPortMappingArgs, buffer, &bufsize);
+  ParseNameValue (buffer, bufsize, &pdata);
+  p = GetValueFromNameValueList (&pdata, "NewRemoteHost");
+  if (p && rHost)
+    {
+      strncpy (rHost, p, 64);
+      rHost[63] = '\0';
+    }
+  p = GetValueFromNameValueList (&pdata, "NewExternalPort");
+  if (p && extPort)
+    {
+      strncpy (extPort, p, 6);
+      extPort[5] = '\0';
+      r = UPNPCOMMAND_SUCCESS;
+    }
+  p = GetValueFromNameValueList (&pdata, "NewProtocol");
+  if (p && protocol)
+    {
+      strncpy (protocol, p, 4);
+      protocol[3] = '\0';
+    }
+  p = GetValueFromNameValueList (&pdata, "NewInternalClient");
+  if (p && intClient)
+    {
+      strncpy (intClient, p, 128);
+      intClient[127] = '\0';
+      r = 0;
+    }
+  p = GetValueFromNameValueList (&pdata, "NewInternalPort");
+  if (p && intPort)
+    {
+      strncpy (intPort, p, 6);
+      intPort[5] = '\0';
+    }
+  p = GetValueFromNameValueList (&pdata, "NewEnabled");
+  if (p && enabled)
+    {
+      strncpy (enabled, p, 4);
+      enabled[3] = '\0';
+    }
+  p = GetValueFromNameValueList (&pdata, "NewPortMappingDescription");
+  if (p && desc)
+    {
+      strncpy (desc, p, 80);
+      desc[79] = '\0';
+    }
+  p = GetValueFromNameValueList (&pdata, "NewLeaseDuration");
+  if (p && duration)
+    {
+      strncpy (duration, p, 16);
+      duration[15] = '\0';
+    }
+  p = GetValueFromNameValueList (&pdata, "errorCode");
+  if (p)
+    {
+      r = UPNPCOMMAND_UNKNOWN_ERROR;
+      sscanf (p, "%d", &r);
+    }
+  ClearNameValueList (&pdata);
+  free (GetPortMappingArgs);
+  return r;
+}
+
+int
+UPNP_GetPortMappingNumberOfEntries (const char *controlURL,
+                                    const char *servicetype,
+                                    unsigned int *numEntries)
+{
+  struct NameValueParserData pdata;
+  char buffer[4096];
+  int bufsize = 4096;
+  char *p;
+  int ret = UPNPCOMMAND_UNKNOWN_ERROR;
+  simpleUPnPcommand (-1, controlURL, servicetype,
+                     "GetPortMappingNumberOfEntries", 0, buffer, &bufsize);
+#ifdef DEBUG
+  DisplayNameValueList (buffer, bufsize);
+#endif
+  ParseNameValue (buffer, bufsize, &pdata);
+
+  p = GetValueFromNameValueList (&pdata, "NewPortMappingNumberOfEntries");
+  if (numEntries && p)
+    {
+      *numEntries = 0;
+      sscanf (p, "%u", numEntries);
+      ret = UPNPCOMMAND_SUCCESS;
+    }
+
+  p = GetValueFromNameValueList (&pdata, "errorCode");
+  if (p)
+    {
+      ret = UPNPCOMMAND_UNKNOWN_ERROR;
+      sscanf (p, "%d", &ret);
+    }
+
+  ClearNameValueList (&pdata);
+  return ret;
+}
+
+/* UPNP_GetSpecificPortMappingEntry retrieves an existing port mapping
+ * the result is returned in the intClient and intPort strings
+ * please provide 128 and 6 bytes of data */
+int
+UPNP_GetSpecificPortMappingEntry (const char *controlURL,
+                                  const char *servicetype,
+                                  const char *extPort,
+                                  const char *proto,
+                                  char *intClient, char *intPort)
+{
+  struct NameValueParserData pdata;
+  struct UPNParg *GetPortMappingArgs;
+  char buffer[4096];
+  int bufsize = 4096;
+  char *p;
+  int ret = UPNPCOMMAND_UNKNOWN_ERROR;
+
+  if (!intPort || !intClient || !extPort || !proto)
+    return UPNPCOMMAND_INVALID_ARGS;
+
+  GetPortMappingArgs = calloc (4, sizeof (struct UPNParg));
+  GetPortMappingArgs[0].elt = "NewRemoteHost";
+  GetPortMappingArgs[1].elt = "NewExternalPort";
+  GetPortMappingArgs[1].val = extPort;
+  GetPortMappingArgs[2].elt = "NewProtocol";
+  GetPortMappingArgs[2].val = proto;
+  simpleUPnPcommand (-1, controlURL, servicetype,
+                     "GetSpecificPortMappingEntry",
+                     GetPortMappingArgs, buffer, &bufsize);
+  /*fd = simpleUPnPcommand(fd, controlURL, data.servicetype, 
"GetSpecificPortMappingEntry", AddPortMappingArgs, buffer, &bufsize); */
+  /*DisplayNameValueList(buffer, bufsize); */
+  ParseNameValue (buffer, bufsize, &pdata);
+
+  p = GetValueFromNameValueList (&pdata, "NewInternalClient");
+  if (p)
+    {
+      strncpy (intClient, p, 128);
+      intClient[127] = '\0';
+      ret = UPNPCOMMAND_SUCCESS;
+    }
+  else
+    intClient[0] = '\0';
+
+  p = GetValueFromNameValueList (&pdata, "NewInternalPort");
+  if (p)
+    {
+      strncpy (intPort, p, 6);
+      intPort[5] = '\0';
+    }
+  else
+    intPort[0] = '\0';
+
+  p = GetValueFromNameValueList (&pdata, "errorCode");
+  if (p)
+    {
+      ret = UPNPCOMMAND_UNKNOWN_ERROR;
+      sscanf (p, "%d", &ret);
+    }
+
+  ClearNameValueList (&pdata);
+  free (GetPortMappingArgs);
+  return ret;
+}

Added: gnunet/src/nat/miniupnp/upnpcommands.h
===================================================================
--- gnunet/src/nat/miniupnp/upnpcommands.h                              (rev 0)
+++ gnunet/src/nat/miniupnp/upnpcommands.h      2009-10-25 09:44:36 UTC (rev 
9271)
@@ -0,0 +1,189 @@
+/* $Id: upnpcommands.h,v 1.17 2009/04/17 21:21:19 nanard Exp $ */
+/* Miniupnp project : http://miniupnp.free.fr/
+ * Author : Thomas Bernard
+ * Copyright (c) 2005-2008 Thomas Bernard
+ * This software is subject to the conditions detailed in the
+ * LICENCE file provided within this distribution */
+#ifndef __UPNPCOMMANDS_H__
+#define __UPNPCOMMANDS_H__
+
+#include "upnpreplyparse.h"
+#include "declspec.h"
+
+/* MiniUPnPc return codes : */
+#define UPNPCOMMAND_SUCCESS (0)
+#define UPNPCOMMAND_UNKNOWN_ERROR (-1)
+#define UPNPCOMMAND_INVALID_ARGS (-2)
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#if (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L)
+#define UNSIGNED_INTEGER unsigned long long
+#define STRTOUI        strtoull
+#else
+#define UNSIGNED_INTEGER unsigned int
+#define STRTOUI        strtoul
+#endif
+
+  LIBSPEC UNSIGNED_INTEGER
+    UPNP_GetTotalBytesSent (const char *controlURL, const char *servicetype);
+
+  LIBSPEC UNSIGNED_INTEGER
+    UPNP_GetTotalBytesReceived (const char *controlURL,
+                                const char *servicetype);
+
+  LIBSPEC UNSIGNED_INTEGER
+    UPNP_GetTotalPacketsSent (const char *controlURL,
+                              const char *servicetype);
+
+  LIBSPEC UNSIGNED_INTEGER
+    UPNP_GetTotalPacketsReceived (const char *controlURL,
+                                  const char *servicetype);
+
+/* UPNP_GetStatusInfo()
+ * status and lastconnerror are 64 byte buffers
+ * Return values :
+ * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR
+ * or a UPnP Error code */
+  LIBSPEC int
+    UPNP_GetStatusInfo (const char *controlURL,
+                        const char *servicetype,
+                        char *status,
+                        unsigned int *uptime, char *lastconnerror);
+
+/* UPNP_GetConnectionTypeInfo()
+ * argument connectionType is a 64 character buffer
+ * Return Values :
+ * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR
+ * or a UPnP Error code */
+  LIBSPEC int
+    UPNP_GetConnectionTypeInfo (const char *controlURL,
+                                const char *servicetype,
+                                char *connectionType);
+
+/* UPNP_GetExternalIPAddress() call the corresponding UPNP method.
+ * if the third arg is not null the value is copied to it.
+ * at least 128 bytes must be available 
+ *
+ * Return values :
+ * 0 : SUCCESS
+ * NON ZERO : ERROR Either an UPnP error code or an unknown error.
+ * 
+ * possible UPnP Errors :
+ * 402 Invalid Args - See UPnP Device Architecture section on Control.
+ * 501 Action Failed - See UPnP Device Architecture section on Control. */
+  LIBSPEC int
+    UPNP_GetExternalIPAddress (const char *controlURL,
+                               const char *servicetype, char *extIpAdd);
+
+/* UPNP_GetLinkLayerMaxBitRates()
+ * call WANCommonInterfaceConfig:1#GetCommonLinkProperties
+ *
+ * return values :
+ * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR
+ * or a UPnP Error Code. */
+  LIBSPEC int
+    UPNP_GetLinkLayerMaxBitRates (const char *controlURL,
+                                  const char *servicetype,
+                                  unsigned int *bitrateDown,
+                                  unsigned int *bitrateUp);
+
+/* UPNP_AddPortMapping()
+ * if desc is NULL, it will be defaulted to "libminiupnpc"
+ * remoteHost is usually NULL because IGD don't support it.
+ *
+ * Return values :
+ * 0 : SUCCESS
+ * NON ZERO : ERROR. Either an UPnP error code or an unknown error.
+ * 
+ * List of possible UPnP errors for AddPortMapping :
+ * errorCode errorDescription (short) - Description (long)
+ * 402 Invalid Args - See UPnP Device Architecture section on Control.
+ * 501 Action Failed - See UPnP Device Architecture section on Control.
+ * 715 WildCardNotPermittedInSrcIP - The source IP address cannot be
+ *                                   wild-carded
+ * 716 WildCardNotPermittedInExtPort - The external port cannot be wild-carded
+ * 718 ConflictInMappingEntry - The port mapping entry specified conflicts
+ *                     with a mapping assigned previously to another client
+ * 724 SamePortValuesRequired - Internal and External port values
+ *                              must be the same 
+ * 725 OnlyPermanentLeasesSupported - The NAT implementation only supports
+ *                  permanent lease times on port mappings
+ * 726 RemoteHostOnlySupportsWildcard - RemoteHost must be a wildcard
+ *                             and cannot be a specific IP address or DNS name
+ * 727 ExternalPortOnlySupportsWildcard - ExternalPort must be a wildcard and
+ *                                        cannot be a specific port value */
+  LIBSPEC int
+    UPNP_AddPortMapping (const char *controlURL, const char *servicetype,
+                         const char *extPort,
+                         const char *inPort,
+                         const char *inClient,
+                         const char *desc,
+                         const char *proto, const char *remoteHost);
+
+/* UPNP_DeletePortMapping()
+ * Use same argument values as what was used for AddPortMapping().
+ * remoteHost is usually NULL because IGD don't support it.
+ * Return Values :
+ * 0 : SUCCESS
+ * NON ZERO : error. Either an UPnP error code or an undefined error.
+ *
+ * List of possible UPnP errors for DeletePortMapping :
+ * 402 Invalid Args - See UPnP Device Architecture section on Control.
+ * 714 NoSuchEntryInArray - The specified value does not exist in the array */
+  LIBSPEC int
+    UPNP_DeletePortMapping (const char *controlURL, const char *servicetype,
+                            const char *extPort, const char *proto,
+                            const char *remoteHost);
+
+/* UPNP_GetPortMappingNumberOfEntries()
+ * not supported by all routers */
+  LIBSPEC int
+    UPNP_GetPortMappingNumberOfEntries (const char *controlURL,
+                                        const char *servicetype,
+                                        unsigned int *num);
+
+/* UPNP_GetSpecificPortMappingEntry retrieves an existing port mapping
+ * the result is returned in the intClient and intPort strings
+ * please provide 128 and 6 bytes of data
+ *
+ * return value :
+ * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR
+ * or a UPnP Error Code. */
+  LIBSPEC int
+    UPNP_GetSpecificPortMappingEntry (const char *controlURL,
+                                      const char *servicetype,
+                                      const char *extPort,
+                                      const char *proto,
+                                      char *intClient, char *intPort);
+
+/* UPNP_GetGenericPortMappingEntry()
+ *
+ * return value :
+ * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR
+ * or a UPnP Error Code.
+ *
+ * Possible UPNP Error codes :
+ * 402 Invalid Args - See UPnP Device Architecture section on Control.
+ * 713 SpecifiedArrayIndexInvalid - The specified array index is out of bounds
+ */
+  LIBSPEC int
+    UPNP_GetGenericPortMappingEntry (const char *controlURL,
+                                     const char *servicetype,
+                                     const char *index,
+                                     char *extPort,
+                                     char *intClient,
+                                     char *intPort,
+                                     char *protocol,
+                                     char *desc,
+                                     char *enabled,
+                                     char *rHost, char *duration);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

Added: gnunet/src/nat/miniupnp/upnpreplyparse.c
===================================================================
--- gnunet/src/nat/miniupnp/upnpreplyparse.c                            (rev 0)
+++ gnunet/src/nat/miniupnp/upnpreplyparse.c    2009-10-25 09:44:36 UTC (rev 
9271)
@@ -0,0 +1,122 @@
+/* $Id: upnpreplyparse.c,v 1.10 2008/02/21 13:05:27 nanard Exp $ */
+/* MiniUPnP project
+ * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
+ * (c) 2006 Thomas Bernard 
+ * This software is subject to the conditions detailed
+ * in the LICENCE file provided within the distribution */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "upnpreplyparse.h"
+#include "minixml.h"
+
+static void
+NameValueParserStartElt (void *d, const char *name, int l)
+{
+  struct NameValueParserData *data = (struct NameValueParserData *) d;
+  if (l > 63)
+    l = 63;
+  memcpy (data->curelt, name, l);
+  data->curelt[l] = '\0';
+}
+
+static void
+NameValueParserGetData (void *d, const char *datas, int l)
+{
+  struct NameValueParserData *data = (struct NameValueParserData *) d;
+  struct NameValue *nv;
+  nv = malloc (sizeof (struct NameValue));
+  if (l > 63)
+    l = 63;
+  strncpy (nv->name, data->curelt, 64);
+  nv->name[63] = '\0';
+  memcpy (nv->value, datas, l);
+  nv->value[l] = '\0';
+  LIST_INSERT_HEAD (&(data->head), nv, entries);
+}
+
+void
+ParseNameValue (const char *buffer, int bufsize,
+                struct NameValueParserData *data)
+{
+  struct xmlparser parser;
+  LIST_INIT (&(data->head));
+  /* init xmlparser object */
+  parser.xmlstart = buffer;
+  parser.xmlsize = bufsize;
+  parser.data = data;
+  parser.starteltfunc = NameValueParserStartElt;
+  parser.endeltfunc = 0;
+  parser.datafunc = NameValueParserGetData;
+  parser.attfunc = 0;
+  parsexml (&parser);
+}
+
+void
+ClearNameValueList (struct NameValueParserData *pdata)
+{
+  struct NameValue *nv;
+  while ((nv = pdata->head.lh_first) != NULL)
+    {
+      LIST_REMOVE (nv, entries);
+      free (nv);
+    }
+}
+
+char *
+GetValueFromNameValueList (struct NameValueParserData *pdata,
+                           const char *Name)
+{
+  struct NameValue *nv;
+  char *p = NULL;
+  for (nv = pdata->head.lh_first;
+       (nv != NULL) && (p == NULL); nv = nv->entries.le_next)
+    {
+      if (strcmp (nv->name, Name) == 0)
+        p = nv->value;
+    }
+  return p;
+}
+
+#if 0
+/* useless now that minixml ignores namespaces by itself */
+char *
+GetValueFromNameValueListIgnoreNS (struct NameValueParserData *pdata,
+                                   const char *Name)
+{
+  struct NameValue *nv;
+  char *p = NULL;
+  char *pname;
+  for (nv = pdata->head.lh_first;
+       (nv != NULL) && (p == NULL); nv = nv->entries.le_next)
+    {
+      pname = strrchr (nv->name, ':');
+      if (pname)
+        pname++;
+      else
+        pname = nv->name;
+      if (strcmp (pname, Name) == 0)
+        p = nv->value;
+    }
+  return p;
+}
+#endif
+
+/* debug all-in-one function 
+ * do parsing then display to stdout */
+#ifdef DEBUG
+void
+DisplayNameValueList (char *buffer, int bufsize)
+{
+  struct NameValueParserData pdata;
+  struct NameValue *nv;
+  ParseNameValue (buffer, bufsize, &pdata);
+  for (nv = pdata.head.lh_first; nv != NULL; nv = nv->entries.le_next)
+    {
+      printf ("%s = %s\n", nv->name, nv->value);
+    }
+  ClearNameValueList (&pdata);
+}
+#endif

Added: gnunet/src/nat/miniupnp/upnpreplyparse.h
===================================================================
--- gnunet/src/nat/miniupnp/upnpreplyparse.h                            (rev 0)
+++ gnunet/src/nat/miniupnp/upnpreplyparse.h    2009-10-25 09:44:36 UTC (rev 
9271)
@@ -0,0 +1,60 @@
+/* $Id: upnpreplyparse.h,v 1.8 2008/02/21 13:05:27 nanard Exp $ */
+/* MiniUPnP project
+ * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
+ * (c) 2006 Thomas Bernard 
+ * This software is subject to the conditions detailed
+ * in the LICENCE file provided within the distribution */
+
+#ifndef __UPNPREPLYPARSE_H__
+#define __UPNPREPLYPARSE_H__
+
+#if defined(NO_SYS_QUEUE_H) || defined(WIN32)
+#include "bsdqueue.h"
+#else
+#include <sys/queue.h>
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+  struct NameValue
+  {
+    LIST_ENTRY (NameValue) entries;
+    char name[64];
+    char value[64];
+  };
+
+  struct NameValueParserData
+  {
+    LIST_HEAD (listhead, NameValue) head;
+    char curelt[64];
+  };
+
+/* ParseNameValue() */
+  void
+    ParseNameValue (const char *buffer, int bufsize,
+                    struct NameValueParserData *data);
+
+/* ClearNameValueList() */
+  void ClearNameValueList (struct NameValueParserData *pdata);
+
+/* GetValueFromNameValueList() */
+  char *GetValueFromNameValueList (struct NameValueParserData *pdata,
+                                   const char *Name);
+
+/* GetValueFromNameValueListIgnoreNS() */
+  char *GetValueFromNameValueListIgnoreNS (struct NameValueParserData *pdata,
+                                           const char *Name);
+
+/* DisplayNameValueList() */
+#ifdef DEBUG
+  void DisplayNameValueList (char *buffer, int bufsize);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

Added: gnunet/src/nat/nat.c
===================================================================
--- gnunet/src/nat/nat.c                                (rev 0)
+++ gnunet/src/nat/nat.c        2009-10-25 09:44:36 UTC (rev 9271)
@@ -0,0 +1,375 @@
+/*
+     This file is part of GNUnet.
+     (C) 2009 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 2, 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.
+*/
+
+/*
+ * Parts of this file have been adapted from the Transmission project:
+ * Originally licensed by the GPL version 2.
+ * Copyright (C) 2007-2009 Charles Kerr <address@hidden>
+ */
+
+/**
+ * @file nat/nat.c
+ * @brief Library handling UPnP and NAT-PMP port forwarding and
+ *     external IP address retrieval
+ *
+ * @author Milan Bouchet-Valat
+ */
+
+#ifdef __cplusplus
+extern "C"
+{
+#if 0                           /* keep Emacsens' auto-indent happy */
+}
+#endif
+#endif
+
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <sys/types.h>
+
+#include "platform.h"
+#include "gnunet_common.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_nat_lib.h"
+#include "natpmp.h"
+#include "upnp.h"
+
+/* Component name for logging */
+#define COMP_NAT _("NAT")
+#define DEBUG
+
+struct GNUNET_NAT_Handle
+{
+  int is_enabled;
+
+  GNUNET_NAT_port_forwarding natpmp_status;
+  GNUNET_NAT_port_forwarding upnp_status;
+
+  int should_change;
+  u_short public_port;
+
+  GNUNET_NAT_UPNP_Handle *upnp;
+  GNUNET_NAT_NATPMP_Handle *natpmp;
+
+  struct GNUNET_SCHEDULER_Handle *sched;
+  GNUNET_SCHEDULER_TaskIdentifier pulse_timer;
+
+  struct sockaddr *local_addr; /* LAN address as passed by the caller */
+  struct sockaddr *ext_addr; /* External address as reported by NAT box */
+  struct sockaddr *contact_addr; /* External address and port where paquets 
are redirected*/
+  GNUNET_NAT_AddressCallback callback;
+  void *callback_cls;
+};
+
+#ifdef DEBUG
+static const char *
+get_nat_state_str (int state)
+{
+  switch (state)
+    {
+      /* we're in the process of trying to set up port forwarding */
+    case GNUNET_NAT_PORT_MAPPING:
+      return "Starting";
+
+      /* we've successfully forwarded the port */
+    case GNUNET_NAT_PORT_MAPPED:
+      return "Forwarded";
+
+      /* we're cancelling the port forwarding */
+    case GNUNET_NAT_PORT_UNMAPPING:
+      return "Stopping";
+
+      /* the port isn't forwarded */
+    case GNUNET_NAT_PORT_UNMAPPED:
+      return "Not forwarded";
+
+    case GNUNET_NAT_PORT_ERROR:
+      return "Redirection failed";
+    }
+
+  return "notfound";
+}
+#endif
+
+static int
+get_traversal_status (const GNUNET_NAT_Handle * s)
+{
+  return MAX (s->natpmp_status, s->upnp_status);
+}
+
+/**
+ * Compare the sin(6)_addr fields of AF_INET or AF_INET(6) sockaddr.
+ * @param a first sockaddr
+ * @param second sockaddr
+ * @returns 0 if addresses are equal, non-null value otherwise */
+int
+GNUNET_NAT_cmp_addr (const struct sockaddr *a, const struct sockaddr *b)
+{
+  if (!(a && b))
+    return -1;
+
+  if (a->sa_family == AF_INET && b->sa_family == AF_INET)
+    return memcmp (&(((struct sockaddr_in *) a)->sin_addr),
+                   &(((struct sockaddr_in *) b)->sin_addr),
+                   sizeof (struct in_addr));
+  else if (a->sa_family == AF_INET6 && b->sa_family == AF_INET6)
+    return memcmp (&(((struct sockaddr_in6 *) a)->sin6_addr),
+                   &(((struct sockaddr_in6 *) b)->sin6_addr),
+                   sizeof (struct in6_addr));
+  else
+    return -1;
+}
+
+/* Deal with a new IP address or port redirection:
+ * Send signals with the appropriate sockaddr (IP and port), free and changes
+ * or nullify the previous sockaddr. Change the port if needed.
+ */
+static void
+notify_change (GNUNET_NAT_Handle *nat, struct sockaddr *addr, int 
new_port_mapped)
+{
+  static int port_mapped = GNUNET_NO;
+
+  /* Nothing to do. We already check in nat_pulse() that addr has changed */
+  if (new_port_mapped == port_mapped)
+    return;
+
+  port_mapped = new_port_mapped;
+
+  if (nat->contact_addr && nat->callback)
+    (*nat->callback) (nat->callback_cls, GNUNET_NO, (struct sockaddr *) 
&nat->contact_addr,
+                      sizeof (nat->contact_addr));
+
+  /* At this point, we're sure contact_addr has changed */
+  if (nat->contact_addr)
+    {
+      GNUNET_free (nat->contact_addr);
+      nat->contact_addr = NULL;
+    }
+
+  /* No address, don't signal a new one */
+  if (!addr)
+    {
+      if (nat->ext_addr)
+        GNUNET_free (nat->ext_addr);
+      nat->ext_addr = NULL;
+      return;
+    }
+  /* Copy the new address and use it */
+  else if (addr != nat->ext_addr)
+    {
+      if (nat->ext_addr)
+        GNUNET_free (nat->ext_addr);
+      nat->ext_addr = GNUNET_malloc (sizeof (*addr));
+      memcpy (nat->ext_addr, addr, sizeof (*addr));
+    }
+
+  /* Recreate the ext_addr:public_port bogus address to pass to the callback */
+  if (nat->ext_addr->sa_family == AF_INET)
+    {
+      struct sockaddr_in *tmp_addr;
+      tmp_addr = GNUNET_malloc (sizeof (struct sockaddr_in));
+      tmp_addr->sin_family = AF_INET;
+#ifdef HAVE_SOCKADDR_IN_SIN_LEN
+      tmp_addr->sin_len = sizeof (struct sockaddr_in);
+#endif
+      tmp_addr->sin_port = port_mapped ? htons (nat->public_port) : 0;
+      tmp_addr->sin_addr = ((struct sockaddr_in *) nat->ext_addr)->sin_addr;
+      nat->contact_addr = (struct sockaddr *) tmp_addr;
+      if (nat->callback)
+        (*nat->callback) (nat->callback_cls, GNUNET_YES, nat->contact_addr,
+                          sizeof (struct sockaddr_in));
+    }
+  else if (nat->ext_addr->sa_family == AF_INET6)
+    {
+      struct sockaddr_in6 *tmp_addr;
+      tmp_addr = GNUNET_malloc (sizeof (struct sockaddr_in6));
+      tmp_addr->sin6_family = AF_INET6;
+#ifdef HAVE_SOCKADDR_IN_SIN_LEN
+      tmp_addr->sin6_len = sizeof (struct sockaddr_in6);
+#endif
+      tmp_addr->sin6_port = port_mapped ? htons (nat->public_port) : 0;
+      tmp_addr->sin6_addr = ((struct sockaddr_in6 *) nat->ext_addr)->sin6_addr;
+      nat->contact_addr = (struct sockaddr *) tmp_addr;
+      if (nat->callback)
+        (*nat->callback) (nat->callback_cls, GNUNET_YES, nat->contact_addr,
+                          sizeof (struct sockaddr_in6));
+    }
+}
+
+static void
+nat_pulse (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  GNUNET_NAT_Handle *nat = cls;
+  static int first_warning = GNUNET_YES;
+  int old_status;
+  int new_status;
+  int port_mapped;
+  struct sockaddr *ext_addr_upnp = NULL;
+  struct sockaddr *ext_addr_natpmp = NULL;
+
+  old_status = get_traversal_status (nat);
+
+  /* Only update the protocol that has been successful until now */
+  if (nat->upnp_status >= GNUNET_NAT_PORT_UNMAPPED)
+    nat->upnp_status =
+      GNUNET_NAT_UPNP_pulse (nat->upnp, nat->is_enabled, GNUNET_YES,
+                             &ext_addr_upnp);
+  else if (nat->natpmp_status >= GNUNET_NAT_PORT_UNMAPPED)
+    nat->natpmp_status =
+      GNUNET_NAT_NATPMP_pulse (nat->natpmp, nat->is_enabled,
+                               &ext_addr_natpmp);
+  else
+    {
+      nat->upnp_status =
+        GNUNET_NAT_UPNP_pulse (nat->upnp, nat->is_enabled, GNUNET_YES,
+                               &ext_addr_upnp);
+      nat->natpmp_status =
+        GNUNET_NAT_NATPMP_pulse (nat->natpmp, nat->is_enabled,
+                                 &ext_addr_natpmp);
+    }
+
+  new_status = get_traversal_status (nat);
+
+  if (old_status != new_status &&
+     (new_status == GNUNET_NAT_PORT_UNMAPPED || new_status == 
GNUNET_NAT_PORT_ERROR))
+    GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, COMP_NAT,
+                     _("Port redirection failed: no UPnP or NAT-PMP routers 
supporting this feature found\n"));
+
+#ifdef DEBUG
+  if (new_status != old_status)
+    GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, COMP_NAT,
+                     _("State changed from \"%s\" to \"%s\"\n"),
+                     get_nat_state_str (old_status),
+                     get_nat_state_str (new_status));
+#endif
+
+  port_mapped = (new_status == GNUNET_NAT_PORT_MAPPED);
+  if (!(ext_addr_upnp || ext_addr_natpmp))
+    {
+      /* Address has just changed and we could not get it, or it's the first 
try */
+      if (nat->ext_addr || first_warning)
+        {
+          GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, COMP_NAT,
+                      _("Could not determine external IP address\n"));
+          first_warning = GNUNET_NO;
+        }
+
+      notify_change (nat, NULL, port_mapped);
+    }
+  else if (ext_addr_upnp && GNUNET_NAT_cmp_addr (nat->ext_addr, ext_addr_upnp) 
!= 0)
+    {
+      GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, COMP_NAT,
+                  _("External IP address changed from %s to %s\n"),
+                  GNUNET_a2s (nat->ext_addr, sizeof (nat->ext_addr)),
+                  GNUNET_a2s (ext_addr_upnp, sizeof (ext_addr_upnp)));
+
+      notify_change (nat, ext_addr_upnp, port_mapped);
+    }
+  else if (ext_addr_natpmp && GNUNET_NAT_cmp_addr (nat->ext_addr, 
ext_addr_natpmp) != 0)
+    {
+      GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, COMP_NAT,
+                  _("External IP address changed from %s to %s\n"),
+                  GNUNET_a2s (nat->ext_addr, sizeof (nat->ext_addr)),
+                  GNUNET_a2s (ext_addr_natpmp, sizeof (ext_addr_natpmp)));
+
+      notify_change (nat, ext_addr_natpmp, port_mapped);
+    }
+
+  nat->pulse_timer = GNUNET_SCHEDULER_add_delayed (nat->sched, GNUNET_NO,
+                                                   
GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+                                                   GNUNET_SCHEDULER_NO_TASK,
+                                                   GNUNET_TIME_UNIT_SECONDS,
+                                                   &nat_pulse, nat);
+}
+
+struct GNUNET_NAT_Handle *
+GNUNET_NAT_register (struct GNUNET_SCHEDULER_Handle *sched,
+                     const struct sockaddr *addr, socklen_t addrlen,
+                     GNUNET_NAT_AddressCallback callback, void *callback_cls)
+{
+  GNUNET_NAT_Handle *nat = GNUNET_malloc (sizeof (GNUNET_NAT_Handle));
+
+  if (addr)
+    {
+      GNUNET_assert (addr->sa_family == AF_INET
+                     || addr->sa_family == AF_INET6);
+      if (addr->sa_family == AF_INET)
+        {
+          nat->public_port = ntohs (((struct sockaddr_in *) addr)->sin_port);
+//          ((struct sockaddr_in *) addr)->sin_port = 0;
+        }
+      else if (addr->sa_family == AF_INET6)
+        {
+          nat->public_port = ntohs (((struct sockaddr_in6 *) addr)->sin6_port);
+//          ((struct sockaddr_in6 *) addr)->sin6_port = 0;
+        }
+    }
+
+  nat->should_change = GNUNET_YES;
+  nat->sched = sched;
+  nat->is_enabled = GNUNET_YES;
+  nat->upnp_status = GNUNET_NAT_PORT_UNMAPPED;
+  nat->natpmp_status = GNUNET_NAT_PORT_UNMAPPED;
+  nat->callback = callback;
+  nat->callback_cls = callback_cls;
+  nat->ext_addr = NULL;
+  nat->contact_addr = NULL;
+  nat->local_addr = GNUNET_malloc (addrlen);
+  memcpy (nat->local_addr, addr, addrlen);
+  nat->natpmp = GNUNET_NAT_NATPMP_init (nat->local_addr, addrlen, 
nat->public_port);
+  nat->upnp = GNUNET_NAT_UPNP_init (nat->local_addr, addrlen, 
nat->public_port);
+
+  nat->pulse_timer = GNUNET_SCHEDULER_add_delayed (sched, GNUNET_NO,
+                                                   
GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+                                                   GNUNET_SCHEDULER_NO_TASK,
+                                                   GNUNET_TIME_UNIT_SECONDS,
+                                                   &nat_pulse, nat);
+
+  return nat;
+}
+
+void
+GNUNET_NAT_unregister (struct GNUNET_NAT_Handle *nat)
+{
+  struct sockaddr *addr;
+  GNUNET_SCHEDULER_cancel (nat->sched, nat->pulse_timer);
+
+  nat->upnp_status =
+    GNUNET_NAT_UPNP_pulse (nat->upnp, GNUNET_NO, GNUNET_NO,
+                           &addr);
+  nat->natpmp_status =
+    GNUNET_NAT_NATPMP_pulse (nat->natpmp, GNUNET_NO,
+                             &addr);
+
+  GNUNET_NAT_NATPMP_close (nat->natpmp);
+  GNUNET_NAT_UPNP_close (nat->upnp);
+  if (nat->ext_addr)
+    GNUNET_free (nat->ext_addr);
+  GNUNET_free (nat);
+}
+
+#if 0                           /* keep Emacsens' auto-indent happy */
+{
+#endif
+#ifdef __cplusplus
+}
+#endif

Added: gnunet/src/nat/natpmp.c
===================================================================
--- gnunet/src/nat/natpmp.c                             (rev 0)
+++ gnunet/src/nat/natpmp.c     2009-10-25 09:44:36 UTC (rev 9271)
@@ -0,0 +1,297 @@
+/*
+     This file is part of GNUnet.
+     (C) 2009 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 2, 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.
+*/
+
+/*
+ * This file has been adapted from the Transmission project:
+ * Originally licensed by the GPL version 2.
+ * Copyright (C) 2007-2009 Charles Kerr <address@hidden>
+ */
+
+/**
+ * @file nat/natpmp.c
+ * @brief NAT-PMP support for the NAT library
+ *
+ * @author Milan Bouchet-Valat
+ */
+
+#ifdef __cplusplus
+extern "C"
+{
+#if 0                           /* keep Emacsens' auto-indent happy */
+}
+#endif
+#endif
+
+#include <assert.h>
+#include <errno.h>
+#include <time.h>
+#include <inttypes.h>
+
+#define ENABLE_STRNATPMPERR
+#include <libnatpmp/natpmp.h>
+
+#include "platform.h"
+#include "gnunet_common.h"
+#include "gnunet_nat_lib.h"
+#include "natpmp.h"
+
+#define LIFETIME_SECS 3600
+#define COMMAND_WAIT_SECS 8
+/* Component name for logging */
+#define COMP_NAT_NATPMP _("NAT (NAT-PMP))")
+
+typedef enum
+{
+  NATPMP_IDLE,
+  NATPMP_ERR,
+  NATPMP_DISCOVER,
+  NATPMP_RECV_PUB,
+  NATPMP_SEND_MAP,
+  NATPMP_RECV_MAP,
+  NATPMP_SEND_UNMAP,
+  NATPMP_RECV_UNMAP
+}
+NATPMP_state;
+
+struct GNUNET_NAT_NATPMP_Handle
+{
+  const struct sockaddr *addr;
+  socklen_t addrlen;
+  int is_mapped;
+  int has_discovered;
+  int port;
+  time_t renew_time;
+  time_t command_time;
+  NATPMP_state state;
+  natpmp_t natpmp;
+};
+
+/**
+***
+**/
+
+static void
+log_val (const char *func, int ret)
+{
+#ifdef DEBUG
+  if (ret == NATPMP_TRYAGAIN)
+    GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, COMP_NAT_NATPMP, _("%s retry 
(%d)\n"), func, ret);
+//    return;
+  if (ret >= 0)
+    GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, COMP_NAT_NATPMP, _("%s succeeded 
(%d)\n"), func, ret);
+  else
+    GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, COMP_NAT_NATPMP,
+                "%s failed.  natpmp returned %d (%s); errno is %d (%s)\n",
+                func, ret, strnatpmperr (ret), errno, strerror (errno));
+#else
+  return;
+#endif
+}
+
+struct GNUNET_NAT_NATPMP_Handle *
+GNUNET_NAT_NATPMP_init (const struct sockaddr *addr, socklen_t addrlen,
+                        u_short port)
+{
+  struct GNUNET_NAT_NATPMP_Handle *nat;
+
+  nat = GNUNET_malloc (sizeof (struct GNUNET_NAT_NATPMP_Handle));
+  nat->state = NATPMP_DISCOVER;
+  nat->port = port;
+  nat->addr = addr;
+  nat->addrlen = addrlen;
+  return nat;
+}
+
+void
+GNUNET_NAT_NATPMP_close (GNUNET_NAT_NATPMP_Handle * nat)
+{
+  if (nat)
+    {
+      closenatpmp (&nat->natpmp);
+      GNUNET_free (nat);
+    }
+}
+
+static int
+can_send_command (const struct GNUNET_NAT_NATPMP_Handle *nat)
+{
+  return time (NULL) >= nat->command_time;
+}
+
+static void
+set_command_time (struct GNUNET_NAT_NATPMP_Handle *nat)
+{
+  nat->command_time = time (NULL) + COMMAND_WAIT_SECS;
+}
+
+int
+GNUNET_NAT_NATPMP_pulse (struct GNUNET_NAT_NATPMP_Handle *nat, int is_enabled,
+                         struct sockaddr **ext_addr)
+{
+  int ret;
+
+  /* Keep to NULL if address could not be found */
+  *ext_addr = NULL;
+
+  if (is_enabled && (nat->state == NATPMP_DISCOVER))
+    {
+      int val = initnatpmp (&nat->natpmp);
+      log_val ("initnatpmp", val);
+      val = sendpublicaddressrequest (&nat->natpmp);
+      log_val ("sendpublicaddressrequest", val);
+      nat->state = val < 0 ? NATPMP_ERR : NATPMP_RECV_PUB;
+      nat->has_discovered = 1;
+      set_command_time (nat);
+    }
+
+  if ((nat->state == NATPMP_RECV_PUB) && can_send_command (nat))
+    {
+      natpmpresp_t response;
+      const int val = readnatpmpresponseorretry (&nat->natpmp,
+                                                 &response);
+      log_val ("readnatpmpresponseorretry", val);
+      if (val >= 0)
+        {
+          *ext_addr =
+            GNUNET_malloc (sizeof (response.pnu.publicaddress.addr));
+          memcpy (*ext_addr, &response.pnu.publicaddress.addr,
+                  (sizeof (response.pnu.publicaddress.addr)));
+#ifdef DEBUG
+          GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, COMP_NAT_NATPMP,
+                      _("Found public IP address %s\n"),
+                      GNUNET_a2s (*ext_addr, sizeof (*ext_addr)));
+#endif
+          nat->state = NATPMP_IDLE;
+        }
+      else if (val != NATPMP_TRYAGAIN)
+        {
+          nat->state = NATPMP_ERR;
+        }
+    }
+
+  if ((nat->state == NATPMP_IDLE) || (nat->state == NATPMP_ERR))
+    {
+      if (nat->is_mapped && !is_enabled)
+        nat->state = NATPMP_SEND_UNMAP;
+    }
+
+  if ((nat->state == NATPMP_SEND_UNMAP) && can_send_command (nat))
+    {
+      const int val =
+        sendnewportmappingrequest (&nat->natpmp, NATPMP_PROTOCOL_TCP,
+                                   nat->port, nat->port,
+                                   0);
+      log_val ("sendnewportmappingrequest", val);
+      nat->state = val < 0 ? NATPMP_ERR : NATPMP_RECV_UNMAP;
+      set_command_time (nat);
+    }
+
+  if (nat->state == NATPMP_RECV_UNMAP)
+    {
+      natpmpresp_t resp;
+      const int val = readnatpmpresponseorretry (&nat->natpmp, &resp);
+      log_val ("readnatpmpresponseorretry", val);
+      if (val >= 0)
+        {
+          const int p = resp.pnu.newportmapping.privateport;
+          GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, COMP_NAT_NATPMP,
+                      _("No longer forwarding port %d\n"), p);
+          if (nat->port == p)
+            {
+              nat->port = -1;
+              nat->state = NATPMP_IDLE;
+              nat->is_mapped = 0;
+            }
+        }
+      else if (val != NATPMP_TRYAGAIN)
+        {
+          nat->state = NATPMP_ERR;
+        }
+    }
+
+  if (nat->state == NATPMP_IDLE)
+    {
+      if (is_enabled && !nat->is_mapped && nat->has_discovered)
+        nat->state = NATPMP_SEND_MAP;
+
+      else if (nat->is_mapped && time (NULL) >= nat->renew_time)
+        nat->state = NATPMP_SEND_MAP;
+    }
+
+  if ((nat->state == NATPMP_SEND_MAP) && can_send_command (nat))
+    {
+      const int val =
+        sendnewportmappingrequest (&nat->natpmp, NATPMP_PROTOCOL_TCP,
+                                   nat->port,
+                                   nat->port,
+                                   LIFETIME_SECS);
+      log_val ("sendnewportmappingrequest", val);
+      nat->state = val < 0 ? NATPMP_ERR : NATPMP_RECV_MAP;
+      set_command_time (nat);
+    }
+
+  if (nat->state == NATPMP_RECV_MAP)
+    {
+      natpmpresp_t resp;
+      const int val = readnatpmpresponseorretry (&nat->natpmp, &resp);
+      log_val ("readnatpmpresponseorretry", val);
+      if (val >= 0)
+        {
+          nat->state = NATPMP_IDLE;
+          nat->is_mapped = 1;
+          nat->renew_time = time (NULL) + LIFETIME_SECS;
+          nat->port = resp.pnu.newportmapping.privateport;
+          GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, COMP_NAT_NATPMP,
+                      _("Port %d forwarded successfully\n"), nat->port);
+        }
+      else if (val != NATPMP_TRYAGAIN)
+        {
+          nat->state = NATPMP_ERR;
+        }
+    }
+
+  switch (nat->state)
+    {
+    case NATPMP_IDLE:
+      ret =
+        nat->is_mapped ? GNUNET_NAT_PORT_MAPPED : GNUNET_NAT_PORT_UNMAPPED;
+      break;
+
+    case NATPMP_DISCOVER:
+      ret = GNUNET_NAT_PORT_UNMAPPED;
+      break;
+
+    case NATPMP_RECV_PUB:
+    case NATPMP_SEND_MAP:
+    case NATPMP_RECV_MAP:
+      ret = GNUNET_NAT_PORT_MAPPING;
+      break;
+
+    case NATPMP_SEND_UNMAP:
+    case NATPMP_RECV_UNMAP:
+      ret = GNUNET_NAT_PORT_UNMAPPING;
+      break;
+
+    default:
+      ret = GNUNET_NAT_PORT_ERROR;
+      break;
+    }
+  return ret;
+}

Added: gnunet/src/nat/natpmp.h
===================================================================
--- gnunet/src/nat/natpmp.h                             (rev 0)
+++ gnunet/src/nat/natpmp.h     2009-10-25 09:44:36 UTC (rev 9271)
@@ -0,0 +1,44 @@
+/*
+     This file is part of GNUnet.
+     (C) 2009 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 2, 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.
+*/
+
+/**
+ * @file nat/natpmp.h
+ * @brief NAT-PMP support for the NAT library
+ *
+ * @author Milan Bouchet-Valat
+ */
+
+#ifndef NATPMP_H
+#define NATPMP_H 1
+
+#include "platform.h"
+
+typedef struct GNUNET_NAT_NATPMP_Handle GNUNET_NAT_NATPMP_Handle;
+
+GNUNET_NAT_NATPMP_Handle *GNUNET_NAT_NATPMP_init (const struct sockaddr *addr,
+                                                  socklen_t addrlen,
+                                                  unsigned short port);
+
+void GNUNET_NAT_NATPMP_close (GNUNET_NAT_NATPMP_Handle * nat);
+
+int GNUNET_NAT_NATPMP_pulse (GNUNET_NAT_NATPMP_Handle * nat, int is_enabled,
+                             struct sockaddr **ext_addr);
+
+#endif /* NATPMP_H */

Added: gnunet/src/nat/upnp.c
===================================================================
--- gnunet/src/nat/upnp.c                               (rev 0)
+++ gnunet/src/nat/upnp.c       2009-10-25 09:44:36 UTC (rev 9271)
@@ -0,0 +1,357 @@
+/*
+     This file is part of GNUnet.
+     (C) 2009 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 2, 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.
+*/
+
+/*
+ * This file has been adapted from the Transmission project:
+ * Originally licensed by the GPL version 2.
+ * Copyright (C) 2007-2009 Charles Kerr <address@hidden>
+ */
+
+/**
+ * @file nat/upnp.c
+ * @brief UPnP support for the NAT library
+ *
+ * @author Milan Bouchet-Valat
+ */
+
+#ifdef __cplusplus
+extern "C"
+{
+#if 0                           /* keep Emacsens' auto-indent happy */
+}
+#endif
+#endif
+
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <miniupnp/miniupnpc.h>
+#include <miniupnp/upnpcommands.h>
+
+#include "platform.h"
+#include "gnunet_common.h"
+#include "gnunet_nat_lib.h"
+#include "upnp.h"
+
+/* Component name for logging */
+#define COMP_NAT_UPNP _("NAT (UPnP)")
+
+typedef enum
+{
+  UPNP_IDLE,
+  UPNP_ERR,
+  UPNP_DISCOVER,
+  UPNP_MAP,
+  UPNP_UNMAP
+}
+UPNP_state;
+
+struct GNUNET_NAT_UPNP_Handle
+{
+  int hasDiscovered;
+  struct UPNPUrls urls;
+  struct IGDdatas data;
+  int port;
+  const struct sockaddr *addr;
+  socklen_t addrlen;
+  unsigned int is_mapped;
+  UPNP_state state;
+  struct sockaddr *ext_addr;
+  const char *iface;
+};
+
+static int
+process_if (void *cls,
+            const char *name,
+            int isDefault,
+            const struct sockaddr *addr,
+            socklen_t addrlen)
+{
+  struct GNUNET_NAT_UPNP_Handle *upnp = cls;
+
+  if (addr && GNUNET_NAT_cmp_addr (upnp->addr, addr) == 0)
+    {
+      upnp->iface = name;
+      return GNUNET_SYSERR;
+    }
+
+  return GNUNET_OK;
+}
+
+GNUNET_NAT_UPNP_Handle *
+GNUNET_NAT_UPNP_init (const struct sockaddr *addr, socklen_t addrlen,
+                      u_short port)
+{
+  GNUNET_NAT_UPNP_Handle *upnp =
+    GNUNET_malloc (sizeof (GNUNET_NAT_UPNP_Handle));
+
+  upnp->state = UPNP_DISCOVER;
+  upnp->addr = addr;
+  upnp->addrlen = addrlen;
+  upnp->port = port;
+
+  /* Find the interface corresponding to the address,
+   * on which we should broadcast call for routers */
+  upnp->iface = NULL;
+  GNUNET_OS_network_interfaces_list (process_if, upnp);
+  if (!upnp->iface)
+      GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, COMP_NAT_UPNP, "Could not 
find an interface matching the wanted address.\n");
+
+  return upnp;
+}
+
+void
+GNUNET_NAT_UPNP_close (GNUNET_NAT_UPNP_Handle * handle)
+{
+  GNUNET_assert (!handle->is_mapped);
+  GNUNET_assert ((handle->state == UPNP_IDLE)
+          || (handle->state == UPNP_ERR) || (handle->state == UPNP_DISCOVER));
+
+  if (handle->hasDiscovered)
+    FreeUPNPUrls (&handle->urls);
+  GNUNET_free (handle);
+}
+
+/**
+ * Check state of UPnP NAT: port redirection, external IP address.
+ * 
+ * 
+ * @param handle the handle for UPnP object
+ * @param is_enabled whether enable port redirection
+ * @param ext_addr pointer for returning external IP address.
+ *     Will be set to NULL if address could not be found. Don't free the 
sockaddr.
+ */
+int
+GNUNET_NAT_UPNP_pulse (GNUNET_NAT_UPNP_Handle * handle, int is_enabled,
+                       int doPortCheck, struct sockaddr **ext_addr)
+{
+  int ret;
+
+  if (is_enabled && (handle->state == UPNP_DISCOVER))
+    {
+      struct UPNPDev *devlist;
+      errno = 0;
+      devlist = upnpDiscover (2000, handle->iface, handle->addr, NULL, 0);
+      if (devlist == NULL)
+        {
+#ifdef DEBUG
+          GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, COMP_NAT_UPNP,
+                      "upnpDiscover failed (errno %d - %s)\n", errno,
+                      strerror (errno));
+#endif
+        }
+      errno = 0;
+      if (UPNP_GetValidIGD (devlist, &handle->urls, &handle->data,
+                            NULL, 0))
+        {
+          GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, COMP_NAT_UPNP,
+                      _("Found Internet Gateway Device \"%s\"\n"),
+                      handle->urls.controlURL);
+          handle->state = UPNP_IDLE;
+          handle->hasDiscovered = 1;
+        }
+      else
+        {
+          handle->state = UPNP_ERR;
+#ifdef DEBUG
+          GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, COMP_NAT_UPNP,
+                      "UPNP_GetValidIGD failed (errno %d - %s)\n",
+                      errno, strerror (errno));
+#endif
+        }
+      freeUPNPDevlist (devlist);
+    }
+
+  if (handle->state == UPNP_IDLE)
+    {
+      if (handle->is_mapped && !is_enabled)
+        handle->state = UPNP_UNMAP;
+    }
+
+  if (is_enabled && handle->is_mapped && doPortCheck)
+    {
+      char portStr[8];
+      char intPort[8];
+      char intClient[128];
+      int i;
+
+      GNUNET_snprintf (portStr, sizeof (portStr), "%d", handle->port);
+      i = UPNP_GetSpecificPortMappingEntry (handle->urls.controlURL,
+                                            handle->data.servicetype, portStr,
+                                            "TCP", intClient, intPort);
+      if (i != UPNPCOMMAND_SUCCESS)
+        {
+          GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, COMP_NAT_UPNP,
+                      _("Port %d isn't forwarded\n"), handle->port);
+          handle->is_mapped = GNUNET_NO;
+        }
+    }
+
+  if (handle->state == UPNP_UNMAP)
+    {
+      char portStr[16];
+      GNUNET_snprintf (portStr, sizeof (portStr), "%d", handle->port);
+      UPNP_DeletePortMapping (handle->urls.controlURL,
+                              handle->data.servicetype, portStr, "TCP", NULL);
+      GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, COMP_NAT_UPNP,
+                  _
+                  ("Stopping port forwarding through \"%s\", service 
\"%s\"\n"),
+                  handle->urls.controlURL, handle->data.servicetype);
+      handle->is_mapped = 0;
+      handle->state = UPNP_IDLE;
+      handle->port = -1;
+    }
+
+  if (handle->state == UPNP_IDLE)
+    {
+      if (is_enabled && !handle->is_mapped)
+        handle->state = UPNP_MAP;
+    }
+
+  if (handle->state == UPNP_MAP)
+    {
+      int err = -1;
+      errno = 0;
+
+      if (!handle->urls.controlURL || !handle->data.servicetype)
+        handle->is_mapped = 0;
+      else
+        {
+          char portStr[16];
+          char desc[64];
+          GNUNET_snprintf (portStr, sizeof (portStr), "%d", handle->port);
+          GNUNET_snprintf (desc, sizeof (desc), "GNUnet at %d", handle->port);
+          err = UPNP_AddPortMapping (handle->urls.controlURL,
+                                     handle->data.servicetype,
+                                     portStr, portStr, GNUNET_a2s 
(handle->addr, handle->addrlen),              
+                                     desc, "TCP", NULL);
+          handle->is_mapped = !err;
+        }
+      GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, COMP_NAT_UPNP,
+                  _
+                  ("Port forwarding through \"%s\", service \"%s\"\n"),
+                  handle->urls.controlURL, handle->data.servicetype);
+      if (handle->is_mapped)
+        {
+          GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, COMP_NAT_UPNP,
+                      _("Port %d forwarded successfully\n"), handle->port);
+          handle->state = UPNP_IDLE;
+        }
+      else
+        {
+          GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, COMP_NAT_UPNP,
+                      "Port forwarding failed with error %d (errno %d - %s)\n",
+                      err, errno, strerror (errno));
+          handle->state = UPNP_ERR;
+        }
+    }
+
+  if (ext_addr && handle->state != UPNP_DISCOVER)
+    {
+      int err;
+      char addr_str[128];
+      struct in_addr addr;
+      struct in6_addr addr6;
+
+      /* Keep to NULL if address could not be found */
+      *ext_addr = NULL;
+      err = UPNP_GetExternalIPAddress (handle->urls.controlURL,
+                                       handle->data.servicetype, addr_str);
+      if (err == 0)
+        {
+          if (handle->ext_addr)
+            {
+              GNUNET_free (handle->ext_addr);
+              handle->ext_addr = NULL;
+            }
+
+          /* Try IPv4 and IPv6 as we don't know what's the format */
+          if (inet_aton (addr_str, &addr) != 0)
+            {
+              handle->ext_addr = GNUNET_malloc (sizeof (struct sockaddr_in));
+              handle->ext_addr->sa_family = AF_INET;
+              ((struct sockaddr_in *) handle->ext_addr)->sin_addr = addr;
+              *ext_addr = handle->ext_addr;
+            }
+          else if (inet_pton (AF_INET6, addr_str, &addr6) != 1)
+            {
+              handle->ext_addr = GNUNET_malloc (sizeof (struct sockaddr_in6));
+              handle->ext_addr->sa_family = AF_INET6;
+              ((struct sockaddr_in6 *) handle->ext_addr)->sin6_addr = addr6;
+              *ext_addr = handle->ext_addr;
+            }
+          else
+            GNUNET_assert (GNUNET_YES);
+#ifdef DEBUG
+          GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, COMP_NAT_UPNP,
+                      _("Found public IP address %s\n"),
+                      addr_str);
+#endif
+        }
+      else
+        {
+          *ext_addr = NULL;
+          if (handle->ext_addr)
+            {
+              GNUNET_free (handle->ext_addr);
+              handle->ext_addr = NULL;
+            }
+#ifdef DEBUG
+          GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, COMP_NAT_UPNP,
+                      "UPNP_GetExternalIPAddress failed (error %d)\n", err);
+#endif
+        }
+    }
+
+  switch (handle->state)
+    {
+    case UPNP_DISCOVER:
+      ret = GNUNET_NAT_PORT_UNMAPPED;
+      break;
+
+    case UPNP_MAP:
+      ret = GNUNET_NAT_PORT_MAPPING;
+      break;
+
+    case UPNP_UNMAP:
+      ret = GNUNET_NAT_PORT_UNMAPPING;
+      break;
+
+    case UPNP_IDLE:
+      ret =
+        handle->is_mapped ? GNUNET_NAT_PORT_MAPPED : GNUNET_NAT_PORT_UNMAPPED;
+      break;
+
+    default:
+      ret = GNUNET_NAT_PORT_ERROR;
+      break;
+    }
+
+  return ret;
+}
+
+#if 0                           /* keep Emacsens' auto-indent happy */
+{
+#endif
+#ifdef __cplusplus
+}
+#endif

Added: gnunet/src/nat/upnp.h
===================================================================
--- gnunet/src/nat/upnp.h                               (rev 0)
+++ gnunet/src/nat/upnp.h       2009-10-25 09:44:36 UTC (rev 9271)
@@ -0,0 +1,43 @@
+/*
+     This file is part of GNUnet.
+     (C) 2009 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 2, 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.
+*/
+
+/**
+ * @file nat/upnp.h
+ * @brief UPnP support for the NAT library
+ *
+ * @author Milan Bouchet-Valat
+ */
+
+#ifndef UPNP_H
+#define UPNP_H 1
+
+#include "platform.h"
+
+typedef struct GNUNET_NAT_UPNP_Handle GNUNET_NAT_UPNP_Handle;
+
+GNUNET_NAT_UPNP_Handle *GNUNET_NAT_UPNP_init (const struct sockaddr *addr,
+                                              socklen_t addrlen,
+                                              unsigned short port);
+
+void GNUNET_NAT_UPNP_close (GNUNET_NAT_UPNP_Handle *);
+
+int GNUNET_NAT_UPNP_pulse (GNUNET_NAT_UPNP_Handle *, int is_enabled,
+                           int do_port_check, struct sockaddr **ext_addr);
+#endif /* UPNP_H */





reply via email to

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