-man page for gnunet-conversation
[oweals/gnunet.git] / src / conversation / gnunet-service-conversation-new.c
index 6b33f60920bba05590d628a19e821596d13c2e2a..d379931f7cd77980ed65653ad6bed0c6b126e527 100644 (file)
@@ -63,6 +63,11 @@ enum LineStatus
    */
   LS_CALLEE_CONNECTED,
 
+  /**
+   * We're in shutdown, sending hangup messages before cleaning up.
+   */
+  LS_CALLEE_SHUTDOWN,
+
   /**
    * We are waiting for the phone to be picked up.
    */
@@ -126,6 +131,16 @@ struct Line
    */
   struct GNUNET_PeerIdentity target;
 
+  /**
+   * Temporary buffer for audio data.
+   */
+  void *audio_data;
+
+  /**
+   * Number of bytes in @e audio_data.
+   */
+  size_t audio_size;
+
   /**
    * Our line number.
    */
@@ -252,6 +267,32 @@ handle_client_pickup_message (void *cls,
     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
     return;
   }
+  switch (line->status)
+  {
+  case LS_CALLEE_LISTEN:
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Ignoring client's PICKUP message, caller has HUNG UP already\n");
+    GNUNET_SERVER_receive_done (client, GNUNET_OK);
+    break;
+  case LS_CALLEE_RINGING:
+    line->status = LS_CALLEE_CONNECTED;
+    break;
+  case LS_CALLEE_CONNECTED:
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    return;
+  case LS_CALLEE_SHUTDOWN:
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Ignoring client's PICKUP message, line is in SHUTDOWN\n");
+    GNUNET_SERVER_receive_done (client, GNUNET_OK);
+    break;
+  case LS_CALLER_CALLING:
+  case LS_CALLER_CONNECTED:
+  case LS_CALLER_SHUTDOWN:
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    return;
+  }
   line->status = LS_CALLEE_CONNECTED;
   e = GNUNET_MQ_msg_extra (mppm,
                            len,
@@ -262,6 +303,81 @@ handle_client_pickup_message (void *cls,
 }
 
 
+/**
+ * Destroy the mesh tunnels of a line.
+ *
+ * @param line line to shutdown tunnels of
+ */
+static void
+destroy_line_mesh_tunnels (struct Line *line)
+{
+  if (NULL != line->reliable_mq)
+  {
+    GNUNET_MQ_destroy (line->reliable_mq);
+    line->reliable_mq = NULL;
+  }
+  if (NULL != line->unreliable_mth)
+  {
+    GNUNET_MESH_notify_transmit_ready_cancel (line->unreliable_mth);
+    line->unreliable_mth = NULL;
+  }
+  if (NULL != line->tunnel_unreliable)
+  {
+    GNUNET_MESH_tunnel_destroy (line->tunnel_unreliable);
+    line->tunnel_unreliable = NULL;
+  }
+  if (NULL != line->tunnel_reliable)
+  {
+    GNUNET_MESH_tunnel_destroy (line->tunnel_reliable);
+    line->tunnel_reliable = NULL;
+  }
+}
+
+
+/**
+ * We are done signalling shutdown to the other peer.  Close down
+ * (or reset) the line.
+ *
+ * @param cls the `struct Line` to reset/terminate
+ */
+static void
+mq_done_finish_caller_shutdown (void *cls)
+{
+  struct Line *line = cls;
+
+  switch (line->status)
+  {
+  case LS_CALLEE_LISTEN:
+    GNUNET_break (0);
+    break;
+  case LS_CALLEE_RINGING:
+    GNUNET_break (0);
+    break;
+  case LS_CALLEE_CONNECTED:
+    GNUNET_break (0);
+    break;
+  case LS_CALLEE_SHUTDOWN:
+    line->status = LS_CALLEE_LISTEN;
+    destroy_line_mesh_tunnels (line);
+    return;
+  case LS_CALLER_CALLING:
+    line->status = LS_CALLER_SHUTDOWN;
+    break;
+  case LS_CALLER_CONNECTED:
+    line->status = LS_CALLER_SHUTDOWN;
+    break;
+  case LS_CALLER_SHUTDOWN:
+    destroy_line_mesh_tunnels (line);
+    GNUNET_CONTAINER_DLL_remove (lines_head,
+                                 lines_tail,
+                                 line);
+    GNUNET_free_non_null (line->audio_data);
+    GNUNET_free (line);
+    break;
+  }  
+}
+
+
 /**
  * Function to handle a hangup request message from the client
  *
@@ -297,11 +413,40 @@ handle_client_hangup_message (void *cls,
     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
     return;
   }
-  line->status = LS_CALLEE_LISTEN;
+  switch (line->status)
+  {
+  case LS_CALLEE_LISTEN:
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_OK);
+    return;
+  case LS_CALLEE_RINGING:
+    line->status = LS_CALLEE_SHUTDOWN;
+    break;
+  case LS_CALLEE_CONNECTED:
+    line->status = LS_CALLEE_SHUTDOWN;
+    break;
+  case LS_CALLEE_SHUTDOWN:
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_OK);
+    return;
+  case LS_CALLER_CALLING:
+    line->status = LS_CALLER_SHUTDOWN;
+    break;
+  case LS_CALLER_CONNECTED:
+    line->status = LS_CALLER_SHUTDOWN;
+    break;
+  case LS_CALLER_SHUTDOWN:
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_OK);
+    return;
+  }
   e = GNUNET_MQ_msg_extra (mhum,
                            len,
                            GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_HANG_UP);
   memcpy (&mhum[1], meta, len);
+  GNUNET_MQ_notify_sent (e,
+                         &mq_done_finish_caller_shutdown,
+                         line);
   GNUNET_MQ_send (line->reliable_mq, e);
   GNUNET_SERVER_receive_done (client, GNUNET_OK);
 }
@@ -328,6 +473,7 @@ handle_client_call_message (void *cls,
   line = GNUNET_SERVER_client_get_user_context (client, struct Line);
   if (NULL != line)
   {
+    GNUNET_break (0);
     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
     return;
   }
@@ -368,6 +514,39 @@ handle_client_call_message (void *cls,
 }
 
 
+/**
+ * Transmit audio data via unreliable mesh channel.
+ *
+ * @param cls the `struct Line` we are transmitting for
+ * @param size number of bytes available in @a buf
+ * @param buf where to copy the data
+ * @return number of bytes copied to @buf
+ */
+static size_t
+transmit_line_audio (void *cls,
+                     size_t size,
+                     void *buf)
+{
+  struct Line *line = cls;
+  struct MeshAudioMessage *mam = buf;
+  
+  line->unreliable_mth = NULL;
+  if ( (NULL == buf) ||
+       (size < sizeof (struct MeshAudioMessage) + line->audio_size) )
+    {
+    /* eh, other error handling? */
+    return 0;
+  }
+  mam->header.size = htons (sizeof (struct MeshAudioMessage) + line->audio_size);
+  mam->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_AUDIO);
+  mam->remote_line = htonl (line->remote_line);
+  memcpy (&mam[1], line->audio_data, line->audio_size);
+  GNUNET_free (line->audio_data);
+  line->audio_data = NULL;
+  return sizeof (struct MeshAudioMessage) + line->audio_size;  
+}
+
+
 /**
  * Function to handle audio data from the client
  *
@@ -381,13 +560,84 @@ handle_client_audio_message (void *cls,
                              const struct GNUNET_MessageHeader *message)
 {
   const struct ClientAudioMessage *msg;
+  struct Line *line;
+  size_t size;
 
+  size = ntohs (message->size) - sizeof (struct ClientAudioMessage);
   msg = (struct ClientAudioMessage *) message;
-  GNUNET_break (0); // FIXME
+  line = GNUNET_SERVER_client_get_user_context (client, struct Line);
+  if (NULL == line)
+  {
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    return;
+  }
+  switch (line->status)
+  {
+  case LS_CALLEE_LISTEN:
+  case LS_CALLEE_RINGING:
+  case LS_CALLER_CALLING:
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    return;
+  case LS_CALLEE_CONNECTED:
+  case LS_CALLER_CONNECTED:
+    /* common case, handled below */
+    break;
+  case LS_CALLEE_SHUTDOWN:
+  case LS_CALLER_SHUTDOWN:
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Mesh audio channel in shutdown; audio data dropped\n");
+    GNUNET_SERVER_receive_done (client, GNUNET_OK);
+    return;
+  }
+  if (NULL == line->tunnel_unreliable)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                _("Mesh audio channel not ready; audio data dropped\n"));
+    GNUNET_SERVER_receive_done (client, GNUNET_OK);    
+    return;
+  }
+  if (NULL != line->unreliable_mth)
+  {
+    /* NOTE: we may want to not do this and instead combine the data */
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Dropping previous audio data segment with %u bytes\n",
+                line->audio_size);
+    GNUNET_MESH_notify_transmit_ready_cancel (line->unreliable_mth);
+    GNUNET_free (line->audio_data);
+  }
+  line->audio_size = size;
+  line->audio_data = GNUNET_malloc (line->audio_size);
+  memcpy (line->audio_data,
+          &msg[1],
+          size);
+  line->unreliable_mth = GNUNET_MESH_notify_transmit_ready (line->tunnel_unreliable,
+                                                            GNUNET_NO,
+                                                            GNUNET_TIME_UNIT_FOREVER_REL,
+                                                            sizeof (struct MeshAudioMessage) 
+                                                            + line->audio_size,
+                                                            &transmit_line_audio,
+                                                            line);
   GNUNET_SERVER_receive_done (client, GNUNET_OK);
 }
 
 
+/**
+ * We are done signalling shutdown to the other peer.  
+ * Destroy the tunnel.
+ *
+ * @param cls the `struct GNUNET_MESH_tunnel` to destroy
+ */
+static void
+mq_done_destroy_tunnel (void *cls)
+{
+  struct GNUNET_MESH_Tunnel *tunnel = cls;
+  
+  GNUNET_MESH_tunnel_destroy (tunnel);
+}
+
+
 /**
  * Function to handle a ring message incoming over mesh
  *
@@ -433,7 +683,11 @@ handle_mesh_ring_message (void *cls,
                 _("No available phone for incoming call on line %u, sending BUSY signal\n"),
                 ntohl (msg->remote_line));
     e = GNUNET_MQ_msg (busy, GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_BUSY);
+    GNUNET_MQ_notify_sent (e,
+                           &mq_done_destroy_tunnel,
+                           tunnel);
     GNUNET_MQ_send (line->reliable_mq, e);
+    GNUNET_MESH_receive_done (tunnel); /* needed? */
     return GNUNET_OK;
   }
   line->status = LS_CALLEE_RINGING;
@@ -449,6 +703,7 @@ handle_mesh_ring_message (void *cls,
                                               line->client,
                                               &cring.header,
                                               GNUNET_NO);
+  GNUNET_MESH_receive_done (tunnel);
   return GNUNET_OK;
 }
 
@@ -468,10 +723,67 @@ handle_mesh_hangup_message (void *cls,
                             void **tunnel_ctx,
                             const struct GNUNET_MessageHeader *message)
 {
+  struct Line *line = *tunnel_ctx;
   const struct MeshPhoneHangupMessage *msg;
+  const char *reason;
+  size_t len = ntohs (message->size) - sizeof (struct MeshPhoneHangupMessage);
+  char buf[len + sizeof (struct ClientPhoneHangupMessage)];
+  struct ClientPhoneHangupMessage *hup;
   
   msg = (const struct MeshPhoneHangupMessage *) message;
-  GNUNET_break (0); // FIXME
+  len = ntohs (msg->header.size) - sizeof (struct MeshPhoneHangupMessage);
+  reason = (const char *) &msg[1];
+  if ( (0 == len) ||
+       ('\0' != reason[len - 1]) )
+  {
+    reason = NULL;
+    len = 0;
+  }
+  if (NULL == line)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "HANGUP message received for non-existing line, dropping tunnel.\n");
+    return GNUNET_SYSERR;
+  }
+  *tunnel_ctx = NULL;
+  switch (line->status)
+  {
+  case LS_CALLEE_LISTEN:
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  case LS_CALLEE_RINGING:
+    line->status = LS_CALLEE_LISTEN;
+    destroy_line_mesh_tunnels (line);
+    break;
+  case LS_CALLEE_CONNECTED:
+    line->status = LS_CALLEE_LISTEN;
+    destroy_line_mesh_tunnels (line);
+    break;
+  case LS_CALLEE_SHUTDOWN:
+    line->status = LS_CALLEE_LISTEN;
+    destroy_line_mesh_tunnels (line);
+    return GNUNET_OK;
+  case LS_CALLER_CALLING:
+    line->status = LS_CALLER_SHUTDOWN;
+    mq_done_finish_caller_shutdown (line);
+    break;
+  case LS_CALLER_CONNECTED:
+    line->status = LS_CALLER_SHUTDOWN;
+    mq_done_finish_caller_shutdown (line);
+    break;
+  case LS_CALLER_SHUTDOWN:
+    mq_done_finish_caller_shutdown (line);
+    return GNUNET_OK;
+  }
+  hup = (struct ClientPhoneHangupMessage *) buf;
+  hup->header.size = sizeof (buf);
+  hup->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP);
+  memcpy (&hup[1], reason, len);
+  GNUNET_SERVER_notification_context_unicast (nc,
+                                              line->client,
+                                              &hup->header,
+                                              GNUNET_NO);
+  GNUNET_MESH_receive_done (tunnel);
   return GNUNET_OK;
 }
 
@@ -493,19 +805,68 @@ handle_mesh_pickup_message (void *cls,
 {
   const struct MeshPhonePickupMessage *msg;
   struct Line *line = *tunnel_ctx;
+  const char *metadata;
+  size_t len = ntohs (message->size) - sizeof (struct MeshPhonePickupMessage);
+  char buf[len + sizeof (struct ClientPhonePickupMessage)];
+  struct ClientPhonePickupMessage *pick;
   
   msg = (const struct MeshPhonePickupMessage *) message;
-  GNUNET_break (0); // FIXME
-
-
+  len = ntohs (msg->header.size) - sizeof (struct MeshPhonePickupMessage);
+  metadata = (const char *) &msg[1];
+  if ( (0 == len) ||
+       ('\0' != metadata[len - 1]) )
+  {
+    metadata = NULL;
+    len = 0;
+  }
+  if (NULL == line)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "PICKUP message received for non-existing line, dropping tunnel.\n");
+    return GNUNET_SYSERR;
+  }
+  GNUNET_MESH_receive_done (tunnel);
+  switch (line->status)
+  {
+  case LS_CALLEE_LISTEN:
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  case LS_CALLEE_RINGING:
+  case LS_CALLEE_CONNECTED:
+    GNUNET_break_op (0);
+    destroy_line_mesh_tunnels (line);
+    line->status = LS_CALLEE_LISTEN;
+    return GNUNET_SYSERR;
+  case LS_CALLEE_SHUTDOWN:
+    GNUNET_break_op (0);
+    line->status = LS_CALLEE_LISTEN;
+    destroy_line_mesh_tunnels (line);
+    break;
+  case LS_CALLER_CALLING:
+    line->status = LS_CALLER_CONNECTED;
+    break;
+  case LS_CALLER_CONNECTED:
+    GNUNET_break_op (0);
+    return GNUNET_OK;
+  case LS_CALLER_SHUTDOWN:
+    GNUNET_break_op (0);
+    mq_done_finish_caller_shutdown (line);
+    return GNUNET_SYSERR;
+  }
+  pick = (struct ClientPhonePickupMessage *) buf;
+  pick->header.size = sizeof (buf);
+  pick->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICK_UP);
+  memcpy (&pick[1], metadata, len);
+  GNUNET_SERVER_notification_context_unicast (nc,
+                                              line->client,
+                                              &pick->header,
+                                              GNUNET_NO);
   line->tunnel_unreliable = GNUNET_MESH_tunnel_create (mesh,
                                                        line,
                                                        &line->target,
                                                        GNUNET_APPLICATION_TYPE_CONVERSATION_AUDIO,
                                                        GNUNET_YES,
                                                        GNUNET_NO);
-  
-
   return GNUNET_OK;
 }
 
@@ -525,10 +886,49 @@ handle_mesh_busy_message (void *cls,
                           void **tunnel_ctx,
                           const struct GNUNET_MessageHeader *message)
 {
-  const struct MeshPhoneBusyMessage *msg;
-  
-  msg = (const struct MeshPhoneBusyMessage *) message;
-  GNUNET_break (0); // FIXME
+  struct Line *line = *tunnel_ctx;
+  struct ClientPhoneBusyMessage busy;
+
+  if (NULL == line)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "HANGUP message received for non-existing line, dropping tunnel.\n");
+    return GNUNET_SYSERR;
+  }
+  busy.header.size = sizeof (busy);
+  busy.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_BUSY);
+  GNUNET_SERVER_notification_context_unicast (nc,
+                                              line->client,
+                                              &busy.header,
+                                              GNUNET_NO);
+  GNUNET_MESH_receive_done (tunnel);
+  *tunnel_ctx = NULL;
+  switch (line->status)
+  {
+  case LS_CALLEE_LISTEN:
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  case LS_CALLEE_RINGING:
+    GNUNET_break_op (0);
+    break;
+  case LS_CALLEE_CONNECTED:
+    GNUNET_break_op (0);
+    break;
+  case LS_CALLEE_SHUTDOWN:
+    GNUNET_break_op (0);
+    break;
+  case LS_CALLER_CALLING:
+    line->status = LS_CALLER_SHUTDOWN;
+    mq_done_finish_caller_shutdown (line);
+    break;
+  case LS_CALLER_CONNECTED:
+    line->status = LS_CALLER_SHUTDOWN;
+    mq_done_finish_caller_shutdown (line);
+    break;
+  case LS_CALLER_SHUTDOWN:
+    mq_done_finish_caller_shutdown (line);
+    break;
+  }
   return GNUNET_OK;
 }
 
@@ -549,9 +949,44 @@ handle_mesh_audio_message (void *cls,
                            const struct GNUNET_MessageHeader *message)
 {
   const struct MeshAudioMessage *msg;
+  struct Line *line = *tunnel_ctx;
+  struct GNUNET_PeerIdentity sender;
+  size_t msize = ntohs (message->size) - sizeof (struct MeshAudioMessage);
+  char buf[msize + sizeof (struct ClientAudioMessage)];
+  struct ClientAudioMessage *cam;
   
   msg = (const struct MeshAudioMessage *) message;
-  GNUNET_break (0); // FIXME
+  if (NULL == line)
+  {
+    sender = *GNUNET_MESH_tunnel_get_info (tunnel,
+                                           GNUNET_MESH_OPTION_PEER)->peer;
+    for (line = lines_head; NULL != line; line = line->next)
+      if ( (line->local_line == ntohl (msg->remote_line)) &&
+           (LS_CALLEE_CONNECTED == line->status) &&
+           (0 == memcmp (&line->target,
+                         &sender,
+                         sizeof (struct GNUNET_PeerIdentity))) &&
+           (NULL == line->tunnel_unreliable) )
+        break;
+    if (NULL == line)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "Received AUDIO data for non-existing line %u, dropping.\n",
+                  ntohl (msg->remote_line));
+      return GNUNET_SYSERR;
+    }
+    line->tunnel_unreliable = tunnel;
+    *tunnel_ctx = line;
+  }
+  cam = (struct ClientAudioMessage *) buf;
+  cam->header.size = htons (sizeof (buf));
+  cam->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO);
+  memcpy (&cam[1], &msg[1], msize);
+  GNUNET_SERVER_notification_context_unicast (nc,
+                                              line->client,
+                                              &cam->header,
+                                              GNUNET_YES);
+  GNUNET_MESH_receive_done (tunnel);
   return GNUNET_OK;
 }
 
@@ -572,10 +1007,9 @@ inbound_tunnel (void *cls,
                const struct GNUNET_PeerIdentity *initiator, 
                 uint32_t port)
 {
-  
-  GNUNET_break (0); // FIXME
   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-             _("Received incoming tunnel on port %d\n"), port);
+             _("Received incoming tunnel on port %d\n"), 
+              port);
   return NULL;
 }
 
@@ -594,7 +1028,56 @@ inbound_end (void *cls,
              const struct GNUNET_MESH_Tunnel *tunnel,
             void *tunnel_ctx)
 {
-  GNUNET_break (0); // FIXME
+  struct Line *line = tunnel_ctx;
+  struct ClientPhoneHangupMessage hup;
+
+  if (NULL == line)
+    return;
+  if (line->tunnel_unreliable == tunnel)
+  {
+    line->tunnel_unreliable = NULL;
+    return;
+  }
+  hup.header.size = sizeof (hup);
+  hup.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP);
+  switch (line->status)
+  {
+  case LS_CALLEE_LISTEN:
+    GNUNET_break (0);
+    return;
+  case LS_CALLEE_RINGING:
+  case LS_CALLEE_CONNECTED:
+    GNUNET_SERVER_notification_context_unicast (nc,
+                                                line->client,
+                                                &hup.header,
+                                                GNUNET_NO);
+    line->status = LS_CALLEE_LISTEN;
+    break;
+  case LS_CALLEE_SHUTDOWN:
+    line->status = LS_CALLEE_LISTEN;
+    destroy_line_mesh_tunnels (line);
+    break;
+  case LS_CALLER_CALLING:
+  case LS_CALLER_CONNECTED:
+    GNUNET_SERVER_notification_context_unicast (nc,
+                                                line->client,
+                                                &hup.header,
+                                                GNUNET_NO);
+    destroy_line_mesh_tunnels (line);
+    GNUNET_CONTAINER_DLL_remove (lines_head,
+                                 lines_tail,
+                                 line);
+    GNUNET_free_non_null (line->audio_data);
+    GNUNET_free (line);
+    break;
+  case LS_CALLER_SHUTDOWN:
+    destroy_line_mesh_tunnels (line);
+    GNUNET_CONTAINER_DLL_remove (lines_head,
+                                 lines_tail,
+                                 line);
+    GNUNET_free (line);
+    break;
+  }
 }
 
 
@@ -631,7 +1114,6 @@ static void
 do_shutdown (void *cls,
              const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
-  GNUNET_break (0); // FIXME
   if (NULL != mesh)
   {
     GNUNET_MESH_disconnect (mesh);