- add underlay api implementation
[oweals/gnunet.git] / src / conversation / gnunet-service-conversation.c
index 181ba835188aaac9902141514afee0aefc2eed27..df8d4e9f24cf9bfdde73202854738f136e7edef3 100644 (file)
 /*
-                This file is part of GNUnet.
-                (C) 
-
-                GNUnet is free software; you can redistribute it and/or modify
-                it under the terms of the GNU General Public License as published
-                by the Free Software Foundation; either version 3, or (at your
-                option) any later version.
-
-                GNUnet is distributed in the hope that it will be useful, but
-                WITHOUT ANY WARRANTY; without even the implied warranty of
-                MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-                General Public License for more details.
-
-                You should have received a copy of the GNU General Public License
-                along with GNUnet; see the file COPYING.  If not, write to the
-                Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-                Boston, MA 02111-1307, USA.
+  This file is part of GNUnet.
+  (C) 2013 Christian Grothoff (and other contributing authors)
+
+  GNUnet is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published
+  by the Free Software Foundation; either version 3, or (at your
+  option) any later version.
+
+  GNUnet is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with GNUnet; see the file COPYING.  If not, write to the
+  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+  Boston, MA 02111-1307, USA.
 */
-
 /**
  * @file conversation/gnunet-service-conversation.c
  * @brief conversation service implementation
  * @author Simon Dieterle
  * @author Andreas Fuchs
- * STRUCTURE:
- * - Variables
- * - AUXILIARY FUNCTIONS
- * - SENDING FUNCTIONS CL -> SERVER
- * - RECEIVE FUNCTIONS CL -> SERVER
- * - SENDING FUNCTIONS MESH
- * - RECEIVE FUNCTIONS MESH
- * - HELPER
- * - TUNNEL HANDLING
- * - CLIENT HANDLING
+ * @author Christian Grothoff
  */
-#include <gnunet/platform.h>
-#include <gnunet/gnunet_util_lib.h>
-#include <gnunet/gnunet_constants.h>
-#include <gnunet/gnunet_mesh_service.h>
-#include "gnunet_conversation.h"
-#include "gnunet_protocols_conversation.h"
-
-/******************************************************** 
- * Ugly hack because of not working MESH API
-*/
-typedef uint32_t MESH_TunnelNumber;
-struct GNUNET_MESH_Tunnel
-{
-  struct GNUNET_MESH_Tunnel *next;
-  struct GNUNET_MESH_Tunnel *prev;
-  struct GNUNET_MESH_Handle *mesh;
-  MESH_TunnelNumber tid;
-  uint32_t port;
-  GNUNET_PEER_Id peer;
-  void *ctx;
-  unsigned int packet_size;
-  int buffering;
-  int reliable;
-  int allow_send;
-};
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_protocols.h"
+#include "gnunet_applications.h"
+#include "gnunet_constants.h"
+#include "gnunet_signatures.h"
+#include "gnunet_mesh_service.h"
+#include "gnunet_conversation_service.h"
+#include "conversation.h"
 
 
 /**
- * Our configuration.
+ * How long is our signature on a call valid?  Needs to be long enough for time zone
+ * differences and network latency to not matter.  No strong need for it to be short,
+ * but we simply like all signatures to eventually expire.
  */
-static const struct GNUNET_CONFIGURATION_Handle *cfg;
+#define RING_TIMEOUT GNUNET_TIME_UNIT_DAYS
 
-/**
- * Head of the list of current clients.
- */
-static struct GNUNET_CONTAINER_SList *clients;
 
 /**
- * Notification context containing all connected clients.
+ * A line connects a local client with a mesh channel (or, if it is an
+ * open line, is waiting for a mesh channel).
  */
-struct GNUNET_SERVER_NotificationContext *nc = NULL;
-
-/**
-* The connection status
-*/
-static struct ConnectionStatus connection;
+struct Line;
 
 /**
-* Handle for the record helper
-*/
-static struct GNUNET_HELPER_Handle *record_helper;
-
-/** Handle for the playback handler
-*
-*/
-static struct GNUNET_HELPER_Handle *playback_helper;
-
-/**
-* Handle for mesh
-*/
-static struct GNUNET_MESH_Handle *mesh;
-
-/**
-* Transmit handle for audio messages
-*/
-static struct GNUNET_MESH_TransmitHandle *mth = NULL;
-
-/**
-* Handle for the reliable tunnel (contol data)
-*/
-static struct GNUNET_MESH_Tunnel *tunnel_reliable;
-
-/**
-* Handle for unreliable tunnel (audio data)
-*/
-static struct GNUNET_MESH_Tunnel *tunnel_unreliable;
-
-/**
-* List for missed calls
-*/
-struct GNUNET_CONTAINER_SList *missed_calls;
-
-/**
-* List for peers to notify that we are available again
-*/
-struct GNUNET_CONTAINER_SList *peers_to_notify;
-
-/**
-* Audio buffer (outgoing)
-*/
-struct GNUNET_CONTAINER_SList *audio_buffer;
-
-/**
-* The pointer to the task for sending audio
-*/
-GNUNET_SCHEDULER_TaskIdentifier audio_task;
-
-/**
-* The pointer to the task for checking timeouts an calling a peer
-*/
-GNUNET_SCHEDULER_TaskIdentifier timeout_task;
-
-/**
-* Sequencenumber for the pakets (for evaltuation purposes)
-*/
-int SequenceNumber = 0;
-
-/**
-* Timestamp for call statistics
-*/
-static struct GNUNET_TIME_Absolute start_time;
-
-/**
- * Number of payload packes sent
- */
-static int data_sent;
-static int data_sent_size;
-
-/**
- * Number of payload packets received
+ * The possible connection status
  */
-static int data_received;
-static int data_received_size;
-
-/******************************************************************************/
-/***********************     AUXILIARY FUNCTIONS      *************************/
-/******************************************************************************/
-
-/**
-* Function which displays some call stats
-*/
-static void
-show_end_data (void)
-{
-  static struct GNUNET_TIME_Absolute end_time;
-  static struct GNUNET_TIME_Relative total_time;
-
-  end_time = GNUNET_TIME_absolute_get ();
-  total_time = GNUNET_TIME_absolute_get_difference (start_time, end_time);
-  FPRINTF (stderr, "\nResults of send\n");
-  FPRINTF (stderr, "Test time %s\n",
-          GNUNET_STRINGS_relative_time_to_string (total_time,
-                                                  GNUNET_NO));
-  FPRINTF (stderr, "Test total packets: %d\n", 
-          data_sent);
-  FPRINTF (stderr, "Test bandwidth: %f kb/s\n", 
-          data_sent_size * 1000.0 / (total_time.rel_value_us + 1));    // 4bytes * us
-  FPRINTF (stderr, "Test throughput: %f packets/s\n\n",
-          data_sent * 1000000.0 / (total_time.rel_value_us + 1));      // packets * us
-
-  FPRINTF (stderr, "\nResults of recv\n");
-  FPRINTF (stderr, "Test time %s\n",
-          GNUNET_STRINGS_relative_time_to_string (total_time,
-                                                  GNUNET_NO));
-  FPRINTF (stderr, "Test total packets: %d\n", 
-          data_received);
-  FPRINTF (stderr, "Test bandwidth: %f kb/s\n", 
-          data_received_size * 1000.0 / (total_time.rel_value_us + 1));        // 4bytes * us
-  FPRINTF (stderr, "Test throughput: %f packets/s\n\n", 
-          data_received * 1000000.0 / (total_time.rel_value_us + 1));  // packets * us
-}
-
-/**
-* Function which sets the connection state to LISTEN
-*/
-static void
-status_to_listen (void)
+enum ChannelStatus
 {
+  /**
+   * Our phone is ringing, waiting for the client to pick up.
+   */
+  CS_CALLEE_RINGING,
+
+  /**
+   * We are talking!
+   */
+  CS_CALLEE_CONNECTED,
+
+  /**
+   * We're in shutdown, sending hangup messages before cleaning up.
+   */
+  CS_CALLEE_SHUTDOWN,
+
+  /**
+   * We are waiting for the phone to be picked up.
+   */
+  CS_CALLER_CALLING,
+
+  /**
+   * We are talking!
+   */
+  CS_CALLER_CONNECTED,
+
+  /**
+   * We're in shutdown, sending hangup messages before cleaning up.
+   */
+  CS_CALLER_SHUTDOWN
 
-  if (CONNECTED == connection.status)
-    {
-      show_end_data ();
-    }
-
-  if (timeout_task != GNUNET_SCHEDULER_NO_TASK)
-    {
-      GNUNET_SCHEDULER_cancel (timeout_task);
-      timeout_task = GNUNET_SCHEDULER_NO_TASK;
-    }
-
-  stop_helpers ();
-
-  connection.status = LISTEN;
-  connection.client = NULL;
-
-  data_sent = 0;
-  data_sent_size = 0;
-  data_received = 0;
-  data_received_size = 0;
+};
 
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Changed connection status to %s\n"),
-             "LISTEN");
-}
 
 /**
-* Function to terminate the active call
-*/
-static void
-terminate_call ()
+ * A `struct Channel` represents a mesh channel, which is a P2P
+ * connection to another conversation service.  Multiple channels can
+ * be attached the the same `struct Line`, which represents a local
+ * client.  We keep them in a linked list.
+ */
+struct Channel
 {
-  size_t msg_size;
-  msg_size = sizeof (struct MeshSessionTerminateMessage);
-  struct MeshSessionTerminateMessage *message_mesh_terminate =
-    (struct MeshSessionTerminateMessage *) GNUNET_malloc (msg_size);
-
-  if (NULL == message_mesh_terminate)
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                 _("Could not create MeshSessionTerminateMessage\n"));
-      status_to_listen ();
 
-      return;
-    }
+  /**
+   * This is a DLL.
+   */
+  struct Channel *next;
+
+  /**
+   * This is a DLL.
+   */
+  struct Channel *prev;
+
+  /**
+   * Line associated with the channel.
+   */
+  struct Line *line;
+
+  /**
+   * Handle for the reliable channel (contol data)
+   */
+  struct GNUNET_MESH_Channel *channel_reliable;
+
+  /**
+   * Handle for unreliable channel (audio data)
+   */
+  struct GNUNET_MESH_Channel *channel_unreliable;
+
+  /**
+   * Transmit handle for pending audio messages
+   */
+  struct GNUNET_MESH_TransmitHandle *unreliable_mth;
+
+  /**
+   * Message queue for control messages
+   */
+  struct GNUNET_MQ_Handle *reliable_mq;
+
+  /**
+   * Target of the line, if we are the caller.
+   */
+  struct GNUNET_PeerIdentity target;
+
+  /**
+   * Temporary buffer for audio data.
+   */
+  void *audio_data;
+
+  /**
+   * Number of bytes in @e audio_data.
+   */
+  size_t audio_size;
+
+  /**
+   * Channel identifier.
+   */
+  uint32_t cid;
+
+  /**
+   * Remote line number.
+   */
+  uint32_t remote_line;
+
+  /**
+   * Current status of this line.
+   */
+  enum ChannelStatus status;
+
+  /**
+   * #GNUNET_YES if the channel was suspended by the other peer.
+   */
+  int8_t suspended_remote;
+
+  /**
+   * #GNUNET_YES if the channel was suspended by the local client.
+   */
+  int8_t suspended_local;
 
-  message_mesh_terminate->header.size = htons (msg_size);
-  message_mesh_terminate->header.type =
-    htons (GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_SESSION_TERMINATE);
+};
 
-  if (NULL ==
-      GNUNET_MESH_notify_transmit_ready (tunnel_reliable, 0,
-                                        MAX_TRANSMIT_DELAY, msg_size,
-                                        &transmit_mesh_message,
-                                        (void *) message_mesh_terminate))
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                 _("Could not queue MeshSessionTerminateMessage\n"));
-      GNUNET_free (message_mesh_terminate);
-      status_to_listen ();
-    }
-}
 
 /**
-* Function to reject a call
-*
-* @param tunnel the tunnel where to reject the incoming call
-* @param reason te reson why the call is rejected
-*/
-static void
-reject_call (struct GNUNET_MESH_Tunnel *tunnel, int reason)
+ * A `struct Line` connects a local client with mesh channels.
+ */
+struct Line
 {
-  size_t msg_size;
-  msg_size = sizeof (struct MeshSessionRejectMessage);
-  struct MeshSessionRejectMessage *message_mesh_reject =
-    (struct MeshSessionRejectMessage *) GNUNET_malloc (msg_size);
-
-  if (NULL == message_mesh_reject)
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                 _("Could not create MeshSessionRejectMessage\n"));
-      status_to_listen ();
-
-      return;
-    }
+  /**
+   * Kept in a DLL.
+   */
+  struct Line *next;
+
+  /**
+   * Kept in a DLL.
+   */
+  struct Line *prev;
+
+  /**
+   * This is a DLL.
+   */
+  struct Channel *channel_head;
+
+  /**
+   * This is a DLL.
+   */
+  struct Channel *channel_tail;
+
+  /**
+   * Handle to the line client.
+   */
+  struct GNUNET_SERVER_Client *client;
+
+  /**
+   * Generator for channel IDs.
+   */
+  uint32_t cid_gen;
+
+  /**
+   * Our line number.
+   */
+  uint32_t local_line;
 
-  message_mesh_reject->header.size = htons (msg_size);
-  message_mesh_reject->header.type =
-    htons (GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_SESSION_REJECT);
-  message_mesh_reject->reason = htons (reason);
+};
 
-  if (NULL ==
-      GNUNET_MESH_notify_transmit_ready (tunnel_reliable, 0,
-                                        MAX_TRANSMIT_DELAY, msg_size,
-                                        &transmit_mesh_message,
-                                        (void *) message_mesh_reject))
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                 _("Could not queue MeshSessionRejectMessage\n"));
-      GNUNET_free (message_mesh_reject);
-      status_to_listen ();
-    }
-}
 
 /**
- * Check for timeout when calling a peer
- *
- * @param cls closure, NULL
- * @param tc the task context (can be NULL)
+ * Our configuration.
  */
-static void
-check_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Call timeout\n");
-
-  if (NULL ==
-      GNUNET_SERVER_notify_transmit_ready (connection.client,
-                                          sizeof (struct
-                                                  ServerClientNoAnswerMessage),
-                                          MAX_TRANSMIT_DELAY,
-                                          &transmit_server_no_answer_message,
-                                          NULL))
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                 _("Could not queue ServerClientNoAnswerMessage\n"));
-    }
-
-  terminate_call ();
-}
-
-/******************************************************************************/
-/***********************  SENDING FUNCTIONS CL -> SERVER    *******************/
-/******************************************************************************/
+static const struct GNUNET_CONFIGURATION_Handle *cfg;
 
 /**
- * Function called to send a session initiate message to the client.
- * "buf" will be NULL and "size" zero if the socket was closed for writing in
- * the meantime.
- *
- * @param cls closure, NULL
- * @param size number of bytes available in buf
- * @param buf where the callee should write the initiate message
- * @return number of bytes written to buf
+ * Notification context containing all connected clients.
  */
-static size_t
-transmit_server_initiate_message (void *cls, size_t size, void *buf)
-{
-  struct ServerClientSessionInitiateMessage *msg;
-  size_t msg_size;
-
-  msg_size = sizeof (struct ServerClientSessionInitiateMessage);
-
-  GNUNET_assert (size >= msg_size);
-
-  msg = (struct ServerClientSessionInitiateMessage *) buf;
-  msg->header.size = htons (msg_size);
-  msg->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_SC_SESSION_INITIATE);
-  memcpy (&(msg->peer), (struct GNUNET_PeerIdentity *) cls,
-         sizeof (struct GNUNET_PeerIdentity));
-
-  return msg_size;
-}
+static struct GNUNET_SERVER_NotificationContext *nc;
 
 /**
- * Function called to send a session accept message to the client.
- * "buf" will be NULL and "size" zero if the socket was closed for writing in
- * the meantime.
- *
- * @param cls closure, NULL
- * @param size number of bytes available in buf
- * @param buf where the callee should write the accept message
- * @return number of bytes written to buf
+ * Handle for mesh
  */
-static size_t
-transmit_server_accept_message (void *cls, size_t size, void *buf)
-{
-  struct ServerClientSessionAcceptMessage *msg;
-  size_t msg_size;
-
-  msg_size = sizeof (struct ServerClientSessionAcceptMessage);
-
-  GNUNET_assert (size >= msg_size);
-
-  msg = (struct ServerClientSessionAcceptMessage *) buf;
-  msg->header.size = htons (msg_size);
-  msg->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_SC_SESSION_ACCEPT);
-
-  return msg_size;
-}
+static struct GNUNET_MESH_Handle *mesh;
 
 /**
- * Function called to send a session reject message to the client.
- * "buf" will be NULL and "size" zero if the socket was closed for writing in
- * the meantime.
- *
- * @param cls closure, NULL
- * @param size number of bytes available in buf
- * @param buf where the callee should write the reject message
- * @return number of bytes written to buf
+ * Identity of this peer.
  */
-static size_t
-transmit_server_reject_message (void *cls, size_t size, void *buf)
-{
-  struct ServerClientSessionRejectMessage *msg;
-  size_t msg_size;
-
-  msg_size = sizeof (struct ServerClientSessionRejectMessage);
-
-  GNUNET_assert (size >= msg_size);
-
-  msg = (struct ServerClientSessionRejectMessage *) buf;
-  msg->header.size = htons (msg_size);
-  msg->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_SC_SESSION_REJECT);
-
-  if (NULL == cls)
-    {
-      msg->reason = htons (REJECT_REASON_NOT_AVAILABLE);
-    }
-  else
-    {
-      msg->reason = ((struct MeshSessionRejectMessage *) cls)->reason;
-    }
-
-  return msg_size;
-}
+static struct GNUNET_PeerIdentity my_identity;
 
 /**
- * Function called to send a session terminate message to the client.
- * "buf" will be NULL and "size" zero if the socket was closed for writing in
- * the meantime.
- *
- * @param cls closure, NULL
- * @param size number of bytes available in buf
- * @param buf where the callee should write the terminate message
- * @return number of bytes written to buf
+ * Head of DLL of active lines.
  */
-static size_t
-transmit_server_terminate_message (void *cls, size_t size, void *buf)
-{
-  struct ServerClientSessionTerminateMessage *msg;
-  size_t msg_size;
-
-  msg_size = sizeof (struct ServerClientSessionTerminateMessage);
-
-  GNUNET_assert (size >= msg_size);
-
-  msg = (struct ServerClientSessionTerminateMessage *) buf;
-  msg->header.size = htons (msg_size);
-  msg->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_SC_SESSION_TERMINATE);
-
-  return msg_size;
-}
+static struct Line *lines_head;
 
 /**
- * Function called to send a missed call message to the client.
- * "buf" will be NULL and "size" zero if the socket was closed for writing in
- * the meantime.
- *
- * @param cls closure, NULL
- * @param size number of bytes available in buf
- * @param buf where the callee should write the missed call message
- * @return number of bytes written to buf
+ * Tail of DLL of active lines.
  */
-static size_t
-transmit_server_missed_call_message (void *cls, size_t size, void *buf)
-{
-  struct ServerClientMissedCallMessage *msg;
-  msg = (struct ServerClientMissedCallMessage *) cls;
+static struct Line *lines_tail;
 
-  memcpy (buf, msg, size);
-  GNUNET_free (msg);
+/**
+ * Counter for generating local line numbers.
+ * FIXME: randomize generation in the future
+ * to eliminate information leakage.
+ */
+static uint32_t local_line_cnt;
 
-  return size;
-}
 
 /**
- * Function called to send a service blocked message to the client.
- * "buf" will be NULL and "size" zero if the socket was closed for writing in
- * the meantime.
+ * Function to register a phone.
  *
  * @param cls closure, NULL
- * @param size number of bytes available in buf
- * @param buf where the callee should write the service blocked message
- * @return number of bytes written to buf
+ * @param client the client from which the message is
+ * @param message the message from the client
  */
-static size_t
-transmit_server_service_blocked_message (void *cls, size_t size, void *buf)
+static void
+handle_client_register_message (void *cls,
+                                struct GNUNET_SERVER_Client *client,
+                                const struct GNUNET_MessageHeader *message)
 {
-  struct ServerClientServiceBlockedMessage *msg;
-  size_t msg_size;
-
-  msg_size = sizeof (struct ServerClientServiceBlockedMessage);
-
-  GNUNET_assert (size >= msg_size);
-
-  msg = (struct ServerClientServiceBlockedMessage *) buf;
-  msg->header.size = htons (msg_size);
-  msg->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_SC_SERVICE_BLOCKED);
-
-  return msg_size;
+  const struct ClientPhoneRegisterMessage *msg;
+  struct Line *line;
+
+  msg = (const struct ClientPhoneRegisterMessage *) message;
+  line = GNUNET_SERVER_client_get_user_context (client, struct Line);
+  if (NULL != line)
+  {
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    return;
+  }
+  line = GNUNET_new (struct Line);
+  line->client = client;
+  GNUNET_SERVER_notification_context_add (nc, client);
+  GNUNET_SERVER_client_set_user_context (client, line);
+  GNUNET_CONTAINER_DLL_insert (lines_head,
+                               lines_tail,
+                               line);
+  line->local_line = ntohl (msg->line) & (~ (1 << 31));
+  GNUNET_SERVER_receive_done (client, GNUNET_OK);
 }
 
+
 /**
- * Function called to send a peer not connected message to the client.
- * "buf" will be NULL and "size" zero if the socket was closed for writing in
- * the meantime.
+ * Function to handle a pickup request message from the client
  *
  * @param cls closure, NULL
- * @param size number of bytes available in buf
- * @param buf where the callee should write the peer not connected message
- * @return number of bytes written to buf
+ * @param client the client from which the message is
+ * @param message the message from the client
  */
-static size_t
-transmit_server_peer_not_connected_message (void *cls, size_t size, void *buf)
+static void
+handle_client_pickup_message (void *cls,
+                              struct GNUNET_SERVER_Client *client,
+                              const struct GNUNET_MessageHeader *message)
 {
-  struct ServerClientPeerNotConnectedMessage *msg;
-  size_t msg_size;
-
-  msg_size = sizeof (struct ServerClientPeerNotConnectedMessage);
-
-  GNUNET_assert (size >= msg_size);
-
-  msg = (struct ServerClientPeerNotConnectedMessage *) buf;
-  msg->header.size = htons (msg_size);
-  msg->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_SC_PEER_NOT_CONNECTED);
-
-  return msg_size;
+  const struct ClientPhonePickupMessage *msg;
+  struct GNUNET_MQ_Envelope *e;
+  struct MeshPhonePickupMessage *mppm;
+  struct Line *line;
+  struct Channel *ch;
+
+  msg = (const struct ClientPhonePickupMessage *) message;
+  line = GNUNET_SERVER_client_get_user_context (client, struct Line);
+  if (NULL == line)
+  {
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    return;
+  }
+  for (ch = line->channel_head; NULL != ch; ch = ch->next)
+    if (msg->cid == ch->cid)
+      break;
+  if (NULL == ch)
+  {
+    /* could have been destroyed asynchronously, ignore message */
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Channel %u not found\n",
+                msg->cid);
+    return;
+  }
+  switch (ch->status)
+  {
+  case CS_CALLEE_RINGING:
+    ch->status = CS_CALLEE_CONNECTED;
+    break;
+  case CS_CALLEE_CONNECTED:
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    return;
+  case CS_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 CS_CALLER_CALLING:
+  case CS_CALLER_CONNECTED:
+  case CS_CALLER_SHUTDOWN:
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    return;
+  }
+  GNUNET_break (CS_CALLEE_CONNECTED == ch->status);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Sending PICK_UP message to mesh\n");
+  e = GNUNET_MQ_msg (mppm,
+                     GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_PICK_UP);
+  GNUNET_MQ_send (ch->reliable_mq, e);
+  GNUNET_SERVER_receive_done (client, GNUNET_OK);
 }
 
+
 /**
- * Function called to send a peer no answer message to the client.
- * "buf" will be NULL and "size" zero if the socket was closed for writing in
- * the meantime.
+ * Destroy a channel.
  *
- * @param cls closure, NULL
- * @param size number of bytes available in buf
- * @param buf where the callee should write the peer no answer message
- * @return number of bytes written to buf
+ * @param ch channel to destroy.
  */
-static size_t
-transmit_server_no_answer_message (void *cls, size_t size, void *buf)
+static void
+destroy_line_mesh_channels (struct Channel *ch)
 {
-  struct ServerClientNoAnswerMessage *msg;
-  size_t msg_size;
-
-  msg_size = sizeof (struct ServerClientNoAnswerMessage);
-
-  GNUNET_assert (size >= msg_size);
-
-  msg = (struct ServerClientNoAnswerMessage *) buf;
-  msg->header.size = htons (msg_size);
-  msg->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_SC_NO_ANSWER);
-
-  return msg_size;
+  struct Line *line = ch->line;
+  struct GNUNET_MESH_Channel *t;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Destroying mesh channels\n");
+  if (NULL != ch->reliable_mq)
+  {
+    GNUNET_MQ_destroy (ch->reliable_mq);
+    ch->reliable_mq = NULL;
+  }
+  if (NULL != ch->unreliable_mth)
+  {
+    GNUNET_MESH_notify_transmit_ready_cancel (ch->unreliable_mth);
+    ch->unreliable_mth = NULL;
+  }
+  if (NULL != (t = ch->channel_unreliable))
+  {
+    ch->channel_unreliable = NULL;
+    GNUNET_MESH_channel_destroy (t);
+  }
+  if (NULL != (t = ch->channel_reliable))
+  {
+    ch->channel_reliable = NULL;
+    GNUNET_MESH_channel_destroy (t);
+  }
+  GNUNET_CONTAINER_DLL_remove (line->channel_head,
+                               line->channel_tail,
+                               ch);
+  GNUNET_free_non_null (ch->audio_data);
+  GNUNET_free (ch);
 }
 
+
 /**
- * Function called to send a error message to the client.
- * "buf" will be NULL and "size" zero if the socket was closed for writing in
- * the meantime.
+ * We are done signalling shutdown to the other peer.  Close down
+ * the channel.
  *
- * @param cls closure, NULL
- * @param size number of bytes available in buf
- * @param buf where the callee should write the error message
- * @return number of bytes written to buf
+ * @param cls the `struct Channel` to reset/terminate
  */
-static size_t
-transmit_server_error_message (void *cls, size_t size, void *buf)
+static void
+mq_done_finish_caller_shutdown (void *cls)
 {
-  struct ServerClientErrorMessage *msg;
-  size_t msg_size;
-
-  msg_size = sizeof (struct ServerClientErrorMessage);
-
-  GNUNET_assert (size >= msg_size);
-
-  msg = (struct ServerClientErrorMessage *) buf;
-  msg->header.size = htons (msg_size);
-  msg->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_SC_ERROR);
-
-  return msg_size;
+  struct Channel *ch = cls;
+
+  switch (ch->status)
+  {
+  case CS_CALLEE_RINGING:
+    GNUNET_break (0);
+    break;
+  case CS_CALLEE_CONNECTED:
+    GNUNET_break (0);
+    break;
+  case CS_CALLEE_SHUTDOWN:
+    destroy_line_mesh_channels (ch);
+    break;
+  case CS_CALLER_CALLING:
+    GNUNET_break (0);
+    break;
+  case CS_CALLER_CONNECTED:
+    GNUNET_break (0);
+    break;
+  case CS_CALLER_SHUTDOWN:
+    destroy_line_mesh_channels (ch);
+    break;
+  }
 }
 
-/******************************************************************************/
-/***********************  RECEIVE FUNCTIONS CL -> SERVER   ********************/
-/******************************************************************************/
 
 /**
- * Function to handle a session initiate message from the client
+ * Function to handle a hangup request message from the client
  *
  * @param cls closure, NULL
  * @param client the client from which the message is
  * @param message the message from the client
-*/
+ */
 static void
-handle_session_initiate_message (void *cls,
-                                struct GNUNET_SERVER_Client *client,
-                                const struct GNUNET_MessageHeader *message)
+handle_client_hangup_message (void *cls,
+                              struct GNUNET_SERVER_Client *client,
+                              const struct GNUNET_MessageHeader *message)
 {
-  static uint32_t port = 50002;
-  size_t msg_size;
-  struct ClientServerSessionInitiateMessage *msg =
-    (struct ClientServerSessionInitiateMessage *) message;
-  struct GNUNET_PeerIdentity *peer = &(msg->peer);
-
+  const struct ClientPhoneHangupMessage *msg;
+  struct GNUNET_MQ_Envelope *e;
+  struct MeshPhoneHangupMessage *mhum;
+  struct Line *line;
+  struct Channel *ch;
+
+  msg = (const struct ClientPhoneHangupMessage *) message;
+  line = GNUNET_SERVER_client_get_user_context (client, struct Line);
+  if (NULL == line)
+  {
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    return;
+  }
+  for (ch = line->channel_head; NULL != ch; ch = ch->next)
+    if (msg->cid == ch->cid)
+      break;
+  if (NULL == ch)
+  {
+    /* could have been destroyed asynchronously, ignore message */
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Channel %u not found\n",
+                msg->cid);
+    return;
+  }
+
+  switch (ch->status)
+  {
+  case CS_CALLEE_RINGING:
+    ch->status = CS_CALLEE_SHUTDOWN;
+    break;
+  case CS_CALLEE_CONNECTED:
+    ch->status = CS_CALLEE_SHUTDOWN;
+    break;
+  case CS_CALLEE_SHUTDOWN:
+    /* maybe the other peer closed asynchronously... */
+    return;
+  case CS_CALLER_CALLING:
+    ch->status = CS_CALLER_SHUTDOWN;
+    break;
+  case CS_CALLER_CONNECTED:
+    ch->status = CS_CALLER_SHUTDOWN;
+    break;
+  case CS_CALLER_SHUTDOWN:
+    /* maybe the other peer closed asynchronously... */
+    return;
+  }
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Sending HANG_UP message via mesh\n");
+  e = GNUNET_MQ_msg (mhum,
+                     GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_HANG_UP);
+  GNUNET_MQ_notify_sent (e,
+                         &mq_done_finish_caller_shutdown,
+                         ch);
+  GNUNET_MQ_send (ch->reliable_mq, e);
   GNUNET_SERVER_receive_done (client, GNUNET_OK);
-
-  if (NULL != connection.client)
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                 _("There is already a peer in interaction\n"));
-      GNUNET_SERVER_notify_transmit_ready (client,
-                                          sizeof (struct
-                                                  ServerClientServiceBlockedMessage),
-                                          MAX_TRANSMIT_DELAY,
-                                          &transmit_server_service_blocked_message,
-                                          NULL);
-
-      return;
-    }
-
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Creating tunnel to: %s\n"),
-             GNUNET_i2s_full (peer));
-  tunnel_reliable =
-    GNUNET_MESH_tunnel_create (mesh, NULL, peer, port, GNUNET_NO, GNUNET_NO);
-  if (NULL == tunnel_reliable)
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                 _("Could not create reliable tunnel\n"));
-      GNUNET_SERVER_notify_transmit_ready (client,
-                                          sizeof (struct
-                                                  ServerClientPeerNotConnectedMessage),
-                                          MAX_TRANSMIT_DELAY,
-                                          &transmit_server_peer_not_connected_message,
-                                          NULL);
-
-      return;
-    }
-
-  msg_size = sizeof (struct MeshSessionInitiateMessage);
-  struct MeshSessionInitiateMessage *message_mesh_initiate =
-    (struct MeshSessionInitiateMessage *) GNUNET_malloc (msg_size);
-
-  if (NULL == message_mesh_initiate)
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                 _("Could not create MeshSessionInitiateMessage\n"));
-      GNUNET_MESH_tunnel_destroy (tunnel_reliable);
-      tunnel_reliable = NULL;
-      GNUNET_SERVER_notify_transmit_ready (client,
-                                          sizeof (struct
-                                                  ServerClientErrorMessage),
-                                          MAX_TRANSMIT_DELAY,
-                                          &transmit_server_error_message,
-                                          NULL);
-
-      return;
-    }
-
-  message_mesh_initiate->header.size = htons (msg_size);
-  message_mesh_initiate->header.type =
-    htons (GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_SESSION_INITIATE);
-
-  if (NULL ==
-      GNUNET_MESH_notify_transmit_ready (tunnel_reliable, 0,
-                                        MAX_TRANSMIT_DELAY, msg_size,
-                                        &transmit_mesh_message,
-                                        (void *) message_mesh_initiate))
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                 _("Could not queue MeshSessionInitiateMessage\n"));
-      GNUNET_MESH_tunnel_destroy (tunnel_reliable);
-      tunnel_reliable = NULL;
-      GNUNET_free (message_mesh_initiate);
-      GNUNET_SERVER_notify_transmit_ready (client,
-                                          sizeof (struct
-                                                  ServerClientErrorMessage),
-                                          MAX_TRANSMIT_DELAY,
-                                          &transmit_server_error_message,
-                                          NULL);
-
-      return;
-    }
-
-  connection.status = CALLER;
-  connection.client = client;
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Changed connection status to %d\n"),
-             connection.status);
-  memcpy (&(connection.peer), peer, sizeof (struct GNUNET_PeerIdentity));
-
-  return;
 }
 
+
 /**
- * Function to handle a session accept message from the client
+ * Function to handle a suspend request message from the client
  *
  * @param cls closure, NULL
  * @param client the client from which the message is
  * @param message the message from the client
-*/
+ */
 static void
-handle_session_accept_message (void *cls, struct GNUNET_SERVER_Client *client,
-                              const struct GNUNET_MessageHeader *message)
+handle_client_suspend_message (void *cls,
+                               struct GNUNET_SERVER_Client *client,
+                               const struct GNUNET_MessageHeader *message)
 {
-  size_t msg_size;
-
+  const struct ClientPhoneSuspendMessage *msg;
+  struct GNUNET_MQ_Envelope *e;
+  struct MeshPhoneSuspendMessage *mhum;
+  struct Line *line;
+  struct Channel *ch;
+
+  msg = (const struct ClientPhoneSuspendMessage *) message;
+  line = GNUNET_SERVER_client_get_user_context (client, struct Line);
+  if (NULL == line)
+  {
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    return;
+  }
+  for (ch = line->channel_head; NULL != ch; ch = ch->next)
+    if (msg->cid == ch->cid)
+      break;
+  if (NULL == ch)
+  {
+    /* could have been destroyed asynchronously, ignore message */
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Channel %u not found\n",
+                msg->cid);
+    return;
+  }
+  if (GNUNET_YES == ch->suspended_local)
+  {
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    return;
+  }
+  switch (ch->status)
+  {
+  case CS_CALLEE_RINGING:
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    return;
+  case CS_CALLEE_CONNECTED:
+    ch->suspended_local = GNUNET_YES;
+    break;
+  case CS_CALLEE_SHUTDOWN:
+    /* maybe the other peer closed asynchronously... */
+    return;
+  case CS_CALLER_CALLING:
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    return;
+  case CS_CALLER_CONNECTED:
+    ch->suspended_local = GNUNET_YES;
+    break;
+  case CS_CALLER_SHUTDOWN:
+    /* maybe the other peer closed asynchronously... */
+    return;
+  }
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Sending SUSPEND message via mesh\n");
+  e = GNUNET_MQ_msg (mhum,
+                     GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_SUSPEND);
+  GNUNET_MQ_send (ch->reliable_mq, e);
   GNUNET_SERVER_receive_done (client, GNUNET_OK);
-
-  if (connection.status != CALLEE)
-    {
-      // TODO send illegal command
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                 _
-                 ("handle_session_accept_message called when not allowed\n"));
-      return;
-    }
-
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Accepting the call of: %s\n"),
-             GNUNET_i2s_full (&(connection.peer)));
-
-  msg_size = sizeof (struct MeshSessionAcceptMessage);
-  struct MeshSessionAcceptMessage *message_mesh_accept =
-    (struct MeshSessionAcceptMessage *) GNUNET_malloc (msg_size);
-
-  if (NULL == message_mesh_accept)
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                 _("Could not create MeshSessionAcceptMessage\n"));
-      return;
-    }
-
-  message_mesh_accept->header.size = htons (msg_size);
-  message_mesh_accept->header.type =
-    htons (GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_SESSION_ACCEPT);
-
-  if (NULL ==
-      GNUNET_MESH_notify_transmit_ready (tunnel_reliable, 0,
-                                        MAX_TRANSMIT_DELAY, msg_size,
-                                        &transmit_mesh_message,
-                                        (void *) message_mesh_accept))
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                 _("Could not queue MeshSessionAcceptMessage\n"));
-      GNUNET_free (message_mesh_accept);
-      return;
-    }
-
-  connection.status = CONNECTED;
-  connection.client = client;
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Changed connection status to %d\n"),
-             connection.status);
-
-  return;
 }
 
+
 /**
- * Function to handle a session reject message from the client
+ * Function to handle a resume request message from the client
  *
  * @param cls closure, NULL
  * @param client the client from which the message is
  * @param message the message from the client
-*/
+ */
 static void
-handle_session_reject_message (void *cls, struct GNUNET_SERVER_Client *client,
-                              const struct GNUNET_MessageHeader *message)
+handle_client_resume_message (void *cls,
+                              struct GNUNET_SERVER_Client *client,
+                              const struct GNUNET_MessageHeader *message)
 {
-  struct ClientServerSessionRejectMessage *message_received;
-
+  const struct ClientPhoneResumeMessage *msg;
+  struct GNUNET_MQ_Envelope *e;
+  struct MeshPhoneResumeMessage *mhum;
+  struct Line *line;
+  struct Channel *ch;
+
+  msg = (const struct ClientPhoneResumeMessage *) message;
+  line = GNUNET_SERVER_client_get_user_context (client, struct Line);
+  if (NULL == line)
+  {
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    return;
+  }
+  for (ch = line->channel_head; NULL != ch; ch = ch->next)
+    if (msg->cid == ch->cid)
+      break;
+  if (NULL == ch)
+  {
+    /* could have been destroyed asynchronously, ignore message */
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Channel %u not found\n",
+                msg->cid);
+    return;
+  }
+  if (GNUNET_YES != ch->suspended_local)
+  {
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    return;
+  }
+  switch (ch->status)
+  {
+  case CS_CALLEE_RINGING:
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    return;
+  case CS_CALLEE_CONNECTED:
+    ch->suspended_local = GNUNET_NO;
+    break;
+  case CS_CALLEE_SHUTDOWN:
+    /* maybe the other peer closed asynchronously... */
+    return;
+  case CS_CALLER_CALLING:
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    return;
+  case CS_CALLER_CONNECTED:
+    ch->suspended_local = GNUNET_NO;
+    break;
+  case CS_CALLER_SHUTDOWN:
+    /* maybe the other peer closed asynchronously... */
+    return;
+  }
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Sending RESUME message via mesh\n");
+  e = GNUNET_MQ_msg (mhum,
+                     GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_RESUME);
+  GNUNET_MQ_send (ch->reliable_mq, e);
   GNUNET_SERVER_receive_done (client, GNUNET_OK);
-
-  if (connection.status != CALLEE)
-    {
-      // TODO send illegal command
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                 _
-                 ("handle_session_reject_message called when not allowed\n"));
-      return;
-    }
-
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Rejecting the call of: %s\n"),
-             GNUNET_i2s_full (&(connection.peer)));
-  message_received = (struct ClientServerSessionRejectMessage *) message;
-  reject_call (tunnel_reliable, ntohs (message_received->reason));
-
-  return;
 }
 
+
 /**
- * Function to handle a session terminate message from the client
+ * Function to handle call request from the client
  *
  * @param cls closure, NULL
  * @param client the client from which the message is
  * @param message the message from the client
-*/
+ */
 static void
-handle_session_terminate_message (void *cls,
-                                 struct GNUNET_SERVER_Client *client,
-                                 const struct GNUNET_MessageHeader *message)
+handle_client_call_message (void *cls,
+                            struct GNUNET_SERVER_Client *client,
+                            const struct GNUNET_MessageHeader *message)
 {
+  const struct ClientCallMessage *msg;
+  struct Line *line;
+  struct Channel *ch;
+  struct GNUNET_MQ_Envelope *e;
+  struct MeshPhoneRingMessage *ring;
+
+  msg = (const struct ClientCallMessage *) message;
+  line = GNUNET_SERVER_client_get_user_context (client, struct Line);
+  if (NULL != line)
+  {
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    return;
+  }
+  line = GNUNET_new (struct Line);
+  line->client = client;
+  line->local_line = (local_line_cnt++) | (1 << 31);
+  GNUNET_SERVER_client_set_user_context (client, line);
+  GNUNET_SERVER_notification_context_add (nc, client);
+  GNUNET_CONTAINER_DLL_insert (lines_head,
+                               lines_tail,
+                               line);
+  ch = GNUNET_new (struct Channel);
+  ch->line = line;
+  GNUNET_CONTAINER_DLL_insert (line->channel_head,
+                               line->channel_tail,
+                               ch);
+  ch->target = msg->target;
+  ch->remote_line = ntohl (msg->line);
+  ch->status = CS_CALLER_CALLING;
+  ch->channel_reliable = GNUNET_MESH_channel_create (mesh,
+                                                     ch,
+                                                     &msg->target,
+                                                     GNUNET_APPLICATION_TYPE_CONVERSATION_CONTROL,
+                                                     GNUNET_MESH_OPTION_RELIABLE);
+  ch->reliable_mq = GNUNET_MESH_mq_create (ch->channel_reliable);
+  e = GNUNET_MQ_msg (ring, GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_RING);
+  ring->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CONVERSATION_RING);
+  ring->purpose.size = htonl (sizeof (struct GNUNET_PeerIdentity) * 2 +
+                              sizeof (struct GNUNET_TIME_AbsoluteNBO) +
+                              sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
+                              sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
+  GNUNET_CRYPTO_ecdsa_key_get_public (&msg->caller_id,
+                                      &ring->caller_id);
+  ring->remote_line = msg->line;
+  ring->source_line = line->local_line;
+  ring->target = msg->target;
+  ring->source = my_identity;
+  ring->expiration_time = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (RING_TIMEOUT));
+  GNUNET_CRYPTO_ecdsa_sign (&msg->caller_id,
+                            &ring->purpose,
+                            &ring->signature);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Sending RING message via mesh\n");
+  GNUNET_MQ_send (ch->reliable_mq, e);
   GNUNET_SERVER_receive_done (client, GNUNET_OK);
-
-  if (connection.client == NULL || connection.status == CALLEE)
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                 _
-                 ("handle_session_terminate_message called when not allowed\n"));
-      return;
-    }
-
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Terminating the call with: %s\n"),
-             GNUNET_i2s_full (&(connection.peer)));
-  terminate_call ();
 }
 
-/******************************************************************************/
-/***********************       SENDING FUNCTIONS MESH       *******************/
-/******************************************************************************/
 
 /**
-* Transmit a mesh message
- * @param cls closure, NULL
- * @param size number of bytes available in buf
- * @param buf where the callee should write the message
- * @return number of bytes written to buf
+ * Transmit audio data via unreliable mesh channel.
+ *
+ * @param cls the `struct Channel` 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 @a buf
  */
 static size_t
-transmit_mesh_message (void *cls, size_t size, void *buf)
+transmit_line_audio (void *cls,
+                     size_t size,
+                     void *buf)
 {
-  struct VoIPMeshMessageHeader *msg_header =
-    (struct VoIPMeshMessageHeader *) cls;
-  msg_header->SequenceNumber = SequenceNumber += 1;
-  msg_header->time = GNUNET_TIME_absolute_get ();
-
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transmitting message over mesh\n"));
+  struct Channel *ch = cls;
+  struct MeshAudioMessage *mam = buf;
 
-  memcpy (buf, cls, size);
-  // Check if this is correct
-
-
-  if ((GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_SESSION_TERMINATE ==
-       ntohs (msg_header->header.type))
-      || (GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_SESSION_REJECT ==
-         ntohs (msg_header->header.type)))
-    {
-      status_to_listen ();
-    }
-  else if (GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_SESSION_INITIATE ==
-          ntohs (msg_header->header.type))
+  ch->unreliable_mth = NULL;
+  if ( (NULL == buf) ||
+       (size < sizeof (struct MeshAudioMessage) + ch->audio_size) )
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Starting timeout task.\n"));
-      timeout_task =
-       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
-                                     (GNUNET_TIME_UNIT_SECONDS, 30),
-                                     &check_timeout, NULL);
-    }
-
-  GNUNET_free (cls);
-
-  return size;
+    /* eh, other error handling? */
+    return 0;
+  }
+  mam->header.size = htons (sizeof (struct MeshAudioMessage) + ch->audio_size);
+  mam->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_AUDIO);
+  mam->remote_line = htonl (ch->remote_line);
+  memcpy (&mam[1], ch->audio_data, ch->audio_size);
+  GNUNET_free (ch->audio_data);
+  ch->audio_data = NULL;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Sending %u bytes of audio data on line %u via mesh\n",
+              ch->audio_size, ch->remote_line);
+  return sizeof (struct MeshAudioMessage) + ch->audio_size;
 }
 
+
 /**
-* Transmit a audo message over mesh
+ * Function to handle audio data from the client
+ *
  * @param cls closure, NULL
- * @param size number of bytes available in buf
- * @param buf where the callee should write the message
- * @return number of bytes written to buf
+ * @param client the client from which the message is
+ * @param message the message from the client
  */
-static size_t
-transmit_mesh_audio_message (void *cls, size_t size, void *buf)
+static void
+handle_client_audio_message (void *cls,
+                             struct GNUNET_SERVER_Client *client,
+                             const struct GNUNET_MessageHeader *message)
 {
-  struct AudioMessage *message = (struct AudioMessage *) cls;
-
-  if (size < sizeof (struct AudioMessage) || NULL == buf)
-    {
-      GNUNET_break (0);
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                 "size %u, buf %p, data_sent %u, data_received %u\n",
-                 size, buf, data_sent, data_received);
-      return 0;
-    }
-
-  memcpy (buf, message, size);
-
-  data_sent++;
-  data_sent_size += size;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO, " Sent packet %d\n", data_sent);
-
-  audio_task = GNUNET_SCHEDULER_add_now (&transmit_audio_task, NULL);
-
-  return size;
+  const struct ClientAudioMessage *msg;
+  struct Line *line;
+  struct Channel *ch;
+  size_t size;
+
+  size = ntohs (message->size) - sizeof (struct ClientAudioMessage);
+  msg = (const struct ClientAudioMessage *) message;
+  line = GNUNET_SERVER_client_get_user_context (client, struct Line);
+  if (NULL == line)
+  {
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    return;
+  }
+  for (ch = line->channel_head; NULL != ch; ch = ch->next)
+    if (msg->cid == ch->cid)
+      break;
+  if (NULL == ch)
+  {
+    /* could have been destroyed asynchronously, ignore message */
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Channel %u not found\n",
+                msg->cid);
+    return;
+  }
+
+  switch (ch->status)
+  {
+  case CS_CALLEE_RINGING:
+  case CS_CALLER_CALLING:
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    return;
+  case CS_CALLEE_CONNECTED:
+  case CS_CALLER_CONNECTED:
+    /* common case, handled below */
+    break;
+  case CS_CALLEE_SHUTDOWN:
+  case CS_CALLER_SHUTDOWN:
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
+                "Mesh audio channel in shutdown; audio data dropped\n");
+    GNUNET_SERVER_receive_done (client, GNUNET_OK);
+    return;
+  }
+  if (NULL == ch->channel_unreliable)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
+                _("Mesh audio channel not ready; audio data dropped\n"));
+    GNUNET_SERVER_receive_done (client, GNUNET_OK);
+    return;
+  }
+  if (NULL != ch->unreliable_mth)
+  {
+    /* NOTE: we may want to not do this and instead combine the data */
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Bandwidth insufficient; dropping previous audio data segment with %u bytes\n",
+                (unsigned int) ch->audio_size);
+    GNUNET_MESH_notify_transmit_ready_cancel (ch->unreliable_mth);
+    ch->unreliable_mth = NULL;
+    GNUNET_free (ch->audio_data);
+    ch->audio_data = NULL;
+  }
+  ch->audio_size = size;
+  ch->audio_data = GNUNET_malloc (ch->audio_size);
+  memcpy (ch->audio_data,
+          &msg[1],
+          size);
+  ch->unreliable_mth = GNUNET_MESH_notify_transmit_ready (ch->channel_unreliable,
+                                                          GNUNET_NO,
+                                                          GNUNET_TIME_UNIT_FOREVER_REL,
+                                                          sizeof (struct MeshAudioMessage)
+                                                          + ch->audio_size,
+                                                          &transmit_line_audio,
+                                                          ch);
+  GNUNET_SERVER_receive_done (client, GNUNET_OK);
 }
 
+
 /**
- * Task to schedule a audio transmission.
- * 
- * @param cls Closure.
- * @param tc Task Context.
+ * We are done signalling shutdown to the other peer.
+ * Destroy the channel.
+ *
+ * @param cls the `struct GNUNET_MESH_channel` to destroy
  */
 static void
-transmit_audio_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+mq_done_destroy_channel (void *cls)
 {
-  struct GNUNET_CONTAINER_SList_Iterator iterator;
-  struct AudioMessage *msg;
-  int ab_length = GNUNET_CONTAINER_slist_count (audio_buffer);
-
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "We have %d packets.\n", ab_length);
+  struct GNUNET_MESH_Channel *channel = cls;
 
-  if (NULL == cls)
-    {
-      if (0 == ab_length && CONNECTED == connection.status)
-       {
-         audio_task =
-           GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
-                                         (GNUNET_TIME_UNIT_MILLISECONDS, 10),
-                                         &transmit_audio_task, NULL);
-         return;
-       }
-
-      iterator = GNUNET_CONTAINER_slist_begin (audio_buffer);
-      msg =
-       (struct AudioMessage *) GNUNET_CONTAINER_slist_get (&iterator, NULL);
-      msg->SequenceNumber = SequenceNumber += 1;
-      msg->time = GNUNET_TIME_absolute_get ();
-
-      GNUNET_CONTAINER_slist_erase (&iterator);
-      GNUNET_CONTAINER_slist_iter_destroy (&iterator);
-    }
-  else
-    {
-      msg = (struct AudioMessage *) cls;
-    }
-
-  if (NULL == tunnel_unreliable)
-    {
-      GNUNET_CONTAINER_slist_clear (audio_buffer);
-      return;
-    }
-
-  mth = GNUNET_MESH_notify_transmit_ready (tunnel_unreliable, GNUNET_NO,
-                                          MAX_TRANSMIT_DELAY,
-                                          sizeof (struct AudioMessage),
-                                          &transmit_mesh_audio_message,
-                                          (void *) msg);
-
-  if (NULL == mth)
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                 "Need to retransmit audio packet\n");
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO, "  in 1 ms\n");
-      audio_task =
-       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS,
-                                     &transmit_audio_task, (void *) msg);
-    }
+  GNUNET_MESH_channel_destroy (channel);
 }
 
-/******************************************************************************/
-/***********************       RECEIVE FUNCTIONS MESH      ********************/
-/******************************************************************************/
 
 /**
-* Function to handle a initiation messaage incoming over mesh
+ * Function to handle a ring message incoming over mesh
+ *
  * @param cls closure, NULL
- * @param tunnel the tunnel over which the message arrived
- * @pram tunnel_ctx the tunnel context, can be NULL
- * @pram message the incoming message
- * 
- * @return GNUNET_OK
-*/
-int
-handle_mesh_initiate_message (void *cls, struct GNUNET_MESH_Tunnel *tunnel,
-                             void **tunnel_ctx,
-                             const struct GNUNET_MessageHeader *message)
+ * @param channel the channel over which the message arrived
+ * @param channel_ctx the channel context, can be NULL
+ *                    or point to the `struct Channel`
+ * @param message the incoming message
+ * @return #GNUNET_OK
+ */
+static int
+handle_mesh_ring_message (void *cls,
+                          struct GNUNET_MESH_Channel *channel,
+                          void **channel_ctx,
+                          const struct GNUNET_MessageHeader *message)
 {
-  int reject_reason;
-  //struct GNUNET_PeerIdentity *peer =  (GNUNET_MESH_tunnel_get_info(tunnel, GNUNET_MESH_OPTION_PEER))->peer;
-  const struct GNUNET_PeerIdentity *peer =
-    GNUNET_PEER_resolve2 (tunnel->peer);
-
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-             _("Handling MeshSessionInitiateMessage from peer: %s\n"),
-             GNUNET_i2s_full (peer));
-  GNUNET_MESH_receive_done (tunnel);
-
-  if (LISTEN != connection.status
-      || 1 > GNUNET_CONTAINER_slist_count (clients))
-    {
-
-      if (CONNECTED == connection.status)
-       {
-         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                     _
-                     ("Rejected call from %s because there is an active call"),
-                     GNUNET_i2s_full (peer));
-         reject_reason = htons (REJECT_REASON_ACTIVE_CALL);
-
-         // Notifying client about missed call
-         size_t msg_size =
-           sizeof (struct ServerClientMissedCallMessage) +
-           sizeof (struct MissedCall);
-         struct ServerClientMissedCallMessage *message =
-           GNUNET_malloc (msg_size);
-
-         message->header.size = htons (msg_size);
-         message->header.type =
-           htons (GNUNET_MESSAGE_TYPE_CONVERSATION_SC_MISSED_CALL);
-         message->number = 1;
-
-         memcpy (&(message->missed_call->peer), peer,
-                 sizeof (struct GNUNET_PeerIdentity));
-         message->missed_call->time = GNUNET_TIME_absolute_get ();
-
-         if (NULL ==
-             GNUNET_SERVER_notify_transmit_ready (connection.client,
-                                                  sizeof (struct
-                                                          ServerClientMissedCallMessage),
-                                                  MAX_TRANSMIT_DELAY,
-                                                  &transmit_server_missed_call_message,
-                                                  (void *) message))
-           {
-             GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                         _
-                         ("Could not queue ServerClientMissedCallMessage\n"));
-             GNUNET_free (message);
-           }
-       }
-
-      if (1 > GNUNET_CONTAINER_slist_count (clients))
-       {
-         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                     _("Got a call from %s while no client connected.\n"),
-                     GNUNET_i2s_full (peer));
-         reject_reason = htons (REJECT_REASON_NO_CLIENT);
-         // Store missed calls
-         struct MissedCall call;
-         memcpy (&(call.peer), peer, sizeof (struct GNUNET_PeerIdentity));
-         call.time = GNUNET_TIME_absolute_get ();
-         GNUNET_CONTAINER_slist_add_end (missed_calls,
-                                         GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
-                                         &call, sizeof (struct MissedCall));
-
-       }
-
-      reject_call (tunnel, reject_reason);
-    }
-  else
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Initiated call from: %s\n"),
-                 GNUNET_i2s_full (peer));
-      tunnel_reliable = tunnel;
-      connection.status = CALLEE;
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                 _("Changed connection status to %d\n"), connection.status);
-      memcpy (&(connection.peer), peer, sizeof (struct GNUNET_PeerIdentity));
-
-      struct GNUNET_CONTAINER_SList_Iterator iterator =
-       GNUNET_CONTAINER_slist_begin (clients);
-      do
-       {
-         struct VoipClient *conversation_client =
-           (struct VoipClient *) GNUNET_CONTAINER_slist_get (&iterator,
-                                                             NULL);
-         struct GNUNET_SERVER_Client *client = conversation_client->client;
-         GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Client found: %p\n"),
-                     client);
-
-         if (NULL ==
-             GNUNET_SERVER_notify_transmit_ready (client,
-                                                  sizeof (struct
-                                                          ServerClientSessionInitiateMessage),
-                                                  MAX_TRANSMIT_DELAY,
-                                                  &transmit_server_initiate_message,
-                                                  (void *) peer))
-           {
-             GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                         _
-                         ("Could not queue ServerClientSessionInitiateMessage\n"));
-           }
-
-         GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Client notified.\n"));
-       }
-      while (GNUNET_OK == GNUNET_CONTAINER_slist_next (&iterator));
-
-      GNUNET_CONTAINER_slist_iter_destroy (&iterator);
-
-    }
-
+  const struct MeshPhoneRingMessage *msg;
+  struct Line *line;
+  struct Channel *ch;
+  struct GNUNET_MQ_Envelope *e;
+  struct MeshPhoneHangupMessage *hang_up;
+  struct ClientPhoneRingMessage cring;
+  struct GNUNET_MQ_Handle *reliable_mq;
+
+  msg = (const struct MeshPhoneRingMessage *) message;
+  if ( (msg->purpose.size != htonl (sizeof (struct GNUNET_PeerIdentity) * 2 +
+                                    sizeof (struct GNUNET_TIME_AbsoluteNBO) +
+                                    sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
+                                    sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey))) ||
+       (GNUNET_OK !=
+        GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_CONVERSATION_RING,
+                                  &msg->purpose,
+                                  &msg->signature,
+                                  &msg->caller_id)) )
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  for (line = lines_head; NULL != line; line = line->next)
+    if (line->local_line == ntohl (msg->remote_line))
+      break;
+  if (NULL == line)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                _("No available phone for incoming call on line %u, sending HANG_UP signal\n"),
+                ntohl (msg->remote_line));
+    e = GNUNET_MQ_msg (hang_up,
+                       GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_HANG_UP);
+    GNUNET_MQ_notify_sent (e,
+                           &mq_done_destroy_channel,
+                           channel);
+    reliable_mq = GNUNET_MESH_mq_create (channel);
+    GNUNET_MQ_send (reliable_mq, e);
+    /* FIXME: do we need to clean up reliable_mq somehow/somewhere? */
+    GNUNET_MESH_receive_done (channel); /* needed? */
+    return GNUNET_OK;
+  }
+  ch = GNUNET_new (struct Channel);
+  ch->line = line;
+  GNUNET_CONTAINER_DLL_insert (line->channel_head,
+                               line->channel_tail,
+                               ch);
+  ch->status = CS_CALLEE_RINGING;
+  ch->remote_line = ntohl (msg->source_line);
+  ch->channel_reliable = channel;
+  ch->reliable_mq = GNUNET_MESH_mq_create (ch->channel_reliable);
+  ch->cid = line->cid_gen++;
+  ch->target = msg->source;
+  *channel_ctx = ch;
+  cring.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RING);
+  cring.header.size = htons (sizeof (cring));
+  cring.cid = ch->cid;
+  cring.caller_id = msg->caller_id;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Sending RING message to client\n");
+  GNUNET_SERVER_notification_context_unicast (nc,
+                                              line->client,
+                                              &cring.header,
+                                              GNUNET_NO);
+  GNUNET_MESH_receive_done (channel);
   return GNUNET_OK;
 }
 
-/**
-* Function to handle an accept messaage incoming over mesh
- * @param cls closure, NULL
- * @param tunnel the tunnel over which the message arrived
- * @pram tunnel_ctx the tunnel context, can be NULL
- * @pram message the incoming message
- * 
- * @return GNUNET_OK
-*/
-int
-handle_mesh_accept_message (void *cls, struct GNUNET_MESH_Tunnel *tunnel,
-                           void **tunnel_ctx,
-                           const struct GNUNET_MessageHeader *message)
-{
-  static uint32_t port = 50003;
-  //struct GNUNET_PeerIdentity *peer =  (GNUNET_MESH_tunnel_get_info(tunnel, GNUNET_MESH_OPTION_PEER))->peer;
-  const struct GNUNET_PeerIdentity *peer =
-    GNUNET_PEER_resolve2 (tunnel->peer);
-
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-             _
-             ("Handling MeshSessionAccpetMessage from peer: %s (connection.peer: %s)\n"),
-             GNUNET_i2s_full (peer), GNUNET_i2s_full (&(connection.peer)));
-  GNUNET_MESH_receive_done (tunnel);
-
-  if (0 ==
-      memcmp (peer, &(connection.peer), sizeof (struct GNUNET_PeerIdentity))
-      && connection.status == CALLER)
-    {
-      tunnel_unreliable =
-       GNUNET_MESH_tunnel_create (mesh, NULL, peer, port, GNUNET_NO,
-                                  GNUNET_NO);
-      if (NULL == tunnel_unreliable)
-       {
-         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                     _("Could not create unreliable tunnel\n"));
-
-         status_to_listen ();
-
-         GNUNET_SERVER_notify_transmit_ready (connection.client,
-                                              sizeof (struct
-                                                      ServerClientSessionRejectMessage),
-                                              MAX_TRANSMIT_DELAY,
-                                              &transmit_server_reject_message,
-                                              NULL);
-         return GNUNET_SYSERR;
-       }
-
-      if (timeout_task != GNUNET_SCHEDULER_NO_TASK)
-       {
-         GNUNET_SCHEDULER_cancel (timeout_task);
-         timeout_task = GNUNET_SCHEDULER_NO_TASK;
-       }
-
-      connection.status = CONNECTED;
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                 _("Changed connection status to %d\n"), connection.status);
-
-      if (NULL ==
-         GNUNET_SERVER_notify_transmit_ready (connection.client,
-                                              sizeof (struct
-                                                      ServerClientSessionAcceptMessage),
-                                              MAX_TRANSMIT_DELAY,
-                                              &transmit_server_accept_message,
-                                              (void *) message))
-       {
-         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                     _
-                     ("Could not queue ServerClientSessionAcceptMessage\n"));
-         return GNUNET_SYSERR;
-       }
-
-      start_time = GNUNET_TIME_absolute_get ();
-      start_helpers ();
-      audio_task = GNUNET_SCHEDULER_add_now (&transmit_audio_task, NULL);
-    }
-
-  return GNUNET_OK;
-}
 
 /**
-* Function to handle a reject messaage incoming over mesh
+ * Function to handle a hangup message incoming over mesh
+ *
  * @param cls closure, NULL
- * @param tunnel the tunnel over which the message arrived
- * @pram tunnel_ctx the tunnel context, can be NULL
- * @pram message the incoming message
- * 
- * @return GNUNET_OK
-*/
-int
-handle_mesh_reject_message (void *cls, struct GNUNET_MESH_Tunnel *tunnel,
-                           void **tunnel_ctx,
-                           const struct GNUNET_MessageHeader *message)
+ * @param channel the channel over which the message arrived
+ * @param channel_ctx the channel context, can be NULL
+ *                    or point to the `struct Channel`
+ * @param message the incoming message
+ * @return #GNUNET_OK
+ */
+static int
+handle_mesh_hangup_message (void *cls,
+                            struct GNUNET_MESH_Channel *channel,
+                            void **channel_ctx,
+                            const struct GNUNET_MessageHeader *message)
 {
-  //struct GNUNET_PeerIdentity *peer =  (GNUNET_MESH_tunnel_get_info(tunnel, GNUNET_MESH_OPTION_PEER))->peer;
-  const struct GNUNET_PeerIdentity *peer =
-    GNUNET_PEER_resolve2 (tunnel->peer);
-
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-             _
-             ("Handling MeshSessionRejectMessage from peer: %s (connection.peer: %s)\n"),
-             GNUNET_i2s_full (peer), GNUNET_i2s_full (&(connection.peer)));
-  GNUNET_MESH_receive_done (tunnel);
-
-  if (0 ==
-      memcmp (peer, &(connection.peer), sizeof (struct GNUNET_PeerIdentity))
-      && connection.status == CALLER)
-    {
-      if (NULL ==
-         GNUNET_SERVER_notify_transmit_ready (connection.client,
-                                              sizeof (struct
-                                                      ServerClientSessionRejectMessage),
-                                              MAX_TRANSMIT_DELAY,
-                                              &transmit_server_reject_message,
-                                              (void *) message))
-       {
-         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                     _
-                     ("Could not queue ServerClientSessionRejectMessage\n"));
-       }
-
-      status_to_listen ();
-
-      if (NULL != tunnel_reliable)
-       {
-         GNUNET_MESH_tunnel_destroy (tunnel_reliable);
-         tunnel_reliable = NULL;
-       }
-    }
-
+  struct Channel *ch = *channel_ctx;
+  struct Line *line;
+  struct ClientPhoneHangupMessage hup;
+  enum ChannelStatus status;
+
+  if (NULL == ch)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "HANGUP message received for non-existing line, dropping channel.\n");
+    return GNUNET_SYSERR;
+  }
+  line = ch->line;
+  *channel_ctx = NULL;
+  hup.header.size = htons (sizeof (hup));
+  hup.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP);
+  hup.cid = ch->cid;
+  status = ch->status;
+  GNUNET_MESH_receive_done (channel);
+  destroy_line_mesh_channels (ch);
+  switch (status)
+  {
+  case CS_CALLEE_RINGING:
+  case CS_CALLEE_CONNECTED:
+    break;
+  case CS_CALLEE_SHUTDOWN:
+    return GNUNET_OK;
+  case CS_CALLER_CALLING:
+  case CS_CALLER_CONNECTED:
+    break;
+  case CS_CALLER_SHUTDOWN:
+    return GNUNET_OK;
+  }
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Sending HANG UP message to client\n");
+  GNUNET_SERVER_notification_context_unicast (nc,
+                                              line->client,
+                                              &hup.header,
+                                              GNUNET_NO);
   return GNUNET_OK;
 }
 
+
 /**
-* Function to handle a terminate messaage incoming over mesh
+ * Function to handle a pickup message incoming over mesh
+ *
  * @param cls closure, NULL
- * @param tunnel the tunnel over which the message arrived
- * @pram tunnel_ctx the tunnel context, can be NULL
- * @pram message the incoming message
- * 
- * @return GNUNET_OK
-*/
-int
-handle_mesh_terminate_message (void *cls, struct GNUNET_MESH_Tunnel *tunnel,
-                              void **tunnel_ctx,
-                              const struct GNUNET_MessageHeader *message)
+ * @param channel the channel over which the message arrived
+ * @param channel_ctx the channel context, can be NULL
+ *                    or point to the `struct Channel`
+ * @param message the incoming message
+ * @return #GNUNET_OK
+ */
+static int
+handle_mesh_pickup_message (void *cls,
+                            struct GNUNET_MESH_Channel *channel,
+                            void **channel_ctx,
+                            const struct GNUNET_MessageHeader *message)
 {
-  //struct GNUNET_PeerIdentity *peer =  (GNUNET_MESH_tunnel_get_info(tunnel, GNUNET_MESH_OPTION_PEER))->peer;
-  const struct GNUNET_PeerIdentity *peer =
-    GNUNET_PEER_resolve2 (tunnel->peer);
-
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-             _
-             ("Handling MeshSessionTerminateMessage from peer: %s (connection.peer: %s)\n"),
-             GNUNET_i2s_full (peer), GNUNET_i2s_full (&(connection.peer)));
-  GNUNET_MESH_receive_done (tunnel);
-
-  if (!memcmp (peer, &(connection.peer), sizeof (struct GNUNET_PeerIdentity))
-      && (connection.status == CONNECTED || connection.status == CALLEE))
-    {
-      status_to_listen ();
-
-      if (NULL != tunnel_unreliable)
-       {
-         GNUNET_MESH_tunnel_destroy (tunnel_unreliable);
-         tunnel_unreliable = NULL;
-       }
-
-      if (NULL != tunnel_reliable)
-       {
-         GNUNET_MESH_tunnel_destroy (tunnel_reliable);
-         tunnel_reliable = NULL;
-       }
-    }
-
+  struct Channel *ch = *channel_ctx;
+  struct Line *line;
+  struct ClientPhonePickupMessage pick;
+
+  if (NULL == ch)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "PICKUP message received for non-existing channel, dropping channel.\n");
+    return GNUNET_SYSERR;
+  }
+  line = ch->line;
+  GNUNET_MESH_receive_done (channel);
+  switch (ch->status)
+  {
+  case CS_CALLEE_RINGING:
+  case CS_CALLEE_CONNECTED:
+    GNUNET_break_op (0);
+    destroy_line_mesh_channels (ch);
+    return GNUNET_SYSERR;
+  case CS_CALLEE_SHUTDOWN:
+    GNUNET_break_op (0);
+    destroy_line_mesh_channels (ch);
+    break;
+  case CS_CALLER_CALLING:
+    ch->status = CS_CALLER_CONNECTED;
+    break;
+  case CS_CALLER_CONNECTED:
+    GNUNET_break_op (0);
+    return GNUNET_OK;
+  case CS_CALLER_SHUTDOWN:
+    GNUNET_break_op (0);
+    mq_done_finish_caller_shutdown (ch);
+    return GNUNET_SYSERR;
+  }
+  pick.header.size = htons (sizeof (pick));
+  pick.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICKED_UP);
+  pick.cid = ch->cid;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Sending PICKED UP message to client\n");
+  GNUNET_SERVER_notification_context_unicast (nc,
+                                              line->client,
+                                              &pick.header,
+                                              GNUNET_NO);
+  ch->channel_unreliable = GNUNET_MESH_channel_create (mesh,
+                                                       ch,
+                                                       &ch->target,
+                                                       GNUNET_APPLICATION_TYPE_CONVERSATION_AUDIO,
+                                                       GNUNET_MESH_OPTION_DEFAULT);
+  if (NULL == ch->channel_unreliable)
+  {
+    GNUNET_break (0);
+  }
   return GNUNET_OK;
 }
 
+
 /**
-* Function to handle a audio messaage incoming over mesh
+ * Function to handle a suspend message incoming over mesh
+ *
  * @param cls closure, NULL
- * @param tunnel the tunnel over which the message arrived
- * @pram tunnel_ctx the tunnel context, can be NULL
- * @pram message the incoming message
- * 
- * @return GNUNET_OK
-*/
-int
-handle_mesh_audio_message (void *cls, struct GNUNET_MESH_Tunnel *tunnel,
-                          void **tunnel_ctx,
-                          const struct GNUNET_MessageHeader *message)
+ * @param channel the channel over which the message arrived
+ * @param channel_ctx the channel context, can be NULL
+ *                    or point to the `struct Channel`
+ * @param message the incoming message
+ * @return #GNUNET_OK
+ */
+static int
+handle_mesh_suspend_message (void *cls,
+                             struct GNUNET_MESH_Channel *channel,
+                             void **channel_ctx,
+                             const struct GNUNET_MessageHeader *message)
 {
-
-  GNUNET_MESH_receive_done (tunnel);
-
-  if (CONNECTED != connection.status)
+  struct Channel *ch = *channel_ctx;
+  struct Line *line;
+  struct ClientPhoneSuspendMessage suspend;
+
+  if (NULL == ch)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "SUSPEND message received for non-existing line, dropping channel.\n");
+    return GNUNET_SYSERR;
+  }
+  line = ch->line;
+  suspend.header.size = htons (sizeof (suspend));
+  suspend.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_SUSPEND);
+  suspend.cid = ch->cid;
+  GNUNET_MESH_receive_done (channel);
+  switch (ch->status)
+  {
+  case CS_CALLEE_RINGING:
+    GNUNET_break_op (0);
+    break;
+  case CS_CALLEE_CONNECTED:
+    ch->suspended_remote = GNUNET_YES;
+    break;
+  case CS_CALLEE_SHUTDOWN:
     return GNUNET_OK;
-
-
-  struct AudioMessage *audio;
-  size_t msg_size;
-  msg_size = sizeof (struct AudioMessage);
-
-  audio = (struct AudioMessage *) message;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "[RECV] %dbytes\n", audio->length);
-
-  if (NULL == playback_helper)
+  case CS_CALLER_CALLING:
+    GNUNET_break_op (0);
+    break;
+  case CS_CALLER_CONNECTED:
+    ch->suspended_remote = GNUNET_YES;
+    break;
+  case CS_CALLER_SHUTDOWN:
     return GNUNET_OK;
-
-  (void) GNUNET_HELPER_send (playback_helper,
-                            message, GNUNET_YES, NULL, NULL);
-
-  data_received++;
-  data_received_size += msg_size;
-
+  }
+  GNUNET_SERVER_notification_context_unicast (nc,
+                                              line->client,
+                                              &suspend.header,
+                                              GNUNET_NO);
   return GNUNET_OK;
 }
 
-/******************************************************************************/
-/***********************                     HELPER                *******************/
-/******************************************************************************/
 
 /**
-* Function to process the audio from the record helper
+ * Function to handle a resume message incoming over mesh
+ *
  * @param cls closure, NULL
- * @param client NULL
- * @param msg the message from the helper
- * 
- * @return GNUNET_OK
-*/
+ * @param channel the channel over which the message arrived
+ * @param channel_ctx the channel context, can be NULL
+ *                    or point to the `struct Channel`
+ * @param message the incoming message
+ * @return #GNUNET_OK
+ */
 static int
-process_record_messages (void *cls GNUNET_UNUSED, void *client,
-                        const struct GNUNET_MessageHeader *msg)
+handle_mesh_resume_message (void *cls,
+                             struct GNUNET_MESH_Channel *channel,
+                             void **channel_ctx,
+                             const struct GNUNET_MessageHeader *message)
 {
-  size_t msg_size;
-  struct AudioMessage *message = (struct AudioMessage *) msg;
-  msg_size = sizeof (struct AudioMessage);
-
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO, " [REC] %dbyte\n", message->length);
-  GNUNET_CONTAINER_slist_add_end (audio_buffer,
-                                 GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
-                                 message, msg_size);
-
+  struct Channel *ch = *channel_ctx;
+  struct Line *line;
+  struct ClientPhoneResumeMessage resume;
+
+  if (NULL == ch)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "RESUME message received for non-existing line, dropping channel.\n");
+    return GNUNET_SYSERR;
+  }
+  line = ch->line;
+  resume.header.size = htons (sizeof (resume));
+  resume.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RESUME);
+  resume.cid = ch->cid;
+  GNUNET_MESH_receive_done (channel);
+  if (GNUNET_YES != ch->suspended_remote)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "RESUME message received for non-suspended channel, dropping channel.\n");
+    return GNUNET_SYSERR;
+  }
+  switch (ch->status)
+  {
+  case CS_CALLEE_RINGING:
+    GNUNET_break (0);
+    break;
+  case CS_CALLEE_CONNECTED:
+    ch->suspended_remote = GNUNET_NO;
+    break;
+  case CS_CALLEE_SHUTDOWN:
+    return GNUNET_OK;
+  case CS_CALLER_CALLING:
+    GNUNET_break (0);
+    break;
+  case CS_CALLER_CONNECTED:
+    ch->suspended_remote = GNUNET_NO;
+    break;
+  case CS_CALLER_SHUTDOWN:
+    return GNUNET_OK;
+  }
+  GNUNET_SERVER_notification_context_unicast (nc,
+                                              line->client,
+                                              &resume.header,
+                                              GNUNET_NO);
   return GNUNET_OK;
 }
 
-/**
-* Function to to start the playback helper
- * 
- * @return 0 ok, 1 on error
-*/
-int
-start_playback_helper (void)
-{
-  static char *playback_helper_argv[1];
-  int success = 1;
-
-  playback_helper_argv[0] = "gnunet-helper-audio-playback";
-  playback_helper = GNUNET_HELPER_start (GNUNET_NO,
-                                        "gnunet-helper-audio-playback",
-                                        playback_helper_argv,
-                                        NULL, NULL, NULL);
-
-  if (NULL == playback_helper)
-    {
-      success = 0;
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                 _("Could not start playback audio helper.\n"));
-    }
-
-  return success;
-}
-
-/**
-* Function to to start the record helper
- * 
- * @return 0 ok, 1 on error
-*/
-int
-start_record_helper (void)
-{
-  static char *record_helper_argv[1];
-  int success = 1;
-
-  record_helper_argv[0] = "gnunet-helper-audio-record";
-  record_helper = GNUNET_HELPER_start (GNUNET_NO,
-                                      "gnunet-helper-audio-record",
-                                      record_helper_argv,
-                                      &process_record_messages, NULL, NULL);
-
-  if (NULL == record_helper)
-    {
-      success = 0;
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                 _("Could not start record audio helper\n"));
-    }
-
-  return success;
-}
-
-
-/**
-* Function to to start both helpers
- * 
- * @return 0 ok, 1 on error
-*/
-int
-start_helpers (void)
-{
-
-  if (0 == start_playback_helper () || 0 == start_record_helper ())
-    {
-      stop_helpers ();
-      return 0;
-    }
-
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Started helpers\n"));
-
-  return 1;
-}
 
 /**
-* Function to to stop the playback helper
-*/
-void
-stop_playback_helper (void)
+ * Function to handle an audio message incoming over mesh
+ *
+ * @param cls closure, NULL
+ * @param channel the channel over which the message arrived
+ * @param channel_ctx the channel context, can be NULL
+ *                    or point to the `struct Channel`
+ * @param message the incoming message
+ * @return #GNUNET_OK
+ */
+static int
+handle_mesh_audio_message (void *cls,
+                           struct GNUNET_MESH_Channel *channel,
+                           void **channel_ctx,
+                           const struct GNUNET_MessageHeader *message)
 {
-  if (NULL != playback_helper)
+  const struct MeshAudioMessage *msg;
+  struct Channel *ch = *channel_ctx;
+  struct Line *line;
+  struct GNUNET_PeerIdentity sender;
+  size_t msize = ntohs (message->size) - sizeof (struct MeshAudioMessage);
+  char buf[msize + sizeof (struct ClientAudioMessage)];
+  struct ClientAudioMessage *cam;
+  const union GNUNET_MESH_ChannelInfo *info;
+
+  msg = (const struct MeshAudioMessage *) message;
+  if (NULL == ch)
+  {
+    info = GNUNET_MESH_channel_get_info (channel,
+                                         GNUNET_MESH_OPTION_PEER);
+    if (NULL == info)
     {
-      GNUNET_HELPER_stop (playback_helper, GNUNET_NO);
-      playback_helper = NULL;
-
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Stopped playback helper\n"));
+      GNUNET_break (0);
+      return GNUNET_OK;
     }
-}
-
-/**
-* Function to to stop the record helper
-*/
-void
-stop_record_helper (void)
-{
-  if (NULL != record_helper)
+    sender = info->peer;
+    for (line = lines_head; NULL != line; line = line->next)
+      if (line->local_line == ntohl (msg->remote_line))
+      {
+        for (ch = line->channel_head; NULL != ch; ch = ch->next)
+        {
+          if ( (CS_CALLEE_CONNECTED == ch->status) &&
+               (0 == memcmp (&ch->target,
+                             &sender,
+                             sizeof (struct GNUNET_PeerIdentity))) &&
+               (NULL == ch->channel_unreliable) )
+            break;
+        }
+      }
+    if (NULL == ch)
     {
-      GNUNET_HELPER_stop (record_helper, GNUNET_NO);
-      record_helper = NULL;
-
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Stopped record helper\n"));
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "Received AUDIO data for non-existing line %u, dropping.\n",
+                  ntohl (msg->remote_line));
+      return GNUNET_SYSERR;
     }
+    ch->channel_unreliable = channel;
+    *channel_ctx = ch;
+  }
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Forwarding %u bytes of AUDIO data to client\n",
+              msize);
+  cam = (struct ClientAudioMessage *) buf;
+  cam->header.size = htons (sizeof (buf));
+  cam->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO);
+  cam->cid = ch->cid;
+  memcpy (&cam[1], &msg[1], msize);
+  GNUNET_SERVER_notification_context_unicast (nc,
+                                              ch->line->client,
+                                              &cam->header,
+                                              GNUNET_YES);
+  GNUNET_MESH_receive_done (channel);
+  return GNUNET_OK;
 }
 
-/**
-* Function to stop both audio helpers
-*/
-void
-stop_helpers (void)
-{
-  stop_playback_helper ();
-  stop_record_helper ();
-}
-
-/******************************************************************************/
-/***********************                TUNNEL HANDLING            *******************/
-/******************************************************************************/
 
 /**
- * Method called whenever another peer has added us to a tunnel
+ * Method called whenever another peer has added us to a channel
  * the other peer initiated.
  *
  * @param cls closure
- * @param tunnel new handle to the tunnel
- * @param initiator peer that started the tunnel
+ * @param channel new handle to the channel
+ * @param initiator peer that started the channel
  * @param port port
- * @return initial tunnel context for the tunnel (can be NULL -- that's not an error)
+ * @param options channel option flags
+ * @return initial channel context for the channel;
+ *         (can be NULL -- that's not an error)
  */
 static void *
-inbound_tunnel (void *cls, struct GNUNET_MESH_Tunnel *tunnel,
-               const struct GNUNET_PeerIdentity *initiator, uint32_t port)
+inbound_channel (void *cls,
+                struct GNUNET_MESH_Channel *channel,
+               const struct GNUNET_PeerIdentity *initiator,
+                uint32_t port, enum GNUNET_MESH_ChannelOption options)
 {
   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-             _("Received incoming tunnel on port %d\n"), port);
-  if (50003 == port)
-    {
-      tunnel_unreliable = tunnel;
-
-      start_time = GNUNET_TIME_absolute_get ();
-
-      start_helpers ();
-      audio_task = GNUNET_SCHEDULER_add_now (&transmit_audio_task, NULL);
-    }
-
+             _("Received incoming channel on port %u\n"),
+              (unsigned int) port);
   return NULL;
 }
 
 
 /**
- * Function called whenever an inbound tunnel is destroyed.  Should clean up
+ * Function called whenever an inbound channel is destroyed.  Should clean up
  * any associated state.
  *
- * @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
+ * @param cls closure (set from #GNUNET_MESH_connect)
+ * @param channel connection to the other end (henceforth invalid)
+ * @param channel_ctx place where local state associated
+ *                   with the channel is stored;
+ *                   may point to the `struct Channel`
  */
 static void
-inbound_end (void *cls, const struct GNUNET_MESH_Tunnel *tunnel,
-            void *tunnel_ctx)
+inbound_end (void *cls,
+             const struct GNUNET_MESH_Channel *channel,
+            void *channel_ctx)
 {
-  if (tunnel == tunnel_unreliable)
+  struct Channel *ch = channel_ctx;
+  struct Line *line;
+  struct ClientPhoneHangupMessage hup;
+
+  if (NULL == ch)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Mesh channel destroyed, but channel is unknown to us\n");
+    return;
+  }
+  line = ch->line;
+  if (ch->channel_unreliable == channel)
+  {
+    if (NULL != ch->unreliable_mth)
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Tunnel closed: audio\n");
-
-      stop_helpers ();
-      tunnel_unreliable = NULL;
-    }
-
-  if (tunnel == tunnel_reliable)
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Tunnel closed: control\n");
-
-      if (LISTEN != connection.status && NULL != connection.client)
-       {
-         if (NULL ==
-             GNUNET_SERVER_notify_transmit_ready (connection.client,
-                                                  sizeof (struct
-                                                          ServerClientSessionTerminateMessage),
-                                                  MAX_TRANSMIT_DELAY,
-                                                  &transmit_server_terminate_message,
-                                                  NULL))
-           {
-             GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                         _
-                         ("Could not queue ServerClientSessionTerminateMessage\n"));
-           }
-       }
-
-      status_to_listen ();
+      GNUNET_MESH_notify_transmit_ready_cancel (ch->unreliable_mth);
+      ch->unreliable_mth = NULL;
     }
+    ch->channel_unreliable = NULL;
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Unreliable channel destroyed\n");
+    return;
+  }
+  if (ch->channel_reliable != channel)
+  {
+    /* recursive call, I'm the one destroying 'ch' right now */
+    return;
+  }
+  ch->channel_reliable = NULL;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Mesh channel destroyed by mesh in state %d\n",
+              ch->status);
+  hup.header.size = htons (sizeof (hup));
+  hup.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP);
+  hup.cid = ch->cid;
+  switch (ch->status)
+  {
+  case CS_CALLEE_RINGING:
+  case CS_CALLEE_CONNECTED:
+    GNUNET_SERVER_notification_context_unicast (nc,
+                                                line->client,
+                                                &hup.header,
+                                                GNUNET_NO);
+    break;
+  case CS_CALLEE_SHUTDOWN:
+    break;
+  case CS_CALLER_CALLING:
+  case CS_CALLER_CONNECTED:
+    GNUNET_SERVER_notification_context_unicast (nc,
+                                                line->client,
+                                                &hup.header,
+                                                GNUNET_NO);
+    break;
+  case CS_CALLER_SHUTDOWN:
+    break;
+  }
+  destroy_line_mesh_channels (ch);
 }
 
-/******************************************************************************/
-/***********************          CLIENT HANDLING           *******************/
-/******************************************************************************/
-
-/**
- * A client connected.
- *
- * @param cls closure, NULL
- * @param client identification of the client
- */
-
-static void
-handle_client_connect (void *cls, struct GNUNET_SERVER_Client *cl)
-{
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client connected\n");
-  struct ServerClientMissedCallMessage *message;
-  size_t msg_size;
-  struct VoipClient c;
-  c.client = cl;
-
-  GNUNET_CONTAINER_slist_add_end (clients,
-                                 GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
-                                 &c, sizeof (struct VoipClient));
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Client added: %p\n"), cl);
-
-  if (0 < GNUNET_CONTAINER_slist_count (missed_calls))
-    {
-      int i = 0;
-      msg_size =
-       sizeof (struct ServerClientMissedCallMessage) +
-       GNUNET_CONTAINER_slist_count (missed_calls) *
-       sizeof (struct MissedCall);
-      message =
-       (struct ServerClientMissedCallMessage *) GNUNET_malloc (msg_size);
-
-      message->header.size = htons (msg_size);
-      message->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_SC_MISSED_CALL);
-      message->number = GNUNET_CONTAINER_slist_count (missed_calls);
-
-      struct GNUNET_CONTAINER_SList_Iterator iterator =
-       GNUNET_CONTAINER_slist_begin (missed_calls);
-      do
-       {
-         memcpy (&(message->missed_call[i]),
-                 GNUNET_CONTAINER_slist_get (&iterator, NULL),
-                 sizeof (struct MissedCall));
-         i++;
-       }
-      while (GNUNET_OK == GNUNET_CONTAINER_slist_next (&iterator));
-
-      GNUNET_CONTAINER_slist_iter_destroy (&iterator);
-      GNUNET_CONTAINER_slist_clear (missed_calls);
-
-
-      if (NULL ==
-         GNUNET_SERVER_notify_transmit_ready (cl, msg_size,
-                                              MAX_TRANSMIT_DELAY,
-                                              &transmit_server_missed_call_message,
-                                              (void *) message))
-       {
-         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                     _("Could not queue ServerClientMissedCallMessage\n"));
-         GNUNET_free (message);
-       }
-    }
-
-  return;
-}
 
 /**
  * A client disconnected.  Remove all of its data structure entries.
@@ -1610,103 +1387,64 @@ handle_client_connect (void *cls, struct GNUNET_SERVER_Client *cl)
  * @param client identification of the client
  */
 static void
-handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *cl)
+handle_client_disconnect (void *cls,
+                          struct GNUNET_SERVER_Client *client)
 {
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client disconnected\n");
-
-  if (connection.client == cl)
-    {
-      if (CONNECTED == connection.status)
-       {
-         terminate_call ();
-       }
-      else
-       {
-         status_to_listen ();
-       }
-    }
-
-  struct GNUNET_CONTAINER_SList_Iterator iterator =
-    GNUNET_CONTAINER_slist_begin (clients);
-  do
-    {
-      if (((struct VoipClient *)
-          GNUNET_CONTAINER_slist_get (&iterator, NULL))->client == cl)
-       {
-         GNUNET_CONTAINER_slist_erase (&iterator);
-       }
-    }
-  while (GNUNET_OK == GNUNET_CONTAINER_slist_next (&iterator));
-
-  GNUNET_CONTAINER_slist_iter_destroy (&iterator);
-
-  return;
+  struct Line *line;
+
+  if (NULL == client)
+    return;
+  line = GNUNET_SERVER_client_get_user_context (client, struct Line);
+  if (NULL == line)
+    return;
+  GNUNET_SERVER_client_set_user_context (client, (void *)NULL);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Client disconnected, closing line\n");
+  GNUNET_CONTAINER_DLL_remove (lines_head,
+                               lines_tail,
+                               line);
+  while (NULL != line->channel_head)
+    destroy_line_mesh_channels (line->channel_head);
+  GNUNET_free (line);
 }
 
-/******************************************************************************/
-/***********************                     SERVICE               *******************/
-/******************************************************************************/
 
 /**
  * Shutdown nicely
- * 
+ *
  * @param cls closure, NULL
  * @param tc the task context
  */
 static void
-do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+do_shutdown (void *cls,
+             const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Shutdown\n");
-
-  stop_helpers ();
-
-  if (NULL != tunnel_reliable)
-    {
-      GNUNET_MESH_tunnel_destroy (tunnel_reliable);
-    }
-
-  if (NULL != tunnel_unreliable)
-    {
-      GNUNET_MESH_tunnel_destroy (tunnel_unreliable);
-    }
-
+  struct Line *line;
+  struct Channel *ch;
+
+  while (NULL != (line = lines_head))
+  {
+    while (NULL != (ch = line->channel_head))
+      destroy_line_mesh_channels (ch);
+    GNUNET_CONTAINER_DLL_remove (lines_head,
+                                 lines_tail,
+                                 line);
+    GNUNET_SERVER_client_set_user_context (line->client, (void *) NULL);
+    GNUNET_free (line);
+  }
   if (NULL != mesh)
-    {
-      GNUNET_MESH_disconnect (mesh);
-    }
-
+  {
+    GNUNET_MESH_disconnect (mesh);
+    mesh = NULL;
+  }
   if (NULL != nc)
-    {
-      GNUNET_SERVER_notification_context_destroy (nc);
-      nc = NULL;
-    }
-
-  GNUNET_CONTAINER_slist_destroy (audio_buffer);
-  GNUNET_CONTAINER_slist_destroy (clients);
-  GNUNET_CONTAINER_slist_destroy (missed_calls);
-  GNUNET_CONTAINER_slist_destroy (peers_to_notify);
+  {
+    GNUNET_SERVER_notification_context_destroy (nc);
+    nc = NULL;
+  }
 }
 
 
-/**
- * Handler array for traffic received
- */
-static struct GNUNET_MESH_MessageHandler mesh_handlers[] = {
-  {&handle_mesh_initiate_message,
-   GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_SESSION_INITIATE,
-   sizeof (struct MeshSessionInitiateMessage)},
-  {&handle_mesh_accept_message, GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_SESSION_ACCEPT,
-   sizeof (struct MeshSessionAcceptMessage)},
-  {&handle_mesh_reject_message, GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_SESSION_REJECT,
-   sizeof (struct MeshSessionRejectMessage)},
-  {&handle_mesh_terminate_message,
-   GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_SESSION_TERMINATE,
-   sizeof (struct MeshSessionTerminateMessage)},
-  {&handle_mesh_audio_message, GNUNET_MESSAGE_TYPE_CONVERSATION_AUDIO,
-   sizeof (struct AudioMessage)},
-  {NULL, 0, 0}
-};
-
 /**
  * Main function that will be run by the scheduler.
  *
@@ -1715,67 +1453,86 @@ static struct GNUNET_MESH_MessageHandler mesh_handlers[] = {
  * @param c configuration
  */
 static void
-run (void *cls, struct GNUNET_SERVER_Handle *server,
+run (void *cls,
+     struct GNUNET_SERVER_Handle *server,
      const struct GNUNET_CONFIGURATION_Handle *c)
 {
+  static const struct GNUNET_SERVER_MessageHandler server_handlers[] = {
+    {&handle_client_register_message, NULL,
+     GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_REGISTER,
+     sizeof (struct ClientPhoneRegisterMessage)},
+    {&handle_client_pickup_message, NULL,
+     GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICK_UP,
+     sizeof (struct ClientPhonePickupMessage) },
+    {&handle_client_suspend_message, NULL,
+     GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_SUSPEND,
+     sizeof (struct ClientPhoneSuspendMessage) },
+    {&handle_client_resume_message, NULL,
+     GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RESUME,
+     sizeof (struct ClientPhoneResumeMessage) },
+    {&handle_client_hangup_message, NULL,
+     GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP,
+     sizeof (struct ClientPhoneHangupMessage) },
+    {&handle_client_call_message, NULL,
+     GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_CALL,
+     sizeof (struct ClientCallMessage) },
+    {&handle_client_audio_message, NULL,
+     GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO,
+     0},
+    {NULL, NULL, 0, 0}
+  };
+  static struct GNUNET_MESH_MessageHandler mesh_handlers[] = {
+    {&handle_mesh_ring_message,
+     GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_RING,
+     sizeof (struct MeshPhoneRingMessage)},
+    {&handle_mesh_hangup_message,
+     GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_HANG_UP,
+     sizeof (struct MeshPhoneHangupMessage)},
+    {&handle_mesh_pickup_message,
+     GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_PICK_UP,
+     sizeof (struct MeshPhonePickupMessage)},
+    {&handle_mesh_suspend_message,
+     GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_SUSPEND,
+     sizeof (struct MeshPhoneSuspendMessage)},
+    {&handle_mesh_resume_message,
+     GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_RESUME,
+     sizeof (struct MeshPhoneResumeMessage)},
+    {&handle_mesh_audio_message, GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_AUDIO,
+     0},
+    {NULL, 0, 0}
+  };
+  static uint32_t ports[] = {
+    GNUNET_APPLICATION_TYPE_CONVERSATION_CONTROL,
+    GNUNET_APPLICATION_TYPE_CONVERSATION_AUDIO,
+    0
+  };
 
-  static uint32_t ports[] = { 50002, 50003, 0 };
   cfg = c;
-
+  GNUNET_assert (GNUNET_OK ==
+                 GNUNET_CRYPTO_get_peer_identity (cfg,
+                                                  &my_identity));
   mesh = GNUNET_MESH_connect (cfg,
                              NULL,
-                             &inbound_tunnel,
-                             &inbound_end, mesh_handlers, ports);
+                             &inbound_channel,
+                             &inbound_end,
+                              mesh_handlers,
+                              ports);
 
   if (NULL == mesh)
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Couldn't connect to mesh\n");
-      return;
-    }
-  else
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Connected to mesh\n");
-    }
-
-  static const struct GNUNET_SERVER_MessageHandler server_handlers[] = {
-    {&handle_session_initiate_message, NULL,
-     GNUNET_MESSAGE_TYPE_CONVERSATION_CS_SESSION_INITIATE,
-     sizeof (struct ClientServerSessionInitiateMessage)},
-    {&handle_session_accept_message, NULL,
-     GNUNET_MESSAGE_TYPE_CONVERSATION_CS_SESSION_ACCEPT,
-     sizeof (struct ClientServerSessionAcceptMessage)},
-    {&handle_session_reject_message, NULL,
-     GNUNET_MESSAGE_TYPE_CONVERSATION_CS_SESSION_REJECT,
-     sizeof (struct ClientServerSessionRejectMessage)},
-    {&handle_session_terminate_message, NULL,
-     GNUNET_MESSAGE_TYPE_CONVERSATION_CS_SESSION_TERMINATE,
-     sizeof (struct ClientServerSessionTerminateMessage)},
-    {NULL, NULL, 0, 0}
-  };
-
-  connection.status = LISTEN;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Changed connection status to %d\n"),
-             connection.status);
-
+  {
+    GNUNET_break (0);
+    GNUNET_SCHEDULER_shutdown ();
+    return;
+  }
   nc = GNUNET_SERVER_notification_context_create (server, 16);
-
   GNUNET_SERVER_add_handlers (server, server_handlers);
-  GNUNET_SERVER_connect_notify (server, &handle_client_connect, NULL);
   GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL);
-  GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &do_shutdown,
+  GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
+                                &do_shutdown,
                                NULL);
-
-  clients = GNUNET_CONTAINER_slist_create ();
-
-  // Missed calls
-  missed_calls = GNUNET_CONTAINER_slist_create ();
-  peers_to_notify = GNUNET_CONTAINER_slist_create ();
-  audio_buffer = GNUNET_CONTAINER_slist_create ();
-
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Voip service running\n"));
 }
 
+
 /**
  * The main function for the conversation service.
  *
@@ -1784,10 +1541,13 @@ run (void *cls, struct GNUNET_SERVER_Handle *server,
  * @return 0 ok, 1 on error
  */
 int
-main (int argc, char *const *argv)
+main (int argc,
+      char *const *argv)
 {
   return (GNUNET_OK ==
-         GNUNET_SERVICE_run (argc, argv, "conversation", GNUNET_SERVICE_OPTION_NONE,
+         GNUNET_SERVICE_run (argc, argv,
+                              "conversation",
+                              GNUNET_SERVICE_OPTION_NONE,
                              &run, NULL)) ? 0 : 1;
 }