Added transition code for new MESH API
[oweals/gnunet.git] / src / mesh / mesh_api_new.c
index 21b264701f2bde717715785c5946f6b59dcfc83b..1d25868255317b70bd62aaed6b53888d980b380a 100644 (file)
@@ -45,7 +45,9 @@ extern "C"
 #include "mesh.h"
 #include "mesh_protocol.h"
 
-#define DEBUG GNUNET_YES
+#define MESH_API_DEBUG GNUNET_YES
+
+#define LOG(kind,...) GNUNET_log_from (kind, "mesh-api",__VA_ARGS__)
 
 /******************************************************************************/
 /************************      DATA STRUCTURES     ****************************/
@@ -105,7 +107,7 @@ struct GNUNET_MESH_TransmitHandle
   uint32_t priority;
 
     /**
-     * Target of the message, 0 for broadcast.  This field
+     * Target of the message, 0 for multicast.  This field
      * is only valid if 'notify' is non-NULL.
      */
   GNUNET_PEER_Id target;
@@ -242,12 +244,12 @@ struct GNUNET_MESH_Tunnel
     /**
      * Callback to execute when peers connect to the tunnel
      */
-  GNUNET_MESH_TunnelConnectHandler connect_handler;
+  GNUNET_MESH_PeerConnectHandler connect_handler;
 
     /**
      * Callback to execute when peers disconnect from the tunnel
      */
-  GNUNET_MESH_TunnelDisconnectHandler disconnect_handler;
+  GNUNET_MESH_PeerDisconnectHandler disconnect_handler;
 
     /**
      * Closure for the connect/disconnect handlers
@@ -380,7 +382,7 @@ destroy_tunnel (struct GNUNET_MESH_Tunnel *t)
 
   if (NULL == t)
   {
-    GNUNET_break(0);
+    GNUNET_break (0);
     return;
   }
   h = t->mesh;
@@ -390,16 +392,16 @@ destroy_tunnel (struct GNUNET_MESH_Tunnel *t)
     if (th->tunnel == t)
     {
       aux = th->next;
-      GNUNET_CONTAINER_DLL_remove(h->th_head, h->th_tail, th);
+      GNUNET_CONTAINER_DLL_remove (h->th_head, h->th_tail, th);
       if (NULL == h->th_head && NULL != h->th)
       {
-        GNUNET_CLIENT_notify_transmit_ready_cancel(h->th);
+        GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
         h->th = NULL;
       }
       if (NULL != th->notify)
-          th->notify(th->notify_cls, 0, NULL);
+        th->notify (th->notify_cls, 0, NULL);
       if (GNUNET_SCHEDULER_NO_TASK != th->timeout_task)
-          GNUNET_SCHEDULER_cancel(th->timeout_task);
+        GNUNET_SCHEDULER_cancel (th->timeout_task);
       GNUNET_free (th);
       th = aux;
     }
@@ -420,7 +422,7 @@ destroy_tunnel (struct GNUNET_MESH_Tunnel *t)
     GNUNET_free (t->peers[i]);
   }
   if (t->npeers > 0)
-      GNUNET_free (t->peers);
+    GNUNET_free (t->peers);
   if (NULL != h->cleaner && 0 != t->owner)
     h->cleaner (h->cls, t, t->ctx);
   if (0 != t->owner)
@@ -431,6 +433,7 @@ destroy_tunnel (struct GNUNET_MESH_Tunnel *t)
   return;
 }
 
+
 /**
  * Get the peer descriptor for the peer with id from the given tunnel
  * @param t Tunnel handle
@@ -479,7 +482,6 @@ add_peer_to_tunnel (struct GNUNET_MESH_Tunnel *t,
 
 /**
  * Remove a peer from a tunnel
- * @param t Tunnel handle
  * @param p Peer handle
  */
 static void
@@ -532,7 +534,7 @@ timeout_transmission (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  * timeout if needed.
  *
  * @param h mesh handle with the queue head and tail
- * @param q handle to the packet to be transmitted
+ * @param th handle to the packet to be transmitted
  */
 static void
 add_to_queue (struct GNUNET_MESH_Handle *h,
@@ -578,6 +580,54 @@ static void
 reconnect_cbk (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
 
 
+/**
+ * Send a connect packet to the service with the applications and types
+ * requested by the user.
+ *
+ * @param h The mesh handle.
+ *
+ */
+static void
+send_connect (struct GNUNET_MESH_Handle *h)
+{
+  size_t size;
+
+  size = sizeof (struct GNUNET_MESH_ClientConnect);
+  size += h->n_applications * sizeof (GNUNET_MESH_ApplicationType);
+  size += h->n_handlers * sizeof (uint16_t);
+  {
+    char buf[size];
+    struct GNUNET_MESH_ClientConnect *msg;
+    GNUNET_MESH_ApplicationType *apps;
+    uint16_t napps;
+    uint16_t *types;
+    uint16_t ntypes;
+
+    /* build connection packet */
+    msg = (struct GNUNET_MESH_ClientConnect *) buf;
+    msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT);
+    msg->header.size = htons (size);
+    apps = (GNUNET_MESH_ApplicationType *) &msg[1];
+    for (napps = 0; napps < h->n_applications; napps++)
+    {
+      apps[napps] = htonl (h->applications[napps]);
+      LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh:  app %u\n", h->applications[napps]);
+    }
+    types = (uint16_t *) & apps[napps];
+    for (ntypes = 0; ntypes < h->n_handlers; ntypes++)
+      types[ntypes] = htons (h->message_handlers[ntypes].type);
+    msg->applications = htons (napps);
+    msg->types = htons (ntypes);
+#if MESH_API_DEBUG
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "mesh: Sending %lu bytes long message %d types and %d apps\n",
+         ntohs (msg->header.size), ntypes, napps);
+#endif
+    send_packet (h, &msg->header);
+  }
+}
+
+
 /**
  * Reconnect to the service, retransmit all infomation to try to restore the
  * original state.
@@ -592,6 +642,11 @@ reconnect (struct GNUNET_MESH_Handle *h)
   struct GNUNET_MESH_Tunnel *t;
   unsigned int i;
 
+#if MESH_API_DEBUG
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh: *****************************\n");
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh: *******   RECONNECT   *******\n");
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh: *****************************\n");
+#endif
   h->in_receive = GNUNET_NO;
   /* disconnect */
   if (NULL != h->th)
@@ -607,9 +662,13 @@ reconnect (struct GNUNET_MESH_Handle *h)
   h->client = GNUNET_CLIENT_connect ("mesh", h->cfg);
   if (h->client == NULL)
   {
-    GNUNET_SCHEDULER_add_delayed(h->reconnect_time, &reconnect_cbk, h);
-    h->reconnect_time = GNUNET_TIME_relative_min(GNUNET_TIME_UNIT_HOURS,
-        GNUNET_TIME_relative_multiply(h->reconnect_time, 2));
+    GNUNET_SCHEDULER_add_delayed (h->reconnect_time, &reconnect_cbk, h);
+    h->reconnect_time =
+        GNUNET_TIME_relative_min (GNUNET_TIME_UNIT_HOURS,
+                                  GNUNET_TIME_relative_multiply
+                                  (h->reconnect_time, 2));
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh:   Next retry in %sms\n",
+         GNUNET_TIME_relative_to_string (h->reconnect_time));
     GNUNET_break (0);
     return GNUNET_NO;
   }
@@ -617,12 +676,21 @@ reconnect (struct GNUNET_MESH_Handle *h)
   {
     h->reconnect_time = GNUNET_TIME_UNIT_MILLISECONDS;
   }
+  send_connect (h);
   /* Rebuild all tunnels */
   for (t = h->tunnels_head; NULL != t; t = t->next)
   {
     struct GNUNET_MESH_TunnelMessage tmsg;
     struct GNUNET_MESH_PeerControl pmsg;
 
+    if (t->tid >= GNUNET_MESH_LOCAL_TUNNEL_ID_SERV)
+    {
+      /* Tunnel was created by service (incoming tunnel) */
+      /* TODO: Notify service of missing tunnel, to request
+       * creator to recreate path (find a path to him via DHT?)
+       */
+      continue;
+    }
     tmsg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE);
     tmsg.header.size = htons (sizeof (struct GNUNET_MESH_TunnelMessage));
     tmsg.tunnel_id = htonl (t->tid);
@@ -667,9 +735,10 @@ static void
 reconnect_cbk (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
   struct GNUNET_MESH_Handle *h = cls;
+
   if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
     return;
-  reconnect(h);
+  reconnect (h);
 }
 
 
@@ -685,14 +754,14 @@ reconnect_cbk (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  */
 static void
 process_tunnel_created (struct GNUNET_MESH_Handle *h,
-                       const struct GNUNET_MESH_TunnelNotification *msg)
+                        const struct GNUNET_MESH_TunnelNotification *msg)
 {
   struct GNUNET_MESH_Tunnel *t;
-  struct GNUNET_TRANSPORT_ATS_Information atsi;
+  struct GNUNET_ATS_Information atsi;
   MESH_TunnelNumber tid;
 
   tid = ntohl (msg->tunnel_id);
-  if (tid <= GNUNET_MESH_LOCAL_TUNNEL_ID_CLI)
+  if (tid < GNUNET_MESH_LOCAL_TUNNEL_ID_SERV)
   {
     GNUNET_break (0);
     return;
@@ -711,9 +780,8 @@ process_tunnel_created (struct GNUNET_MESH_Handle *h,
   {
     atsi.type = 0;
     atsi.value = 0;
-    t->ctx = h->new_tunnel(h->cls, t, &msg->peer, &atsi);
+    t->ctx = h->new_tunnel (h->cls, t, &msg->peer, &atsi);
   }
-  GNUNET_CONTAINER_DLL_insert (h->tunnels_head, h->tunnels_tail, t);
   return;
 }
 
@@ -736,15 +804,14 @@ process_tunnel_destroy (struct GNUNET_MESH_Handle *h,
 
   if (NULL == t)
   {
-    GNUNET_break(0);
     return;
   }
   if (0 == t->owner)
   {
-    GNUNET_break(0);
+    GNUNET_break (0);
   }
 
-  destroy_tunnel(t);
+  destroy_tunnel (t);
   return;
 }
 
@@ -761,10 +828,11 @@ process_peer_event (struct GNUNET_MESH_Handle *h,
 {
   struct GNUNET_MESH_Tunnel *t;
   struct GNUNET_MESH_Peer *p;
-  struct GNUNET_TRANSPORT_ATS_Information atsi;
+  struct GNUNET_ATS_Information atsi;
   GNUNET_PEER_Id id;
   uint16_t size;
 
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh: processig peer event\n");
   size = ntohs (msg->header.size);
   if (size != sizeof (struct GNUNET_MESH_PeerControl))
   {
@@ -774,14 +842,15 @@ process_peer_event (struct GNUNET_MESH_Handle *h,
   t = retrieve_tunnel (h, ntohl (msg->tunnel_id));
   if (NULL == t)
   {
-    GNUNET_break(0);
+    GNUNET_break (0);
     return;
   }
   id = GNUNET_PEER_search (&msg->peer);
   if ((p = retrieve_peer (t, id)) == NULL)
     p = add_peer_to_tunnel (t, &msg->peer);
-  if (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD == msg->header.type)
+  if (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD == ntohs (msg->header.type))
   {
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh: adding peer\n");
     if (NULL != t->connect_handler)
     {
       atsi.type = 0;
@@ -792,6 +861,7 @@ process_peer_event (struct GNUNET_MESH_Handle *h,
   }
   else
   {
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh: removing peer\n");
     if (NULL != t->disconnect_handler && p->connected)
     {
       t->disconnect_handler (t->cls, &msg->peer);
@@ -799,14 +869,15 @@ process_peer_event (struct GNUNET_MESH_Handle *h,
     remove_peer_from_tunnel (p);
     GNUNET_free (p);
   }
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh: processing peer event END\n");
 }
 
 
 /**
  * Process the incoming data packets
  *
- * @param h     The mesh handle
- * @param msh   A message encapsulating the data
+ * @param h         The mesh handle
+ * @param message   A message encapsulating the data
  */
 static void
 process_incoming_data (struct GNUNET_MESH_Handle *h,
@@ -822,15 +893,20 @@ process_incoming_data (struct GNUNET_MESH_Handle *h,
   unsigned int i;
   uint16_t type;
 
-
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: Got a data message!\n");
   type = ntohs (message->type);
   switch (type)
   {
   case GNUNET_MESSAGE_TYPE_MESH_UNICAST:
     ucast = (struct GNUNET_MESH_Unicast *) message;
+
     t = retrieve_tunnel (h, ntohl (ucast->tid));
     payload = (struct GNUNET_MessageHeader *) &ucast[1];
     peer = &ucast->oid;
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "mesh:   on tunnel %s [%x]\n",
+                GNUNET_i2s (peer),
+                ntohl (ucast->tid));
     break;
   case GNUNET_MESSAGE_TYPE_MESH_MULTICAST:
     mcast = (struct GNUNET_MESH_Multicast *) message;
@@ -853,28 +929,28 @@ process_incoming_data (struct GNUNET_MESH_Handle *h,
     GNUNET_break (0);
     return;
   }
-  type = ntohs(payload->type);
+  type = ntohs (payload->type);
   for (i = 0; i < h->n_handlers; i++)
   {
     handler = &h->message_handlers[i];
     if (handler->type == type)
     {
-      struct GNUNET_TRANSPORT_ATS_Information atsi;
+      struct GNUNET_ATS_Information atsi;
 
       atsi.type = 0;
       atsi.value = 0;
       if (GNUNET_OK !=
           handler->callback (h->cls, t, &t->ctx, peer, payload, &atsi))
       {
-        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                    "MESH: callback caused disconnection\n");
+        LOG (GNUNET_ERROR_TYPE_DEBUG, "MESH: callback caused disconnection\n");
         GNUNET_MESH_disconnect (h);
+        return;
       }
-#if DEBUG
+#if MESH_API_DEBUG
       else
       {
-        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                    "MESH: callback completed successfully\n");
+        LOG (GNUNET_ERROR_TYPE_DEBUG,
+             "MESH: callback completed successfully\n");
 
       }
 #endif
@@ -894,12 +970,13 @@ msg_received (void *cls, const struct GNUNET_MessageHeader *msg)
 {
   struct GNUNET_MESH_Handle *h = cls;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: received a message from MESH\n");
   if (msg == NULL)
   {
     reconnect (h);
     return;
   }
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh: received a message type %hu from MESH\n",
+       ntohs (msg->type));
   switch (ntohs (msg->type))
   {
     /* Notify of a new incoming tunnel */
@@ -923,11 +1000,11 @@ msg_received (void *cls, const struct GNUNET_MessageHeader *msg)
     break;
     /* We shouldn't get any other packages, log and ignore */
   default:
-    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                "MESH: unsolicited message form service (type %d)\n",
-                ntohs (msg->type));
+    LOG (GNUNET_ERROR_TYPE_WARNING,
+         "MESH: unsolicited message form service (type %d)\n",
+         ntohs (msg->type));
   }
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: message processed\n");
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh: message processed\n");
   GNUNET_CLIENT_receive (h->client, &msg_received, h,
                          GNUNET_TIME_UNIT_FOREVER_REL);
 }
@@ -956,7 +1033,7 @@ send_callback (void *cls, size_t size, void *buf)
   size_t tsize;
   size_t psize;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: Send packet() Buffer %u\n", size);
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh: Send packet() Buffer %u\n", size);
   h->th = NULL;
   if ((0 == size) || (NULL == buf))
   {
@@ -966,49 +1043,80 @@ send_callback (void *cls, size_t size, void *buf)
   tsize = 0;
   while ((NULL != (th = h->th_head)) && (size >= th->size))
   {
-#if DEBUG
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh:     type: %u\n",
-                ntohs (((struct GNUNET_MessageHeader *)&th[1])->type));
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh:     size: %u\n",
-                ntohs (((struct GNUNET_MessageHeader *)&th[1])->size));
-#endif
     if (NULL != th->notify)
     {
-      if (th->target == 0)
+      if (th->tunnel->tid >= GNUNET_MESH_LOCAL_TUNNEL_ID_SERV)
+      {
+        /* traffic to origin */
+        struct GNUNET_MESH_ToOrigin to;
+        struct GNUNET_MessageHeader *mh;
+
+        GNUNET_assert (size >= th->size);
+        mh = (struct GNUNET_MessageHeader *) &cbuf[sizeof (to)];
+        psize =
+            th->notify (th->notify_cls, size - sizeof (to), mh);
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "mesh:   to origin, type %u\n",
+              ntohs (mh->type));
+        if (psize > 0)
+        {
+          psize += sizeof (to);
+          GNUNET_assert (size >= psize);
+          to.header.size = htons (psize);
+          to.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN);
+          to.tid = htonl (th->tunnel->tid);
+          memset (&to.oid, 0, sizeof (struct GNUNET_PeerIdentity));
+          memset (&to.sender, 0, sizeof (struct GNUNET_PeerIdentity));
+          memcpy (cbuf, &to, sizeof (to));
+        }
+      }
+      else if (th->target == 0)
       {
         /* multicast */
         struct GNUNET_MESH_Multicast mc;
+        struct GNUNET_MessageHeader *mh;
 
-        GNUNET_assert (size >= sizeof (mc) + th->size);
+        GNUNET_assert (size >= th->size);
+        mh = (struct GNUNET_MessageHeader *) &cbuf[sizeof (mc)];
         psize =
-            th->notify (th->notify_cls, size - sizeof (mc), &cbuf[sizeof (mc)]);
+            th->notify (th->notify_cls, size - sizeof (mc), mh);
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                    "mesh:   multicast, type %u\n",
+                    ntohs (mh->type));
         if (psize > 0)
         {
-          mc.header.size = htons (sizeof (mc) + th->size);
+          psize += sizeof (mc);
+          GNUNET_assert (size >= psize);
+          mc.header.size = htons (psize);
           mc.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_MULTICAST);
           mc.tid = htonl (th->tunnel->tid);
-          memset (&mc.oid, 0, sizeof (struct GNUNET_PeerIdentity)); /* myself */
+          memset (&mc.oid, 0, sizeof (struct GNUNET_PeerIdentity));
           memcpy (cbuf, &mc, sizeof (mc));
-          psize = th->size + sizeof (mc);
         }
       }
       else
       {
         /* unicast */
         struct GNUNET_MESH_Unicast uc;
+        struct GNUNET_MessageHeader *mh;
 
-        GNUNET_assert (size >= sizeof (uc) + th->size);
+        GNUNET_assert (size >= th->size);
+        mh = (struct GNUNET_MessageHeader *) &cbuf[sizeof (uc)];
         psize =
-            th->notify (th->notify_cls, size - sizeof (uc), &cbuf[sizeof (uc)]);
+            th->notify (th->notify_cls, size - sizeof (uc), mh);
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "mesh:   unicast, type %u\n",
+              ntohs (mh->type));
         if (psize > 0)
         {
-          uc.header.size = htons (sizeof (uc) + th->size);
+          psize += sizeof (uc);
+          GNUNET_assert (size >= psize);
+          uc.header.size = htons (psize);
           uc.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_UNICAST);
           uc.tid = htonl (th->tunnel->tid);
-          memset (&uc.oid, 0, sizeof (struct GNUNET_PeerIdentity));     /* myself */
+          memset (&uc.oid, 0, sizeof (struct GNUNET_PeerIdentity));
           GNUNET_PEER_resolve (th->target, &uc.destination);
           memcpy (cbuf, &uc, sizeof (uc));
-          psize = th->size + sizeof (uc);
         }
       }
     }
@@ -1025,16 +1133,16 @@ send_callback (void *cls, size_t size, void *buf)
     size -= psize;
     tsize += psize;
   }
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh:   total size: %u\n", tsize);
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh:   total size: %u\n", tsize);
   if (NULL != (th = h->th_head))
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh:   next size: %u\n", th->size);
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh:   next size: %u\n", th->size);
     h->th =
         GNUNET_CLIENT_notify_transmit_ready (h->client, th->size,
                                              GNUNET_TIME_UNIT_FOREVER_REL,
                                              GNUNET_YES, &send_callback, h);
   }
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: Send packet() END\n");
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh: Send packet() END\n");
   if (GNUNET_NO == h->in_receive)
   {
     h->in_receive = GNUNET_YES;
@@ -1107,14 +1215,8 @@ GNUNET_MESH_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
                      const GNUNET_MESH_ApplicationType *stypes)
 {
   struct GNUNET_MESH_Handle *h;
-  struct GNUNET_MESH_ClientConnect *msg;
-  GNUNET_MESH_ApplicationType *apps;
-  uint16_t napps;
-  uint16_t *types;
-  uint16_t ntypes;
-  size_t size;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: GNUNET_MESH_connect()\n");
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh: GNUNET_MESH_connect()\n");
   h = GNUNET_malloc (sizeof (struct GNUNET_MESH_Handle));
   h->cfg = cfg;
   h->max_queue_size = queue_size;
@@ -1128,41 +1230,17 @@ GNUNET_MESH_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
     return NULL;
   }
   h->cls = cls;
-  h->message_handlers = handlers;
+  /* FIXME memdup? */
   h->applications = stypes;
+  h->message_handlers = handlers;
   h->next_tid = GNUNET_MESH_LOCAL_TUNNEL_ID_CLI;
   h->reconnect_time = GNUNET_TIME_UNIT_MILLISECONDS;
 
   /* count handlers and apps, calculate size */
-  for (h->n_handlers = 0; handlers[h->n_handlers].type; h->n_handlers++) ;
   for (h->n_applications = 0; stypes[h->n_applications]; h->n_applications++) ;
-  size = sizeof (struct GNUNET_MESH_ClientConnect);
-  size += h->n_handlers * sizeof (uint16_t);
-  size += h->n_applications * sizeof (GNUNET_MESH_ApplicationType);
-
-  {
-    char buf[size];
-
-    /* build connection packet */
-    msg = (struct GNUNET_MESH_ClientConnect *) buf;
-    msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT);
-    msg->header.size = htons (size);
-    types = (uint16_t *) & msg[1];
-    for (ntypes = 0; ntypes < h->n_handlers; ntypes++)
-      types[ntypes] = h->message_handlers[ntypes].type;
-    apps = (GNUNET_MESH_ApplicationType *) &types[ntypes];
-    for (napps = 0; napps < h->n_applications; napps++)
-      apps[napps] = h->applications[napps];
-    msg->applications = htons (napps);
-    msg->types = htons (ntypes);
-#if DEBUG
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "mesh: Sending %lu bytes long message %d types and %d apps\n",
-                ntohs (msg->header.size), ntypes, napps);
-#endif
-    send_packet (h, &msg->header);
-  }
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: GNUNET_MESH_connect() END\n");
+  for (h->n_handlers = 0; handlers[h->n_handlers].type; h->n_handlers++) ;
+  send_connect (h);
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh: GNUNET_MESH_connect() END\n");
   return h;
 }
 
@@ -1176,10 +1254,14 @@ void
 GNUNET_MESH_disconnect (struct GNUNET_MESH_Handle *handle)
 {
   struct GNUNET_MESH_Tunnel *t;
+  struct GNUNET_MESH_Tunnel *aux;
 
-  for (t = handle->tunnels_head; NULL != t; t = t->next)
+  t = handle->tunnels_head;
+  while (NULL != t)
   {
+    aux = t->next;
     destroy_tunnel (t);
+    t = aux;
   }
   if (NULL != handle->th)
   {
@@ -1205,14 +1287,14 @@ GNUNET_MESH_disconnect (struct GNUNET_MESH_Handle *handle)
  */
 struct GNUNET_MESH_Tunnel *
 GNUNET_MESH_tunnel_create (struct GNUNET_MESH_Handle *h, void *tunnel_ctx,
-                           GNUNET_MESH_TunnelConnectHandler connect_handler,
-                           GNUNET_MESH_TunnelDisconnectHandler
-                           disconnect_handler, void *handler_cls)
+                           GNUNET_MESH_PeerConnectHandler connect_handler,
+                           GNUNET_MESH_PeerDisconnectHandler disconnect_handler,
+                           void *handler_cls)
 {
   struct GNUNET_MESH_Tunnel *t;
   struct GNUNET_MESH_TunnelMessage msg;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: Creating new tunnel\n");
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh: Creating new tunnel\n");
   t = create_tunnel (h, 0);
   t->connect_handler = connect_handler;
   t->disconnect_handler = disconnect_handler;
@@ -1232,21 +1314,21 @@ GNUNET_MESH_tunnel_create (struct GNUNET_MESH_Handle *h, void *tunnel_ctx,
  * @param tun tunnel handle
  */
 void
-GNUNET_MESH_tunnel_destroy (struct GNUNET_MESH_Tunnel *t)
+GNUNET_MESH_tunnel_destroy (struct GNUNET_MESH_Tunnel *tunnel)
 {
   struct GNUNET_MESH_Handle *h;
   struct GNUNET_MESH_TunnelMessage msg;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: Destroying tunnel\n");
-  h = t->mesh;
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh: Destroying tunnel\n");
+  h = tunnel->mesh;
 
-  if (0 != t->owner)
-    GNUNET_PEER_change_rc (t->owner, -1);
+  if (0 != tunnel->owner)
+    GNUNET_PEER_change_rc (tunnel->owner, -1);
 
   msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_DESTROY);
   msg.header.size = htons (sizeof (struct GNUNET_MESH_TunnelMessage));
-  msg.tunnel_id = htonl (t->tid);
-  destroy_tunnel (t);
+  msg.tunnel_id = htonl (tunnel->tid);
+  destroy_tunnel (tunnel);
   send_packet (h, &msg.header);
 }
 
@@ -1258,7 +1340,6 @@ GNUNET_MESH_tunnel_destroy (struct GNUNET_MESH_Tunnel *t)
  * connect handler is called.
  *
  * @param tunnel handle to existing tunnel
- * @param timeout how long to try to establish a connection
  * @param peer peer to add
  */
 void
@@ -1274,6 +1355,7 @@ GNUNET_MESH_peer_request_connect_add (struct GNUNET_MESH_Tunnel *tunnel,
   {
     if (tunnel->peers[i]->id == peer_id)
     {
+      /* Peer already exists in tunnel */
       GNUNET_PEER_change_rc (peer_id, -1);
       GNUNET_break (0);
       return;
@@ -1396,7 +1478,18 @@ GNUNET_MESH_notify_transmit_ready (struct GNUNET_MESH_Tunnel *tunnel, int cork,
   uint32_t least_priority;
   size_t overhead;
 
-  GNUNET_assert(NULL != notify);
+#if MESH_API_DEBUG
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "mesh: mesh notify transmit ready called\n");
+  if (NULL != target)
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "mesh:     target %s\n",
+                GNUNET_i2s (target));
+  else
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "mesh:     target multicast\n");
+#endif
+  GNUNET_assert (NULL != notify);
   if (tunnel->mesh->npackets >= tunnel->mesh->max_queue_size &&
       tunnel->npackets > 0)
   {
@@ -1417,16 +1510,16 @@ GNUNET_MESH_notify_transmit_ready (struct GNUNET_MESH_Tunnel *tunnel, int cork,
     }
     if (NULL == least_priority_th)
       return NULL;
-    GNUNET_assert(NULL != least_priority_th->notify); /* Cant be a cntrl msg */
-    least_priority_th->notify(notify_cls, 0, NULL);
+    /* Can't be a control message */
+    GNUNET_assert (NULL != least_priority_th->notify);
+    least_priority_th->notify (notify_cls, 0, NULL);
     least_priority_th->tunnel->npackets--;
     tunnel->mesh->npackets--;
-    GNUNET_CONTAINER_DLL_remove(tunnel->mesh->th_head,
-                                tunnel->mesh->th_tail,
-                                least_priority_th);
+    GNUNET_CONTAINER_DLL_remove (tunnel->mesh->th_head, tunnel->mesh->th_tail,
+                                 least_priority_th);
     if (GNUNET_SCHEDULER_NO_TASK != least_priority_th->timeout_task)
-      GNUNET_SCHEDULER_cancel(least_priority_th->timeout_task);
-    GNUNET_free(least_priority_th);
+      GNUNET_SCHEDULER_cancel (least_priority_th->timeout_task);
+    GNUNET_free (least_priority_th);
   }
   tunnel->npackets++;
   tunnel->mesh->npackets++;
@@ -1435,14 +1528,25 @@ GNUNET_MESH_notify_transmit_ready (struct GNUNET_MESH_Tunnel *tunnel, int cork,
   th->priority = priority;
   th->timeout = GNUNET_TIME_relative_to_absolute (maxdelay);
   th->target = GNUNET_PEER_intern (target);
-  overhead =
-      (NULL ==
-       target) ? sizeof (struct GNUNET_MESH_Multicast) : sizeof (struct
-                                                                 GNUNET_MESH_Unicast);
+  if (tunnel->tid >= GNUNET_MESH_LOCAL_TUNNEL_ID_SERV)
+    overhead = sizeof (struct GNUNET_MESH_ToOrigin);
+  else if (NULL == target)
+    overhead = sizeof (struct GNUNET_MESH_Multicast);
+  else
+    overhead = sizeof (struct GNUNET_MESH_Unicast);
   th->size = notify_size + overhead;
   th->notify = notify;
   th->notify_cls = notify_cls;
   add_to_queue (tunnel->mesh, th);
+  if (NULL != tunnel->mesh->th)
+    return th;
+  tunnel->mesh->th =
+      GNUNET_CLIENT_notify_transmit_ready (tunnel->mesh->client,
+                                           th->size,
+                                           GNUNET_TIME_UNIT_FOREVER_REL,
+                                           GNUNET_YES,
+                                           &send_callback,
+                                           tunnel->mesh);
   return th;
 }
 
@@ -1471,6 +1575,25 @@ GNUNET_MESH_notify_transmit_ready_cancel (struct GNUNET_MESH_TransmitHandle *th)
 }
 
 
+/**
+ * Transition API for tunnel ctx management
+ */
+void
+GNUNET_MESH_tunnel_set_data (struct GNUNET_MESH_Tunnel *tunnel, void *data)
+{
+  tunnel->ctx = data;
+}
+
+/**
+ * Transition API for tunnel ctx management
+ */
+void *
+GNUNET_MESH_tunnel_get_data (struct GNUNET_MESH_Tunnel *tunnel)
+{
+  return tunnel->ctx;
+}
+
+
 #if 0                           /* keep Emacsens' auto-indent happy */
 {
 #endif