-doxygen, following naming conventions
[oweals/gnunet.git] / src / vpn / gnunet-service-vpn.c
index 61bd977bc8486f0e464e0c820aca2ec537d58bfc..030816797cf80c8dfab729bed6213c756b2b9207 100644 (file)
  *        IP traffic received on those IPs via the GNUnet mesh 
  * @author Philipp Toelke
  * @author Christian Grothoff
+ *
+ * TODO:
+ * - keep multiple peers/mesh tunnels ready as alternative exits /
+ *   recover from tunnel-to-exit failure gracefully
  */
 #include "platform.h"
 #include "gnunet_util_lib.h"
@@ -35,7 +39,7 @@
 #include "gnunet_statistics_service.h"
 #include "gnunet_constants.h"
 #include "gnunet_tun_lib.h"
-#include "gnunet_regex_lib.h"
+#include "gnunet_regex_service.h"
 #include "vpn.h"
 #include "exit.h"
 
@@ -46,6 +50,8 @@
 #define MAX_MESSAGE_QUEUE_SIZE 4
 
 
+#define PORT_VPN 42
+
 /**
  * State we keep for each of our tunnels.
  */
@@ -76,8 +82,8 @@ struct DestinationEntry
   struct GNUNET_CONTAINER_HeapNode *heap_node;
 
   /**
-   * GNUNET_NO if this is a tunnel to an Internet-exit,
-   * GNUNET_YES if this tunnel is to a service.
+   * #GNUNET_NO if this is a tunnel to an Internet-exit,
+   * #GNUNET_YES if this tunnel is to a service.
    */
   int is_service;
 
@@ -171,6 +177,11 @@ struct TunnelState
    */
   struct GNUNET_MESH_Tunnel *tunnel;
 
+  /**
+   * Active query with REGEX to locate exit.
+   */
+  struct GNUNET_REGEX_Search *search;
+
   /**
    * Active transmission handle, NULL for none.
    */
@@ -443,7 +454,7 @@ get_tunnel_key_from_ips (int af,
     break;
   }
   memcpy (off, &protocol, sizeof (uint8_t));
-  off += sizeof (uint8_t);  
+  /* off += sizeof (uint8_t);  */
 }
 
 
@@ -520,11 +531,6 @@ free_tunnel_state (struct TunnelState *ts)
     GNUNET_free (tnq);
   }
   GNUNET_assert (0 == ts->tmq_length);
-  if (NULL != ts->client)
-  {
-    GNUNET_SERVER_client_drop (ts->client);
-    ts->client = NULL;
-  }
   if (NULL != ts->th)
   {
     GNUNET_MESH_notify_transmit_ready_cancel (ts->th);
@@ -536,6 +542,11 @@ free_tunnel_state (struct TunnelState *ts)
     ts->tunnel = NULL;
     GNUNET_MESH_tunnel_destroy (tunnel);
   }
+  if (NULL != ts->search)
+  {
+    GNUNET_REGEX_search_cancel (ts->search);
+    ts->search = NULL;
+  }
   if (GNUNET_SCHEDULER_NO_TASK != ts->destroy_task)
   {
     GNUNET_SCHEDULER_cancel (ts->destroy_task);
@@ -570,7 +581,7 @@ free_tunnel_state (struct TunnelState *ts)
 /**
  * Destroy the mesh tunnel.
  *
- * @param cls the 'struct TunnelState' with the tunnel to destroy
+ * @param cls the `struct TunnelState` with the tunnel to destroy
  * @param tc scheduler context
  */
 static void
@@ -592,13 +603,15 @@ destroy_tunnel_task (void *cls,
 /**
  * Method called whenever a peer has disconnected from the tunnel.
  *
+ * FIXME merge with inbound_cleaner
+ * 
  * @param cls closure
  * @param peer peer identity the tunnel stopped working with
  */
-static void
+void
 tunnel_peer_disconnect_handler (void *cls,
                                const struct
-                               GNUNET_PeerIdentity * peer)
+                               GNUNET_PeerIdentity *peer)
 {
   struct TunnelState *ts = cls;
 
@@ -626,14 +639,15 @@ tunnel_peer_disconnect_handler (void *cls,
  * Method called whenever a peer has connected to the tunnel.  Notifies
  * the waiting client that the tunnel is now up.
  *
+ * FIXME merge with tunnel_create
+ * 
  * @param cls closure
  * @param peer peer identity the tunnel was created to, NULL on timeout
  * @param atsi performance data for the connection
  */
-static void
+void
 tunnel_peer_connect_handler (void *cls,
-                            const struct GNUNET_PeerIdentity
-                            * peer,
+                            const struct GNUNET_PeerIdentity *peer,
                             const struct
                             GNUNET_ATS_Information * atsi)
 {
@@ -651,7 +665,6 @@ tunnel_peer_connect_handler (void *cls,
                     ts->request_id,
                     ts->af,
                     &ts->destination_ip);
-  GNUNET_SERVER_client_drop (ts->client);
   ts->client = NULL;
 }
 
@@ -659,10 +672,10 @@ tunnel_peer_connect_handler (void *cls,
 /**
  * Send a message from the message queue via mesh.
  *
- * @param cls the 'struct TunnelState' with the message queue
- * @param size number of bytes available in buf
+ * @param cls the `struct TunnelState` with the message queue
+ * @param size number of bytes available in @a buf
  * @param buf where to copy the message
- * @return number of bytes copied to buf
+ * @return number of bytes copied to @a buf
  */
 static size_t
 send_to_peer_notify_callback (void *cls, size_t size, void *buf)
@@ -691,7 +704,6 @@ send_to_peer_notify_callback (void *cls, size_t size, void *buf)
     ts->th = GNUNET_MESH_notify_transmit_ready (ts->tunnel, 
                                                GNUNET_NO /* cork */, 
                                                GNUNET_TIME_UNIT_FOREVER_REL,
-                                               NULL, 
                                                tnq->len,
                                                &send_to_peer_notify_callback,
                                                ts);
@@ -743,13 +755,43 @@ send_to_tunnel (struct TunnelMessageQueueEntry *tnq,
     ts->th = GNUNET_MESH_notify_transmit_ready (ts->tunnel, 
                                                GNUNET_NO /* cork */,
                                                GNUNET_TIME_UNIT_FOREVER_REL,
-                                               NULL, 
                                                tnq->len,
                                                &send_to_peer_notify_callback,
                                                ts);
 }
 
 
+/**
+ * Regex has found a potential exit peer for us; consider using it.
+ *
+ * @param cls the 'struct TunnelState'
+ * @param id Peer providing a regex that matches the string.
+ * @param get_path Path of the get request.
+ * @param get_path_length Lenght of get_path.
+ * @param put_path Path of the put request.
+ * @param put_path_length Length of the put_path.
+ */
+static void
+handle_regex_result (void *cls,
+                    const struct GNUNET_PeerIdentity *id,
+                    const struct GNUNET_PeerIdentity *get_path,
+                    unsigned int get_path_length,
+                    const struct GNUNET_PeerIdentity *put_path,
+                    unsigned int put_path_length)
+{
+  struct TunnelState *ts = cls;
+
+  GNUNET_REGEX_search_cancel (ts->search);
+  ts->search = NULL;
+  ts->tunnel = GNUNET_MESH_tunnel_create (mesh_handle,
+                                          ts,
+                                          id,
+                                          PORT_VPN,
+                                          GNUNET_YES,
+                                          GNUNET_NO);
+}
+
+
 /**
  * Initialize the given destination entry's mesh tunnel.
  *
@@ -771,40 +813,36 @@ create_tunnel_to_destination (struct DestinationEntry *de,
                            gettext_noop ("# Mesh tunnels created"),
                            1, GNUNET_NO);
   GNUNET_assert (NULL == de->ts);
-  ts = GNUNET_malloc (sizeof (struct TunnelState));
+  ts = GNUNET_new (struct TunnelState);
   ts->af = client_af;
   if (NULL != client)
   {
     ts->request_id = request_id;
     ts->client = client;
-    GNUNET_SERVER_client_keep (client);
   }
   ts->destination = *de;
   ts->destination.heap_node = NULL; /* copy is NOT in destination heap */
   de->ts = ts;
   ts->destination_container = de; /* we are referenced from de */
-  ts->tunnel = GNUNET_MESH_tunnel_create (mesh_handle,
-                                         ts,
-                                         &tunnel_peer_connect_handler,
-                                         &tunnel_peer_disconnect_handler,
-                                         ts);
-  if (NULL == ts->tunnel)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-               _("Failed to setup mesh tunnel!\n"));
-    if (NULL != client)
-      GNUNET_SERVER_client_drop (client);
-    GNUNET_free (ts);
-    return NULL;
-  }
   if (de->is_service)
   {
+    ts->tunnel = GNUNET_MESH_tunnel_create (mesh_handle,
+                                           ts,
+                                           &de->details.service_destination.target,
+                                           PORT_VPN,
+                                           GNUNET_YES,
+                                           GNUNET_NO);
+    if (NULL == ts->tunnel)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                 _("Failed to setup mesh tunnel!\n"));
+      GNUNET_free (ts);
+      return NULL;
+    }
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                "Creating tunnel to peer %s offering service %s\n",
                GNUNET_i2s (&de->details.service_destination.target),
                GNUNET_h2s (&de->details.service_destination.service_descriptor));
-    GNUNET_MESH_peer_request_connect_add (ts->tunnel,
-                                         &de->details.service_destination.target);  
   }
   else
   {
@@ -814,9 +852,10 @@ create_tunnel_to_destination (struct DestinationEntry *de,
     {
     case AF_INET:
     {
-      char address[GNUNET_REGEX_IPV4_REGEXLEN];
-      GNUNET_REGEX_ipv4toregex (&de->details.exit_destination.ip.v4,
-                                "255.255.255.255", address);
+      char address[GNUNET_TUN_IPV4_REGEXLEN];
+
+      GNUNET_TUN_ipv4toregexsearch (&de->details.exit_destination.ip.v4,
+                  "255.255.255.255", address);
       GNUNET_asprintf (&policy, "%s%s%s",
                        GNUNET_APPLICATION_TYPE_EXIT_REGEX_PREFIX,
                        "4",
@@ -825,9 +864,10 @@ create_tunnel_to_destination (struct DestinationEntry *de,
     }
     case AF_INET6:
     {
-      char address[GNUNET_REGEX_IPV6_REGEXLEN];
-      GNUNET_REGEX_ipv6toregex (&de->details.exit_destination.ip.v6,
-                                128, address);
+      char address[GNUNET_TUN_IPV6_REGEXLEN];
+      
+      GNUNET_TUN_ipv6toregexsearch (&de->details.exit_destination.ip.v6,
+                  128, address);
       GNUNET_asprintf (&policy, "%s%s%s",
                        GNUNET_APPLICATION_TYPE_EXIT_REGEX_PREFIX,
                        "6",
@@ -839,12 +879,13 @@ create_tunnel_to_destination (struct DestinationEntry *de,
       break;
     }
 
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Requesting connect by string: %s\n", policy);
-
-    GNUNET_MESH_peer_request_connect_by_string (ts->tunnel, policy);
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "Creating tunnel to exit peer for policy `%s'\n",
-                policy);
+               "Requesting connect by string: %s\n",
+               policy);
+    ts->search = GNUNET_REGEX_search (cfg,
+                                     policy,
+                                     &handle_regex_result,
+                                     ts);
     GNUNET_free (policy);
   }
   return ts;
@@ -991,6 +1032,7 @@ route_packet (struct DestinationEntry *destination,
                (unsigned int) protocol);
     return;
   }
+  alen = 0;
   if (! destination->is_service)
   {  
     switch (destination->details.exit_destination.af)
@@ -1002,7 +1044,6 @@ route_packet (struct DestinationEntry *destination,
       alen = sizeof (struct in6_addr);
       break;
     default:
-      alen = 0;
       GNUNET_assert (0);
     }
 
@@ -1026,8 +1067,6 @@ route_packet (struct DestinationEntry *destination,
   }
   else
   {
-    /* make compiler happy */
-    alen = 0;
     {
       char sbuf[INET6_ADDRSTRLEN];
       char dbuf[INET6_ADDRSTRLEN];
@@ -1078,7 +1117,7 @@ route_packet (struct DestinationEntry *destination,
     ts->destination_port = destination_port;
     ts->heap_node = GNUNET_CONTAINER_heap_insert (tunnel_heap,
                                                  ts,
-                                                 GNUNET_TIME_absolute_get ().abs_value);
+                                                 GNUNET_TIME_absolute_get ().abs_value_us);
     GNUNET_assert (GNUNET_YES ==
                   GNUNET_CONTAINER_multihashmap_put (tunnel_map,
                                                      &key,
@@ -1095,7 +1134,7 @@ route_packet (struct DestinationEntry *destination,
     is_new = GNUNET_NO;
     GNUNET_CONTAINER_heap_update_cost (tunnel_heap, 
                                       ts->heap_node,
-                                      GNUNET_TIME_absolute_get ().abs_value);
+                                      GNUNET_TIME_absolute_get ().abs_value_us);
   }
   GNUNET_assert (NULL != ts->tunnel);
   
@@ -1559,11 +1598,6 @@ message_token (void *cls GNUNET_UNUSED, void *client GNUNET_UNUSED,
                                   &pkt6->destination_address,
                                   &key);
       de = GNUNET_CONTAINER_multihashmap_get (destination_map, &key);
-      /* FIXME: do we need to guard against hash collision? 
-        (if so, we need to also store the local destination IP in the
-        destination entry and then compare here; however, the risk
-        of collision seems minimal AND the impact is unlikely to be
-        super-problematic as well... */
       if (NULL == de)
       {
        char buf[INET6_ADDRSTRLEN];
@@ -1600,11 +1634,6 @@ message_token (void *cls GNUNET_UNUSED, void *client GNUNET_UNUSED,
                                   &pkt4->destination_address,
                                   &key);
       de = GNUNET_CONTAINER_multihashmap_get (destination_map, &key);
-      /* FIXME: do we need to guard against hash collision? 
-        (if so, we need to also store the local destination IP in the
-        destination entry and then compare here; however, the risk
-        of collision seems minimal AND the impact is unlikely to be
-        super-problematic as well... */
       if (NULL == de)
       {
        char buf[INET_ADDRSTRLEN];
@@ -1701,17 +1730,14 @@ make_up_icmpv6_payload (struct TunnelState *ts,
  * @param cls closure, NULL
  * @param tunnel connection to the other end
  * @param tunnel_ctx pointer to our 'struct TunnelState *'
- * @param sender who sent the message
  * @param message the actual message
- * @param atsi performance data for the connection
- * @return GNUNET_OK to keep the connection open,
- *         GNUNET_SYSERR to close it (signal serious error)
+ * @return #GNUNET_OK to keep the connection open,
+ *         #GNUNET_SYSERR to close it (signal serious error)
  */ 
 static int
 receive_icmp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
-                  void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender,
-                  const struct GNUNET_MessageHeader *message,
-                  const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED)
+                  void **tunnel_ctx,
+                  const struct GNUNET_MessageHeader *message)
 {
   struct TunnelState *ts = *tunnel_ctx;
   const struct GNUNET_EXIT_IcmpToVPNMessage *i2v;
@@ -2030,7 +2056,7 @@ receive_icmp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
   }
   GNUNET_CONTAINER_heap_update_cost (tunnel_heap, 
                                     ts->heap_node,
-                                    GNUNET_TIME_absolute_get ().abs_value);
+                                    GNUNET_TIME_absolute_get ().abs_value_us);
   return GNUNET_OK;
 }
 
@@ -2042,17 +2068,14 @@ receive_icmp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
  * @param cls closure, NULL
  * @param tunnel connection to the other end
  * @param tunnel_ctx pointer to our 'struct TunnelState *'
- * @param sender who sent the message
  * @param message the actual message
- * @param atsi performance data for the connection
- * @return GNUNET_OK to keep the connection open,
- *         GNUNET_SYSERR to close it (signal serious error)
+ * @return #GNUNET_OK to keep the connection open,
+ *         #GNUNET_SYSERR to close it (signal serious error)
  */ 
 static int
 receive_udp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
-                  void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender,
-                  const struct GNUNET_MessageHeader *message,
-                  const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED)
+                  void **tunnel_ctx,
+                  const struct GNUNET_MessageHeader *message)
 {
   struct TunnelState *ts = *tunnel_ctx;
   const struct GNUNET_EXIT_UdpReplyMessage *reply;
@@ -2187,7 +2210,7 @@ receive_udp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
   }
   GNUNET_CONTAINER_heap_update_cost (tunnel_heap, 
                                     ts->heap_node,
-                                    GNUNET_TIME_absolute_get ().abs_value);
+                                    GNUNET_TIME_absolute_get ().abs_value_us);
   return GNUNET_OK;
 }
 
@@ -2198,19 +2221,15 @@ receive_udp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
  *
  * @param cls closure, NULL
  * @param tunnel connection to the other end
- * @param tunnel_ctx pointer to our 'struct TunnelState *'
- * @param sender who sent the message
+ * @param tunnel_ctx pointer to our `struct TunnelState *`
  * @param message the actual message
- * @param atsi performance data for the connection
- * @return GNUNET_OK to keep the connection open,
- *         GNUNET_SYSERR to close it (signal serious error)
+ * @return #GNUNET_OK to keep the connection open,
+ *         #GNUNET_SYSERR to close it (signal serious error)
  */ 
 static int
 receive_tcp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
                   void **tunnel_ctx,
-                  const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED,
-                  const struct GNUNET_MessageHeader *message,
-                  const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED)
+                  const struct GNUNET_MessageHeader *message)
 {
   struct TunnelState *ts = *tunnel_ctx;
   const struct GNUNET_EXIT_TcpDataMessage *data;
@@ -2332,7 +2351,7 @@ receive_tcp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
   }
   GNUNET_CONTAINER_heap_update_cost (tunnel_heap, 
                                     ts->heap_node,
-                                    GNUNET_TIME_absolute_get ().abs_value);
+                                    GNUNET_TIME_absolute_get ().abs_value_us);
   return GNUNET_OK;
 }
 
@@ -2342,8 +2361,8 @@ receive_tcp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
  * for a new redirection.
  *
  * @param v4 where to store the address
- * @return GNUNET_OK on success,
- *         GNUNET_SYSERR on error
+ * @return #GNUNET_OK on success,
+ *         #GNUNET_SYSERR on error
  */
 static int
 allocate_v4_address (struct in_addr *v4)
@@ -2393,8 +2412,8 @@ allocate_v4_address (struct in_addr *v4)
  * for a new redirection.
  *
  * @param v6 where to store the address
- * @return GNUNET_OK on success,
- *         GNUNET_SYSERR on error
+ * @return #GNUNET_OK on success,
+ *         #GNUNET_SYSERR on error
  */
 static int
 allocate_v6_address (struct in6_addr *v6)
@@ -2511,7 +2530,7 @@ expire_destination (struct DestinationEntry *except)
  *         storage location was used; set to NULL if allocation failed
  * @param v4 storage space for an IPv4 address
  * @param v6 storage space for an IPv6 address
- * @return GNUNET_OK normally, GNUNET_SYSERR if '*result_af' was
+ * @return #GNUNET_OK normally, #GNUNET_SYSERR if `* result_af` was
  *         an unsupported address family (not AF_INET, AF_INET6 or AF_UNSPEC)
  */
 static int
@@ -2566,7 +2585,7 @@ allocate_response_ip (int *result_af,
  *
  * @param cls unused
  * @param client requesting client
- * @param message redirection request (a 'struct RedirectToIpRequestMessage')
+ * @param message redirection request (a `struct RedirectToIpRequestMessage`)
  */
 static void
 service_redirect_to_ip (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Client *client,
@@ -2656,7 +2675,7 @@ service_redirect_to_ip (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Client *cl
   }
   
   /* setup destination record */
-  de = GNUNET_malloc (sizeof (struct DestinationEntry));
+  de = GNUNET_new (struct DestinationEntry);
   de->is_service = GNUNET_NO;
   de->details.exit_destination.af = addr_af;
   memcpy (&de->details.exit_destination.ip,
@@ -2673,7 +2692,7 @@ service_redirect_to_ip (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Client *cl
                                                    GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
   de->heap_node = GNUNET_CONTAINER_heap_insert (destination_heap,
                                                de,
-                                               GNUNET_TIME_absolute_ntoh (msg->expiration_time).abs_value);
+                                               GNUNET_TIME_absolute_ntoh (msg->expiration_time).abs_value_us);
   GNUNET_STATISTICS_update (stats,
                            gettext_noop ("# Active destinations"),
                            1, GNUNET_NO);
@@ -2708,7 +2727,7 @@ service_redirect_to_ip (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Client *cl
  *
  * @param cls unused
  * @param client requesting client
- * @param message redirection request (a 'struct RedirectToPeerRequestMessage')
+ * @param message redirection request (a `struct RedirectToPeerRequestMessage`)
  */
 static void
 service_redirect_to_service (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Client *client,
@@ -2764,7 +2783,7 @@ service_redirect_to_service (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Clien
   }
   
   /* setup destination record */
-  de = GNUNET_malloc (sizeof (struct DestinationEntry));
+  de = GNUNET_new (struct DestinationEntry);
   de->is_service = GNUNET_YES;
   de->details.service_destination.service_descriptor = msg->service_descriptor;
   de->details.service_destination.target = msg->target;
@@ -2779,7 +2798,7 @@ service_redirect_to_service (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Clien
                                                    GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
   de->heap_node = GNUNET_CONTAINER_heap_insert (destination_heap,
                                                de,
-                                               GNUNET_TIME_absolute_ntoh (msg->expiration_time).abs_value);
+                                               GNUNET_TIME_absolute_ntoh (msg->expiration_time).abs_value_us);
   while (GNUNET_CONTAINER_multihashmap_size (destination_map) > max_destination_mappings)
     expire_destination (de);
   ts = create_tunnel_to_destination (de,
@@ -2802,43 +2821,24 @@ service_redirect_to_service (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Clien
 }
 
 
-
-/**
- * Function called for inbound tunnels.  As we don't offer
- * any mesh services, this function should never be called.
- *
- * @param cls closure
- * @param tunnel new handle to the tunnel
- * @param initiator peer that started the tunnel
- * @param atsi performance information for the tunnel
- * @return initial tunnel context for the tunnel
- *         (can be NULL -- that's not an error)
- */ 
-static void *
-inbound_tunnel_cb (void *cls, struct GNUNET_MESH_Tunnel *tunnel,
-                  const struct GNUNET_PeerIdentity *initiator,
-                  const struct GNUNET_ATS_Information *atsi)
-{
-  /* How can and why should anyone open an inbound tunnel to vpn? */
-  GNUNET_break (0);
-  return NULL;
-}
-
-
 /**
- * Function called whenever an inbound tunnel is destroyed.  Should clean up
+ * Function called whenever a tunnel is destroyed.  Should clean up
  * any associated state.
- *
- * @param cls closure (set from GNUNET_MESH_connect)
+ * 
+ * @param cls closure (set from #GNUNET_MESH_connect)
  * @param tunnel connection to the other end (henceforth invalid)
  * @param tunnel_ctx place where local state associated
- *                   with the tunnel is stored (our 'struct TunnelState')
+ *                   with the tunnel is stored (our `struct TunnelState`)
  */ 
 static void
-tunnel_cleaner (void *cls, const struct GNUNET_MESH_Tunnel *tunnel, void *tunnel_ctx)
+tunnel_cleaner (void *cls, 
+               const struct GNUNET_MESH_Tunnel *tunnel, 
+               void *tunnel_ctx)
 {
-  /* we don't have inbound tunnels, so this function should never be called */
-  GNUNET_break (0);
+  struct TunnelState *ts = tunnel_ctx;
+
+  ts->tunnel = NULL; /* we must not call GNUNET_MESH_tunnel_destroy() anymore */
+  free_tunnel_state (ts);
 }
 
 
@@ -2847,8 +2847,8 @@ tunnel_cleaner (void *cls, const struct GNUNET_MESH_Tunnel *tunnel, void *tunnel
  *
  * @param cls unused
  * @param key unused
- * @param value a 'struct DestinationEntry *'
- * @return GNUNET_OK (continue to iterate)
+ * @param value a `struct DestinationEntry *`
+ * @return #GNUNET_OK (continue to iterate)
  */
 static int
 cleanup_destination (void *cls,
@@ -2867,8 +2867,8 @@ cleanup_destination (void *cls,
  *
  * @param cls unused
  * @param key unused
- * @param value a 'struct TunnelState *'
- * @return GNUNET_OK (continue to iterate)
+ * @param value a `struct TunnelState *`
+ * @return #GNUNET_OK (continue to iterate)
  */
 static int
 cleanup_tunnel (void *cls,
@@ -2889,7 +2889,7 @@ cleanup_tunnel (void *cls,
  * @param tc unused
  */
 static void
-cleanup (void *cls GNUNET_UNUSED,
+cleanup (void *cls,
          const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
   unsigned int i;
@@ -2928,8 +2928,8 @@ cleanup (void *cls GNUNET_UNUSED,
     mesh_handle = NULL;
   }
   if (NULL != helper_handle)
-    {
-    GNUNET_HELPER_stop (helper_handle);
+  {
+    GNUNET_HELPER_stop (helper_handle, GNUNET_NO);
     helper_handle = NULL;
   }
   if (NULL != nc)
@@ -2937,7 +2937,7 @@ cleanup (void *cls GNUNET_UNUSED,
     GNUNET_SERVER_notification_context_destroy (nc);
     nc = NULL;
   }
-  if (stats != NULL)
+  if (NULL != stats)
   {
     GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
     stats = NULL;
@@ -2952,8 +2952,8 @@ cleanup (void *cls GNUNET_UNUSED,
  *
  * @param cls the client that disconnected
  * @param key unused
- * @param value a 'struct TunnelState *'
- * @return GNUNET_OK (continue to iterate)
+ * @param value a `struct TunnelState *`
+ * @return #GNUNET_OK (continue to iterate)
  */
 static int
 cleanup_tunnel_client (void *cls,
@@ -2964,10 +2964,7 @@ cleanup_tunnel_client (void *cls,
   struct TunnelState *ts = value;
 
   if (client == ts->client)
-  {
-    GNUNET_SERVER_client_drop (ts->client);
     ts->client = NULL;
-  }
   return GNUNET_OK;
 }
 
@@ -2977,8 +2974,8 @@ cleanup_tunnel_client (void *cls,
  *
  * @param cls the client that disconnected
  * @param key unused
- * @param value a 'struct DestinationEntry *'
- * @return GNUNET_OK (continue to iterate)
+ * @param value a `struct DestinationEntry *`
+ * @return #GNUNET_OK (continue to iterate)
  */
 static int
 cleanup_destination_client (void *cls,
@@ -2992,10 +2989,7 @@ cleanup_destination_client (void *cls,
   if (NULL == (ts = de->ts))
     return GNUNET_OK;
   if (client == ts->client)
-  {
-    GNUNET_SERVER_client_drop (ts->client);
     ts->client = NULL;
-  }
   return GNUNET_OK;
 }
 
@@ -3008,7 +3002,8 @@ cleanup_destination_client (void *cls,
  * @param client handle to the client that disconnected
  */
 static void
-client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
+client_disconnect (void *cls, 
+                  struct GNUNET_SERVER_Client *client)
 {
   if (NULL != tunnel_map)
     GNUNET_CONTAINER_multihashmap_iterate (tunnel_map,
@@ -3047,9 +3042,6 @@ run (void *cls,
     { &receive_icmp_back, GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_VPN, 0},
     {NULL, 0, 0}
   };
-  static const GNUNET_MESH_ApplicationType types[] = {
-    GNUNET_APPLICATION_TYPE_END
-  };
   char *ifname;
   char *ipv6addr;
   char *ipv6prefix_s;
@@ -3075,11 +3067,11 @@ run (void *cls,
   cfg = cfg_;
   stats = GNUNET_STATISTICS_create ("vpn", cfg);
   if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_number (cfg, "vpn", "MAX_MAPPING",
+      GNUNET_CONFIGURATION_get_value_number (cfg, "VPN", "MAX_MAPPING",
                                             &max_destination_mappings))
     max_destination_mappings = 200;
   if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_number (cfg, "vpn", "MAX_TUNNELS",
+      GNUNET_CONFIGURATION_get_value_number (cfg, "VPN", "MAX_TUNNELS",
                                             &max_tunnel_mappings))
     max_tunnel_mappings = 200;
 
@@ -3091,10 +3083,9 @@ run (void *cls,
 
   vpn_argv[0] = GNUNET_strdup ("vpn-gnunet");
   if (GNUNET_SYSERR ==
-      GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IFNAME", &ifname))
+      GNUNET_CONFIGURATION_get_value_string (cfg, "VPN", "IFNAME", &ifname))
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                "No entry 'IFNAME' in configuration!\n");
+    GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "VPN", "IFNAME");
     GNUNET_SCHEDULER_shutdown ();
     return;
   }
@@ -3102,32 +3093,33 @@ run (void *cls,
   if (GNUNET_OK == GNUNET_NETWORK_test_pf (PF_INET6))
   {
     if ( (GNUNET_SYSERR ==
-         GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV6ADDR",
+         GNUNET_CONFIGURATION_get_value_string (cfg, "VPN", "IPV6ADDR",
                                                 &ipv6addr) ||
          (1 != inet_pton (AF_INET6, ipv6addr, &v6))) )
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                 "No valid entry 'IPV6ADDR' in configuration!\n");
+      GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, "VPN", "IPV6ADDR", 
+                                _("Must specify valid IPv6 address"));
       GNUNET_SCHEDULER_shutdown ();
       return;
     }
     vpn_argv[2] = ipv6addr;
     if (GNUNET_SYSERR ==
-       GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV6PREFIX",
+       GNUNET_CONFIGURATION_get_value_string (cfg, "VPN", "IPV6PREFIX",
                                               &ipv6prefix_s))
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                 "No entry 'IPV6PREFIX' in configuration!\n");
+      GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "VPN", "IPV6PREFIX");
       GNUNET_SCHEDULER_shutdown ();
       return;
     }
     vpn_argv[3] = ipv6prefix_s;
     if ( (GNUNET_OK !=
-         GNUNET_CONFIGURATION_get_value_number (cfg, "vpn",
+         GNUNET_CONFIGURATION_get_value_number (cfg, "VPN",
                                                 "IPV6PREFIX",
                                                 &ipv6prefix)) ||
         (ipv6prefix >= 127) )
     {
+      GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, "VPN", "IPV4MASK",
+                                _("Must specify valid IPv6 mask"));
       GNUNET_SCHEDULER_shutdown ();
       return;
     }
@@ -3146,8 +3138,8 @@ run (void *cls,
                                                 &ipv4addr) ||
          (1 != inet_pton (AF_INET, ipv4addr, &v4))) )
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                 "No valid entry for 'IPV4ADDR' in configuration!\n");
+      GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, "VPN", "IPV4ADDR", 
+                                _("Must specify valid IPv4 address"));
       GNUNET_SCHEDULER_shutdown ();
       return;
     }
@@ -3157,8 +3149,8 @@ run (void *cls,
                                                 &ipv4mask) ||
          (1 != inet_pton (AF_INET, ipv4mask, &v4))) )
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                 "No valid entry 'IPV4MASK' in configuration!\n");
+      GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, "VPN", "IPV4MASK",
+                                _("Must specify valid IPv4 mask"));
       GNUNET_SCHEDULER_shutdown ();
       return;
     }
@@ -3175,10 +3167,10 @@ run (void *cls,
 
   mesh_handle =
     GNUNET_MESH_connect (cfg_, NULL, 
-                        &inbound_tunnel_cb
+                        NULL
                         &tunnel_cleaner, 
                         mesh_handlers,
-                        types);
+                        NULL);
   helper_handle = GNUNET_HELPER_start (GNUNET_NO,
                                       "gnunet-helper-vpn", vpn_argv,
                                       &message_token, NULL, NULL);