Added transition code for new MESH API
[oweals/gnunet.git] / src / mesh / mesh_api_new.c
index 0fe990eee9d505118738929bca83869ef440bb02..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;
@@ -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,10 +642,10 @@ reconnect (struct GNUNET_MESH_Handle *h)
   struct GNUNET_MESH_Tunnel *t;
   unsigned int i;
 
-#if DEBUG
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: *****************************\n");
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: *******   RECONNECT   *******\n");
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: *****************************\n");
+#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 */
@@ -617,6 +667,8 @@ reconnect (struct GNUNET_MESH_Handle *h)
         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;
   }
@@ -624,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);
@@ -696,11 +757,11 @@ process_tunnel_created (struct GNUNET_MESH_Handle *h,
                         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;
@@ -721,7 +782,6 @@ process_tunnel_created (struct GNUNET_MESH_Handle *h,
     atsi.value = 0;
     t->ctx = h->new_tunnel (h->cls, t, &msg->peer, &atsi);
   }
-  GNUNET_CONTAINER_DLL_insert (h->tunnels_head, h->tunnels_tail, t);
   return;
 }
 
@@ -744,7 +804,6 @@ process_tunnel_destroy (struct GNUNET_MESH_Handle *h,
 
   if (NULL == t)
   {
-    GNUNET_break (0);
     return;
   }
   if (0 == t->owner)
@@ -769,11 +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;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: processig peer event\n");
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh: processig peer event\n");
   size = ntohs (msg->header.size);
   if (size != sizeof (struct GNUNET_MESH_PeerControl))
   {
@@ -791,7 +850,7 @@ process_peer_event (struct GNUNET_MESH_Handle *h,
     p = add_peer_to_tunnel (t, &msg->peer);
   if (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD == ntohs (msg->header.type))
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: adding peer\n");
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh: adding peer\n");
     if (NULL != t->connect_handler)
     {
       atsi.type = 0;
@@ -802,7 +861,7 @@ process_peer_event (struct GNUNET_MESH_Handle *h,
   }
   else
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: removing peer\n");
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh: removing peer\n");
     if (NULL != t->disconnect_handler && p->connected)
     {
       t->disconnect_handler (t->cls, &msg->peer);
@@ -810,7 +869,7 @@ process_peer_event (struct GNUNET_MESH_Handle *h,
     remove_peer_from_tunnel (p);
     GNUNET_free (p);
   }
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: processing peer event END\n");
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh: processing peer event END\n");
 }
 
 
@@ -834,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;
@@ -871,23 +935,22 @@ process_incoming_data (struct GNUNET_MESH_Handle *h,
     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);
-       break;
+        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
@@ -912,9 +975,8 @@ msg_received (void *cls, const struct GNUNET_MessageHeader *msg)
     reconnect (h);
     return;
   }
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "mesh: received a message type %hu from MESH\n",
-              ntohs (msg->type));
+  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 */
@@ -938,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);
 }
@@ -971,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))
   {
@@ -981,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));
           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));
           GNUNET_PEER_resolve (th->target, &uc.destination);
           memcpy (cbuf, &uc, sizeof (uc));
-          psize = th->size + sizeof (uc);
         }
       }
     }
@@ -1040,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;
@@ -1122,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;
@@ -1152,37 +1239,8 @@ GNUNET_MESH_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
   /* count handlers and apps, calculate size */
   for (h->n_applications = 0; stypes[h->n_applications]; h->n_applications++) ;
   for (h->n_handlers = 0; handlers[h->n_handlers].type; h->n_handlers++) ;
-  size = sizeof (struct GNUNET_MESH_ClientConnect);
-  size += h->n_applications * sizeof (GNUNET_MESH_ApplicationType);
-  size += h->n_handlers * sizeof (uint16_t);
-
-  {
-    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);
-    apps = (GNUNET_MESH_ApplicationType *) &msg[1];
-    for (napps = 0; napps < h->n_applications; napps++)
-    {
-      apps[napps] = htonl (h->applications[napps]);
-      GNUNET_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 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");
+  send_connect (h);
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh: GNUNET_MESH_connect() END\n");
   return h;
 }
 
@@ -1236,7 +1294,7 @@ GNUNET_MESH_tunnel_create (struct GNUNET_MESH_Handle *h, void *tunnel_ctx,
   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;
@@ -1261,7 +1319,7 @@ 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");
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh: Destroying tunnel\n");
   h = tunnel->mesh;
 
   if (0 != tunnel->owner)
@@ -1297,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;
@@ -1419,6 +1478,17 @@ GNUNET_MESH_notify_transmit_ready (struct GNUNET_MESH_Tunnel *tunnel, int cork,
   uint32_t least_priority;
   size_t overhead;
 
+#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)
@@ -1458,7 +1528,9 @@ 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);
-  if (NULL == target)
+  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);
@@ -1466,6 +1538,15 @@ GNUNET_MESH_notify_transmit_ready (struct GNUNET_MESH_Tunnel *tunnel, int cork,
   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;
 }
 
@@ -1494,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