gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] r29754 - in gnunet: . src src/conversation


From: gnunet
Subject: [GNUnet-SVN] r29754 - in gnunet: . src src/conversation
Date: Tue, 1 Oct 2013 13:34:38 +0200

Author: fuchs
Date: 2013-10-01 13:34:38 +0200 (Tue, 01 Oct 2013)
New Revision: 29754

Added:
   gnunet/src/conversation/
   gnunet/src/conversation/Makefile.am
   gnunet/src/conversation/conversation.conf.in
   gnunet/src/conversation/conversation_api.c
   gnunet/src/conversation/gnunet-conversation.c
   gnunet/src/conversation/gnunet-helper-audio-playback.c
   gnunet/src/conversation/gnunet-helper-audio-record.c
   gnunet/src/conversation/gnunet-service-conversation.c
   gnunet/src/conversation/gnunet_conversation.h
   gnunet/src/conversation/gnunet_protocols_conversation.h
   gnunet/src/conversation/mst.c
   gnunet/src/conversation/test_voip.api.c
Modified:
   gnunet/configure.ac
   gnunet/src/Makefile.am
Log:
Initial conversation (experimental) commit

Modified: gnunet/configure.ac
===================================================================
--- gnunet/configure.ac 2013-10-01 11:10:21 UTC (rev 29753)
+++ gnunet/configure.ac 2013-10-01 11:34:38 UTC (rev 29754)
@@ -1296,6 +1296,8 @@
 src/core/core.conf
 src/consensus/Makefile
 src/consensus/consensus.conf
+src/conversation/Makefile
+src/conversation/conversation.conf
 src/datacache/Makefile
 src/datastore/Makefile
 src/datastore/datastore.conf

Modified: gnunet/src/Makefile.am
===================================================================
--- gnunet/src/Makefile.am      2013-10-01 11:10:21 UTC (rev 29753)
+++ gnunet/src/Makefile.am      2013-10-01 11:34:38 UTC (rev 29754)
@@ -16,6 +16,7 @@
   multicast \
   env \
   psyc \
+  conversation \
   $(CONSENSUS) \
   $(EXPERIMENTATION)
   # NOTE: scalarproduct is not being listed here yet as the crypto is being 
reworked at the moment

Added: gnunet/src/conversation/Makefile.am
===================================================================
--- gnunet/src/conversation/Makefile.am                         (rev 0)
+++ gnunet/src/conversation/Makefile.am 2013-10-01 11:34:38 UTC (rev 29754)
@@ -0,0 +1,91 @@
+SUBDIRS = .
+
+INCLUDES = \
+  -I$(top_srcdir)/src/include \
+  -I$(top_srcdir)
+
+AM_CPPFLAGS = \
+  $(GNUNET_CPPFLAGS)
+
+# Set this variable if you are using GNUNET libraries for all programs and
+# libraries. You don't then need to target-specific _LDFLAGS with 
GNUNET_LDFLAGS
+# AM_LDFLAGS = \
+#   $(GNUNET_LDFLAGS) \
+#   $(WINFLAGS) \
+#   -export-dynamic
+
+lib_LTLIBRARIES = libgnunetconversation.la
+
+pkgcfgdir= $(prefix)/share/gnunet/config.d/
+
+libexecdir= $(prefix)/lib/gnunet/libexec/
+
+libgnunetconversation_la_SOURCES = \
+  conversation_api.c 
+libgnunetconversation_la_LIBADD = \
+  -lgnunetutil -lgnunetgns_common -lgnunetgns
+libgnunetconversation_la_LDFLAGS = \
+  $(GNUNET_LDFLAGS)  $(WINFLAGS) \
+  -version-info 0:0:0
+
+
+bin_PROGRAMS = gnunet-conversation
+
+libexec_PROGRAMS = gnunet-service-conversation \
+  gnunet-helper-audio-record \
+  gnunet-helper-audio-playback
+
+check_PROGRAMS = \
+ test_conversation_api 
+
+TESTS = $(check_PROGRAMS)
+
+
+gnunet_helper_audio_record_SOURCES = \
+  gnunet-helper-audio-record.c
+gnunet_helper_audio_record_LDADD = \
+  -lgnunetutil \
+  -lpulse  -lopus\
+  $(INTLLIBS) 
+gnunet_helper_audio_record_LDFLAGS = \
+  $(GNUNET_LDFLAGS)  $(WINFLAGS) -export-dynamic
+
+gnunet_helper_audio_playback_SOURCES = \
+  gnunet-helper-audio-playback.c
+gnunet_helper_audio_playback_LDADD = \
+  -lgnunetutil \
+  -lpulse -lopus\
+  $(INTLLIBS) 
+gnunet_helper_audio_playback_LDFLAGS = \
+  $(GNUNET_LDFLAGS)  $(WINFLAGS) -export-dynamic  
+
+gnunet_service_conversation_SOURCES = \
+  gnunet-service-conversation.c
+gnunet_service_conversation_LDADD = \
+  -lgnunetutil -lgnunetmesh -lgnunetgns_common -lgnunetgns\
+    $(INTLLIBS) 
+gnunet_service_conversation_LDFLAGS = \
+  $(GNUNET_LDFLAGS)  $(WINFLAGS) -export-dynamic 
+
+gnunet_conversation_SOURCES = \
+  gnunet-conversation.c
+gnunet_conversation_LDADD = \
+  -lgnunetutil -lgnunetconversation \
+  $(INTLLIBS) 
+gnunet_conversation_LDFLAGS = \
+ $(GNUNET_LDFLAGS) $(WINFLAGS) -export-dynamic 
+
+
+
+
+
+test_conversation_api_SOURCES = \
+ test_conversation_api.c
+test_conversation_api_LDADD = \
+  $(top_builddir)/src/conversation/libgnunetconversation.la \
+  -lgnunetutil
+test_conversation_api_LDFLAGS = \
+ $(GNUNET_LDFLAGS)  $(WINFLAGS) -export-dynamic
+ 
+ pkgcfg_DATA = conversation.conf 
+ 

Added: gnunet/src/conversation/conversation.conf.in
===================================================================
--- gnunet/src/conversation/conversation.conf.in                                
(rev 0)
+++ gnunet/src/conversation/conversation.conf.in        2013-10-01 11:34:38 UTC 
(rev 29754)
@@ -0,0 +1,7 @@
+[conversation]
+BINARY = gnunet-service-conversation
+UNIXPATH = /tmp/gnunet-service-conversation.sock
+HOME = $SERVICEHOME
+# PORT = 2106
+# @UNIXONLY@ PORT = 2087
+

Added: gnunet/src/conversation/conversation_api.c
===================================================================
--- gnunet/src/conversation/conversation_api.c                          (rev 0)
+++ gnunet/src/conversation/conversation_api.c  2013-10-01 11:34:38 UTC (rev 
29754)
@@ -0,0 +1,751 @@
+/*
+     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 2, 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/conversation_api.c
+ * @brief API for conversation
+ * @author Simon Dieterle
+ * @author Andreas Fuchs
+ * STRUCTURE:
+ * - DATA STRUCTURES
+ * - DECLARATIONS
+ * - AUXILIARY FUNCTIONS
+ * - RECEIVE HANDLERS
+ * - SEND FUNCTIONS
+ * - API CALL DEFINITIONS
+ *
+ */
+
+#include <gnunet/platform.h>
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_gns_service.h>
+#include "gnunet_protocols_conversation.h"
+#include "gnunet_conversation_service.h"
+
+#define MAX_TRANSMIT_DELAY GNUNET_TIME_relative_multiply 
(GNUNET_TIME_UNIT_SECONDS, 60)
+
+/******************************************************************************/
+/************************      DATA STRUCTURES     
****************************/
+/******************************************************************************/
+
+enum GNUNET_CONVERSATION_CallType
+{
+  CALLER = 0,
+  CALLEE
+};
+
+/**
+* Information about a call
+*/
+struct GNUNET_CONVERSATION_CallInformation
+{
+
+       /**
+       * Peer interacting with
+       */
+  struct GNUNET_PeerIdentity peer;
+
+       /**
+       * Type of call (incoming or outgoing)
+       */
+  int type;
+
+       /**
+       * Shows if the call ist fully established
+       */
+  int established;
+};
+
+/**
+ * Opaque handle to the service.
+ */
+struct GNUNET_CONVERSATION_Handle
+{
+
+       /**
+       * Our configuration.
+       */
+  const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+    /**
+     * Handle to the server connection, to send messages later
+     */
+  struct GNUNET_CLIENT_Connection *client;
+
+   /**
+       * GNS handle
+       */
+  struct GNUNET_GNS_Handle *gns;
+
+       /**
+       * Namestore handle
+       */
+  struct GNUNET_NAMESTORE_Handle *namestore;
+
+       /**
+       * TXT record for gns
+       */
+  int txt_record_set;
+
+       /**
+     * Callback for incoming calls
+     */
+  GNUNET_CONVERSATION_CallHandler *call_handler;
+
+       /**
+     * Callback for rejected calls
+     */
+  GNUNET_CONVERSATION_RejectHandler *reject_handler;
+
+       /**
+     * Callback for notifications
+     */
+  GNUNET_CONVERSATION_NotificationHandler *notification_handler;
+
+       /**
+     * Callback for missed calls
+     */
+  GNUNET_CONVERSATION_MissedCallHandler *missed_call_handler;
+
+       /**
+       * The pointer to the call
+       */
+  struct GNUNET_CONVERSATION_CallInformation *call;
+};
+
+/******************************************************************************/
+/***********************     AUXILIARY FUNCTIONS      
*************************/
+/******************************************************************************/
+
+/**
+* Initialize the conversation txt record in GNS
+*/
+static void
+setup_gns_txt (struct GNUNET_CONVERSATION_Handle *handle)
+{
+  struct GNUNET_CRYPTO_EccPublicKey zone_pkey;
+  struct GNUNET_CRYPTO_EccPrivateKey *zone_key;
+  struct GNUNET_CRYPTO_EccPublicKey peer_pkey;
+  struct GNUNET_CRYPTO_EccPrivateKey *peer_key;
+  struct GNUNET_NAMESTORE_RecordData rd;
+  struct GNUNET_HashCode hash;
+  struct GNUNET_PeerIdentity peer;
+
+  char *zone_keyfile;
+  char *peer_keyfile;
+
+  rd.expiration_time = UINT64_MAX;
+
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_filename (handle->cfg, "gns", "ZONEKEY",
+                                              &zone_keyfile))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to get key from cfg\n");
+      return;
+    }
+
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_filename (handle->cfg, "PEER",
+                                              "PRIVATE_KEY", &peer_keyfile))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to get key from cfg\n");
+      return;
+    }
+
+  zone_key = GNUNET_CRYPTO_ecc_key_create_from_file (zone_keyfile);
+  GNUNET_CRYPTO_ecc_key_get_public (zone_key, &zone_pkey);
+  peer_key = GNUNET_CRYPTO_ecc_key_create_from_file (peer_keyfile);
+  GNUNET_CRYPTO_ecc_key_get_public (peer_key, &peer_pkey);
+
+  GNUNET_CRYPTO_hash (&peer_pkey, sizeof (peer_pkey), &hash);
+
+  peer.hashPubKey = hash;
+  const char *h = GNUNET_i2s_full (&peer);
+
+  rd.data_size = strlen (h) + 1;
+  rd.data = h;
+  rd.record_type = GNUNET_GNS_RECORD_TXT;
+  rd.flags = GNUNET_NAMESTORE_RF_AUTHORITY;
+
+  GNUNET_NAMESTORE_record_put_by_authority (handle->namestore, zone_key,
+                                           "conversation", 1, &rd, NULL, NULL);
+}
+
+/**
+* Callback for checking the conversation txt gns record
+*
+* @param cls closure
+* @param rd_count
+* @param rd
+*/
+static void
+check_gns_cb (void *cls, uint32_t rd_count,
+             const struct GNUNET_NAMESTORE_RecordData *rd)
+{
+  struct GNUNET_CONVERSATION_Handle *h = (struct GNUNET_CONVERSATION_Handle *) 
cls;
+
+  if (0 == rd_count)
+    {
+      setup_gns_txt (h);
+    }
+  else
+    {
+      h->txt_record_set = GNUNET_YES;
+    }
+
+  return;
+}
+
+/**
+* Check if the gns txt record for conversation exits
+*/
+static void
+check_gns (struct GNUNET_CONVERSATION_Handle *h)
+{
+  GNUNET_GNS_lookup (h->gns, "conversation.gads", GNUNET_GNS_RECORD_TXT,
+                    GNUNET_NO, NULL, &check_gns_cb, (void *) h);
+
+  return;
+}
+
+/******************************************************************************/
+/***********************      RECEIVE HANDLERS     
****************************/
+/******************************************************************************/
+
+/**
+ * Function to process all messages received from the service
+ *
+ * @param cls closure
+ * @param msg message received, NULL on timeout or fatal error
+ */
+static void
+receive_message_cb (void *cls, const struct GNUNET_MessageHeader *msg)
+{
+  struct ServerClientAvailableAnswerMessage *avbmsg;
+  struct ServerClientSessionInitiateMessage *imsg;
+  struct ServerClientSessionRejectMessage *rmsg;
+  struct GNUNET_CONVERSATION_MissedCallNotification *missed_calls;
+  struct GNUNET_CONVERSATION_Handle *h = (struct GNUNET_CONVERSATION_Handle *) 
cls;
+
+  if (NULL != msg)
+    {
+      switch (ntohs (msg->type))
+       {
+       case GNUNET_MESSAGE_TYPE_CONVERSATION_SC_SESSION_ACCEPT:
+         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                     _("%s has accepted your call.\n"),
+                     GNUNET_i2s_full (&(h->call->peer)));
+
+         h->notification_handler (NULL, h, NotificationType_CALL_ACCEPTED,
+                                  &(h->call->peer));
+         h->call->type = CALLEE;
+
+         break;
+
+       case GNUNET_MESSAGE_TYPE_CONVERSATION_SC_SESSION_REJECT:
+         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                     _("%s has rejected your call.\n"),
+                     GNUNET_i2s_full (&(h->call->peer)));
+
+         rmsg = (struct ServerClientSessionRejectMessage *) msg;
+         h->reject_handler (NULL, h, ntohs (rmsg->reason), &(h->call->peer));
+         GNUNET_free (h->call);
+         h->call = NULL;
+
+         break;
+
+       case GNUNET_MESSAGE_TYPE_CONVERSATION_SC_SESSION_TERMINATE:
+         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                     _("%s has terminated the call.\n"),
+                     GNUNET_i2s_full (&(h->call->peer)));
+
+         h->notification_handler (NULL, h, NotificationType_CALL_TERMINATED,
+                                  &(h->call->peer));
+         GNUNET_free (h->call);
+         h->call = NULL;
+
+         break;
+
+       case GNUNET_MESSAGE_TYPE_CONVERSATION_SC_SESSION_INITIATE:
+         imsg = (struct ServerClientSessionInitiateMessage *) msg;
+
+         GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("%s wants to call you.\n"),
+                     GNUNET_i2s_full (&(imsg->peer)));
+
+         h->call =
+           (struct GNUNET_CONVERSATION_CallInformation *)
+           GNUNET_malloc (sizeof (struct GNUNET_CONVERSATION_CallInformation));
+         memcpy (&(h->call->peer), &(imsg->peer),
+                 sizeof (struct GNUNET_PeerIdentity));
+         h->call_handler (NULL, h, &(h->call->peer));
+         h->call->type = CALLEE;
+
+         break;
+
+       case GNUNET_MESSAGE_TYPE_CONVERSATION_SC_MISSED_CALL:
+         missed_calls =
+           (struct GNUNET_CONVERSATION_MissedCallNotification *) (msg +
+                                                          (sizeof
+                                                           (struct
+                                                            
GNUNET_MessageHeader)));
+         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                     _("You &d have missed a calls.\n"),
+                     missed_calls->number);
+         h->missed_call_handler (NULL, h, missed_calls);
+         break;
+
+       case GNUNET_MESSAGE_TYPE_CONVERSATION_SC_SERVICE_BLOCKED:
+         GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("The service is blocked.\n"));
+         h->notification_handler (NULL, h, NotificationType_SERVICE_BLOCKED,
+                                  NULL);
+         break;
+
+       case GNUNET_MESSAGE_TYPE_CONVERSATION_SC_PEER_NOT_CONNECTED:
+         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                     _("The peer you are calling is not connected.\n"));
+         h->notification_handler (NULL, h, NotificationType_NO_PEER, NULL);
+         break;
+
+       case GNUNET_MESSAGE_TYPE_CONVERSATION_SC_NO_ANSWER:
+         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                     _("The peer you are calling does not answer.\n"));
+         h->notification_handler (NULL, h, NotificationType_NO_ANSWER,
+                                  &(h->call->peer));
+         break;
+
+       case GNUNET_MESSAGE_TYPE_CONVERSATION_SC_ERROR:
+         GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Generic error occured.\n"));
+         break;
+
+       default:
+         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                     _("Got unknown message type.\n"));
+         break;
+       }
+
+    }
+
+  GNUNET_CLIENT_receive (h->client, &receive_message_cb, h,
+                        GNUNET_TIME_UNIT_FOREVER_REL);
+}
+
+/******************************************************************************/
+/************************       SEND FUNCTIONS     
****************************/
+/******************************************************************************/
+
+/**
+ * Function called to send a session initiate message to the service.
+ * "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
+ */
+static size_t
+transmit_session_initiate_message (void *cls, size_t size, void *buf)
+{
+  size_t msg_size;
+  struct ClientServerSessionInitiateMessage *msg;
+  struct GNUNET_CONVERSATION_Handle *h = (struct GNUNET_CONVERSATION_Handle *) 
cls;
+
+  msg_size = sizeof (struct ClientServerSessionInitiateMessage);
+
+  GNUNET_assert (size >= msg_size);
+  msg = buf;
+  msg->header.size = htons (msg_size);
+  msg->header.type = htons 
(GNUNET_MESSAGE_TYPE_CONVERSATION_CS_SESSION_INITIATE);
+  memcpy (&msg->peer, &(h->call->peer), sizeof (struct GNUNET_PeerIdentity));
+
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+             _
+             ("Sending ClientServerSessionInitiateMessage to the service for 
peer: %s\n"),
+             GNUNET_i2s_full (&(h->call->peer)));
+
+  h->call->type = CALLER;
+
+  return msg_size;
+}
+
+/**
+ * Function called to send a session accept message to the service.
+ * "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
+ */
+static size_t
+transmit_session_accept_message (void *cls, size_t size, void *buf)
+{
+  size_t msg_size;
+  struct ClientServerSessionAcceptMessage *msg;
+  struct GNUNET_CONVERSATION_Handle *h = (struct GNUNET_CONVERSATION_Handle *) 
cls;
+
+  msg_size = sizeof (struct ClientServerSessionAcceptMessage);
+
+  GNUNET_assert (size >= msg_size);
+  msg = buf;
+  msg->header.size = htons (msg_size);
+  msg->header.type = htons 
(GNUNET_MESSAGE_TYPE_CONVERSATION_CS_SESSION_ACCEPT);
+
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+             _
+             ("Sending ClienServerSessionAcceptMessage to the service for 
peer: %s\n"),
+             GNUNET_i2s_full (&(h->call->peer)));
+
+  h->call->established = GNUNET_YES;
+
+  return msg_size;
+}
+
+/**
+ * Function called to send a session reject message to the service.
+ * "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
+ */
+static size_t
+transmit_session_reject_message (void *cls, size_t size, void *buf)
+{
+  size_t msg_size;
+  struct ClientServerSessionRejectMessage *msg;
+  struct GNUNET_CONVERSATION_Handle *h = (struct GNUNET_CONVERSATION_Handle *) 
cls;
+
+  msg_size = sizeof (struct ClientServerSessionRejectMessage);
+
+  GNUNET_assert (size >= msg_size);
+  msg = buf;
+  msg->header.size = htons (msg_size);
+  msg->header.type = htons 
(GNUNET_MESSAGE_TYPE_CONVERSATION_CS_SESSION_REJECT);
+  msg->reason = htons (REJECT_REASON_NOT_WANTED);
+
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+             _
+             ("Sending ClientServerSessionRejectMessage to the service for 
peer: %s\n"),
+             GNUNET_i2s_full (&(h->call->peer)));
+
+  GNUNET_free (h->call);
+  h->call = NULL;
+
+  return msg_size;
+}
+
+/**
+ * Function called to send a session terminate message to the service.
+ * "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
+ */
+static size_t
+transmit_session_terminate_message (void *cls, size_t size, void *buf)
+{
+  size_t msg_size;
+  struct ClientServerSessionTerminateMessage *msg;
+  struct GNUNET_CONVERSATION_Handle *h = (struct GNUNET_CONVERSATION_Handle *) 
cls;
+
+  msg_size = sizeof (struct ClientServerSessionTerminateMessage);
+
+  GNUNET_assert (size >= msg_size);
+  msg = buf;
+  msg->header.size = htons (msg_size);
+  msg->header.type = htons 
(GNUNET_MESSAGE_TYPE_CONVERSATION_CS_SESSION_TERMINATE);
+
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+             _
+             ("Sending ClientServerSessionTerminateMessage to the service for 
peer: %s\n"),
+             GNUNET_i2s_full (&(h->call->peer)));
+
+  GNUNET_free (h->call);
+  h->call = NULL;
+
+  return msg_size;
+}
+
+/**
+ * Auxiliary function to call a peer.
+ * 
+ * @param h conversation handle
+ * @return 
+ */
+static void
+initiate_call (struct GNUNET_CONVERSATION_Handle *h, struct 
GNUNET_PeerIdentity peer)
+{
+  h->call =
+    (struct GNUNET_CONVERSATION_CallInformation *)
+    GNUNET_malloc (sizeof (struct GNUNET_CONVERSATION_CallInformation));
+  memcpy (&(h->call->peer), &peer, sizeof (struct GNUNET_PeerIdentity));
+
+  GNUNET_CLIENT_notify_transmit_ready (h->client,
+                                      sizeof (struct
+                                              
ClientServerSessionInitiateMessage),
+                                      MAX_TRANSMIT_DELAY, GNUNET_YES,
+                                      &transmit_session_initiate_message, h);
+
+  return;
+}
+
+/**
+ * Auxiliary function to accept a call.
+ * 
+ * @param h conversation handle
+ */
+static void
+accept_call (struct GNUNET_CONVERSATION_Handle *h)
+{
+  GNUNET_CLIENT_notify_transmit_ready (h->client,
+                                      sizeof (struct
+                                              
ClientServerSessionAcceptMessage),
+                                      MAX_TRANSMIT_DELAY, GNUNET_YES,
+                                      &transmit_session_accept_message, h);
+}
+
+/**
+ * Auxiliary function to reject a call.
+ * 
+ * @param h conversation handle
+ */
+static void
+reject_call (struct GNUNET_CONVERSATION_Handle *h)
+{
+  GNUNET_CLIENT_notify_transmit_ready (h->client,
+                                      sizeof (struct
+                                              
ClientServerSessionRejectMessage),
+                                      MAX_TRANSMIT_DELAY, GNUNET_YES,
+                                      &transmit_session_reject_message, h);
+}
+
+/**
+ * Auxiliary function to terminate a call.
+ * 
+ * @param h conversation handle
+ */
+static void
+terminate_call (struct GNUNET_CONVERSATION_Handle *h)
+{
+  GNUNET_CLIENT_notify_transmit_ready (h->client,
+                                      sizeof (struct
+                                              
ClientServerSessionTerminateMessage),
+                                      MAX_TRANSMIT_DELAY, GNUNET_YES,
+                                      &transmit_session_terminate_message,
+                                      h);
+}
+
+/**
+*
+*/
+static void
+gns_call_cb (void *cls, uint32_t rd_count,
+            const struct GNUNET_NAMESTORE_RecordData *rd)
+{
+  struct GNUNET_PeerIdentity peer;
+  char hash[104];
+  struct GNUNET_CONVERSATION_Handle *handle = (struct 
GNUNET_CONVERSATION_Handle *) cls;
+  int i = 0;
+
+  if (0 == rd_count)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Lookup failed\n");
+      handle->notification_handler (NULL, handle, NotificationType_NO_PEER,
+                                   NULL);
+    }
+  else
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Lookup succeeded\n");
+
+      if (GNUNET_GNS_RECORD_TXT == rd[i].record_type)
+       {
+         memcpy (&hash, rd[i].data, 104);
+         GNUNET_CRYPTO_hash_from_string2 (hash, strlen (hash),
+                                          &(peer.hashPubKey));
+
+         initiate_call (handle, peer);
+       }
+      else
+       {
+         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No resolution!\n");
+         handle->notification_handler (NULL, handle,
+                                       NotificationType_NO_PEER, NULL);
+       }
+    }
+  return;
+}
+
+/**
+* GNS lookup
+*/
+static void
+gns_lookup_and_call (struct GNUNET_CONVERSATION_Handle *h, const char *callee)
+{
+  char domain[GNUNET_DNSPARSER_MAX_NAME_LENGTH];
+  char *pos;
+
+  pos = domain;
+  strcpy (pos, "conversation");
+  pos += strlen ("conversation");
+  strcpy (pos, ".");
+  pos++;
+  strcpy (pos, callee);
+  pos += strlen (callee);
+
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Lookup for %s\n", domain);
+
+  GNUNET_GNS_lookup (h->gns, domain, GNUNET_GNS_RECORD_TXT, GNUNET_NO, NULL,
+                    &gns_call_cb, h);
+
+  return;
+}
+
+/******************************************************************************/
+/**********************      API CALL DEFINITIONS     
*************************/
+/******************************************************************************/
+
+struct GNUNET_CONVERSATION_Handle *
+GNUNET_CONVERSATION_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, 
void *cls,
+                    GNUNET_CONVERSATION_CallHandler * call_handler,
+                    GNUNET_CONVERSATION_RejectHandler * reject_handler,
+                    GNUNET_CONVERSATION_NotificationHandler * 
notification_handler,
+                    GNUNET_CONVERSATION_MissedCallHandler * 
missed_call_handler)
+{
+  struct GNUNET_CONVERSATION_Handle *h;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "GNUNET_CONVERSATION_connect()\n");
+  h = GNUNET_malloc (sizeof (struct GNUNET_CONVERSATION_Handle));
+
+  h->cfg = cfg;
+  h->call_handler = call_handler;
+  h->reject_handler = reject_handler;
+  h->notification_handler = notification_handler;
+  h->missed_call_handler = missed_call_handler;
+
+  if (NULL == (h->client = GNUNET_CLIENT_connect ("conversation", cfg)))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not access CONVERSATION 
service\n");
+      GNUNET_break (0);
+      GNUNET_free (h);
+
+      return NULL;
+    }
+
+  if (NULL == (h->gns = GNUNET_GNS_connect (cfg)))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not access GNS service\n");
+      GNUNET_break (0);
+      GNUNET_CLIENT_disconnect (h->client);
+      GNUNET_free (h);
+
+      return NULL;
+    }
+
+  if (NULL == (h->namestore = GNUNET_NAMESTORE_connect (cfg)))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                 "Could not access NAMESTORE service\n");
+      GNUNET_break (0);
+      GNUNET_CLIENT_disconnect (h->client);
+      GNUNET_GNS_disconnect (h->gns);
+      GNUNET_free (h);
+
+      return NULL;
+    }
+
+  check_gns (h);
+  GNUNET_CLIENT_receive (h->client, &receive_message_cb, h,
+                        GNUNET_TIME_UNIT_FOREVER_REL);
+
+  return h;
+}
+
+void
+GNUNET_CONVERSATION_disconnect (struct GNUNET_CONVERSATION_Handle *handle)
+{
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "CONVERSATION DISCONNECT\n");
+
+  GNUNET_CLIENT_disconnect (handle->client);
+  GNUNET_GNS_disconnect (handle->gns);
+
+  GNUNET_free (handle);
+  handle = NULL;
+}
+
+void
+GNUNET_CONVERSATION_call (struct GNUNET_CONVERSATION_Handle *h, const char 
*callee,
+                 int doGnsLookup)
+{
+  struct GNUNET_PeerIdentity peer;
+  if (NULL == h || NULL == h->client)
+    return;
+
+  if (GNUNET_YES == doGnsLookup)
+    {
+      gns_lookup_and_call (h, callee);
+    }
+  else
+    {
+      if (GNUNET_OK !=
+         GNUNET_CRYPTO_hash_from_string2 (callee, strlen (callee),
+                                          &(peer.hashPubKey)))
+       {
+         h->notification_handler (NULL, h, NotificationType_NO_PEER, NULL);
+       }
+
+      initiate_call (h, peer);
+    }
+}
+
+void
+GNUNET_CONVERSATION_hangup (struct GNUNET_CONVERSATION_Handle *h)
+{
+  if (NULL == h || NULL == h->client)
+    return;
+
+  terminate_call (h);
+}
+
+void
+GNUNET_CONVERSATION_accept (struct GNUNET_CONVERSATION_Handle *h)
+{
+  if (NULL == h || NULL == h->client)
+    return;
+
+  accept_call (h);
+}
+
+void
+GNUNET_CONVERSATION_reject (struct GNUNET_CONVERSATION_Handle *h)
+{
+  if (NULL == h || NULL == h->client)
+    return;
+
+  reject_call (h);
+}
+
+/* end of conversation_api.c */

Added: gnunet/src/conversation/gnunet-conversation.c
===================================================================
--- gnunet/src/conversation/gnunet-conversation.c                               
(rev 0)
+++ gnunet/src/conversation/gnunet-conversation.c       2013-10-01 11:34:38 UTC 
(rev 29754)
@@ -0,0 +1,419 @@
+/*
+                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, InGNUNET_SERVERc., 59 Temple Place - 
Suite 330,
+                Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file conversation/gnunet-conversation.c
+ * @brief conversation implementation
+ * @author Simon Dieterle
+ * @author Andreas Fuchs
+ */
+#include <gnunet/platform.h>
+#include <gnunet/gnunet_constants.h>
+#include <gnunet/gnunet_util_lib.h>
+#include "gnunet_conversation_service.h"
+#include <fcntl.h>
+
+#define MAX_MESSAGE_LENGTH   (32 * 1024)
+
+/**
+* CONVERSATION handle
+*/
+struct GNUNET_CONVERSATION_Handle *conversation = NULL;
+
+/**
+* Task which handles the commands
+*/
+static GNUNET_SCHEDULER_TaskIdentifier handle_cmd_task;
+
+/**
+* Function declareation for executing a action
+*/
+typedef int (*ActionFunction) (const char *argumetns, const void *xtra);
+
+/**
+* Structure which defines a command
+*/
+struct VoipCommand
+{
+  const char *command;
+  ActionFunction Action;
+  const char *helptext;
+};
+
+/******************************************************************************/
+/***********************         DECLARATIONS         
*************************/
+/******************************************************************************/
+
+static int do_help (const char *args, const void *xtra);
+
+/******************************************************************************/
+/***********************         Functions            
*************************/
+/******************************************************************************/
+
+
+/**
+ * Method called whenever a call is incoming
+ *
+ * @param cls closure
+ * @param handle to the conversation session
+ * @param caller peer that calls you
+ */
+void
+call_handler (void *cls, struct GNUNET_CONVERSATION_Handle *handle,
+             const struct GNUNET_PeerIdentity *caller)
+{
+  FPRINTF (stdout, _("Incoming call from peer: %s\n"),
+          GNUNET_i2s_full (caller));
+}
+
+/**
+ * Method called whenever a call is rejected
+ *
+ * @param cls closure
+ * @param handle to the conversation session
+ * @param peer peer that rejected your call
+ */
+void
+reject_handler (void *cls, struct GNUNET_CONVERSATION_Handle *handle, int 
reason,
+               const struct GNUNET_PeerIdentity *peer)
+{
+  FPRINTF (stdout, _("Peer %s rejected your call. Reason: %d\n"),
+          GNUNET_i2s_full (peer), reason);
+}
+
+/**
+ * Method called whenever a notification is there
+ *
+ * @param cls closure
+ * @param handle to the conversation session
+ * @param type the type of the notification
+ * @param peer peer that the notification is about
+ */
+void
+notification_handler (void *cls, struct GNUNET_CONVERSATION_Handle *handle, 
int type,
+                     const struct GNUNET_PeerIdentity *peer)
+{
+  switch (type)
+    {
+    case NotificationType_SERVICE_BLOCKED:
+      FPRINTF (stdout, _("The service is already in use. Try again later."));
+
+      break;
+
+    case NotificationType_NO_PEER:
+      FPRINTF (stdout, _("The Peer you were calling is no correct peer.\n"));
+
+      break;
+
+    case NotificationType_NO_ANSWER:
+      FPRINTF (stdout, _("Peer %s did not answer your call.\n"),
+              GNUNET_i2s_full (peer));
+
+      break;
+
+    case NotificationType_AVAILABLE_AGAIN:
+      FPRINTF (stdout, _("Peer %s is now available.\n"),
+              GNUNET_i2s_full (peer));
+
+      break;
+
+    case NotificationType_CALL_ACCEPTED:
+      FPRINTF (stdout, _("Peer %s has accepted your call.\n"),
+              GNUNET_i2s_full (peer));
+
+      break;
+
+    case NotificationType_CALL_TERMINATED:
+      FPRINTF (stdout, _("Peer %s has terminated the call.\n"),
+              GNUNET_i2s_full (peer));
+      break;
+    }
+
+}
+
+/**
+ * Method called whenever a notification for missed calls is there
+ *
+ * @param cls closure
+ * @param handle to the conversation session
+ * @param missed_calls a list of missed calls
+ */
+void
+missed_call_handler (void *cls, struct GNUNET_CONVERSATION_Handle *handle,
+                    struct GNUNET_CONVERSATION_MissedCallNotification 
*missed_calls)
+{
+  FPRINTF (stdout, _("You have missed calls.\n"));
+}
+
+/**
+* Terminating the client
+*/
+static int
+do_quit (const char *args, const void *xtra)
+{
+  return GNUNET_SYSERR;
+}
+
+/**
+*
+*/
+static int
+do_unknown (const char *msg, const void *xtra)
+{
+  FPRINTF (stderr, _("Unknown command `%s'\n"), msg);
+  return GNUNET_OK;
+}
+
+/**
+* Initiating a new call
+*/
+static int
+do_call (const char *arg, const void *xtra)
+{
+  char *callee = GNUNET_strdup (arg);
+  FPRINTF (stdout, _("Initiating call to: %s\n"), callee);
+  GNUNET_CONVERSATION_call (conversation, callee, GNUNET_YES);
+
+  return GNUNET_OK;
+}
+
+/**
+* Initiating a new call
+*/
+static int
+do_call_peer (const char *arg, const void *xtra)
+{
+  char *callee = GNUNET_strdup (arg);
+  FPRINTF (stdout, _("Initiating call to: %s\n"), callee);
+  GNUNET_CONVERSATION_call (conversation, callee, GNUNET_NO);
+
+  return GNUNET_OK;
+}
+
+/**
+* Accepting an incoming call
+*/
+static int
+do_accept (const char *args, const void *xtra)
+{
+  FPRINTF (stdout, _("Accepting the call\n"));
+  GNUNET_CONVERSATION_accept (conversation);
+
+  return GNUNET_OK;
+}
+
+/**
+* Rejecting a call
+*/
+static int
+do_reject (const char *args, const void *xtra)
+{
+  FPRINTF (stdout, _("Rejecting the call\n"));
+  GNUNET_CONVERSATION_reject (conversation);
+
+  return GNUNET_OK;
+}
+
+/**
+* Terminating a call
+*/
+static int
+do_hang_up (const char *args, const void *xtra)
+{
+  FPRINTF (stdout, _("Terminating the call\n"));
+  GNUNET_CONVERSATION_hangup (conversation);
+
+  return GNUNET_OK;
+}
+
+/**
+ * List of supported commands.
+ */
+static struct VoipCommand commands[] = {
+  {"/call ", &do_call, gettext_noop ("Use `/call gads_record'")},
+  {"/callpeer ", &do_call_peer,
+   gettext_noop ("Use `/call private_key' to call a person")},
+  {"/accept", &do_accept,
+   gettext_noop ("Use `/accept' to accept an incoming call")},
+  {"/terminate", &do_hang_up,
+   gettext_noop ("Use `/terminate' to end a call")},
+  {"/reject", &do_reject,
+   gettext_noop ("Use `/rejet' to reject an incoming call")},
+  {"/quit", &do_quit, gettext_noop ("Use `/quit' to terminate 
gnunet-conversation")},
+  {"/help", &do_help,
+   gettext_noop ("Use `/help command' to get help for a specific command")},
+  {"/", &do_unknown, NULL},
+  {"", &do_unknown, NULL},
+  {NULL, NULL, NULL},
+};
+
+/**
+*
+*/
+static int
+do_help (const char *args, const void *xtra)
+{
+  int i;
+
+  i = 0;
+  while ((NULL != args) && (0 != strlen (args)) &&
+        (commands[i].Action != &do_help))
+    {
+      if (0 ==
+         strncasecmp (&args[1], &commands[i].command[1], strlen (args) - 1))
+       {
+         FPRINTF (stdout, "%s\n", gettext (commands[i].helptext));
+         return GNUNET_OK;
+       }
+      i++;
+    }
+  i = 0;
+  FPRINTF (stdout, "%s", "Available commands:");
+  while (commands[i].Action != &do_help)
+    {
+      FPRINTF (stdout, " %s", gettext (commands[i].command));
+      i++;
+    }
+  FPRINTF (stdout, "%s", "\n");
+  FPRINTF (stdout, "%s\n", gettext (commands[i].helptext));
+  return GNUNET_OK;
+}
+
+/**
+*
+*/
+static void
+do_stop_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Running shutdown task\n");
+  GNUNET_CONVERSATION_disconnect (conversation);
+
+  if (handle_cmd_task != GNUNET_SCHEDULER_NO_TASK)
+    {
+      GNUNET_SCHEDULER_cancel (handle_cmd_task);
+      handle_cmd_task = GNUNET_SCHEDULER_NO_TASK;
+    }
+
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Running shutdown task finished\n");
+}
+
+/**
+*
+*/
+void
+handle_command (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  char message[MAX_MESSAGE_LENGTH + 1];
+  int i;
+
+  /* read message from command line and handle it */
+  memset (message, 0, MAX_MESSAGE_LENGTH + 1);
+  if (NULL == fgets (message, MAX_MESSAGE_LENGTH, stdin))
+    goto next;
+  if (strlen (message) == 0)
+    goto next;
+  if (message[strlen (message) - 1] == '\n')
+    message[strlen (message) - 1] = '\0';
+  if (strlen (message) == 0)
+    goto next;
+  i = 0;
+  while ((NULL != commands[i].command) &&
+        (0 !=
+         strncasecmp (commands[i].command, message,
+                      strlen (commands[i].command))))
+    i++;
+  if (GNUNET_OK !=
+      commands[i].Action (&message[strlen (commands[i].command)], NULL))
+    goto out;
+
+next:
+  handle_cmd_task =
+    GNUNET_SCHEDULER_add_delayed_with_priority (GNUNET_TIME_relative_multiply
+                                               (GNUNET_TIME_UNIT_MILLISECONDS,
+                                                100),
+                                               GNUNET_SCHEDULER_PRIORITY_UI,
+                                               &handle_command, NULL);
+  return;
+
+out:
+  handle_cmd_task = GNUNET_SCHEDULER_NO_TASK;
+  GNUNET_SCHEDULER_shutdown ();
+}
+
+/**
+ * Main function that will be run by the scheduler.
+ *
+ * @param cls closure
+ * @param args remaining command-line arguments
+ * @param cfgfile name of the configuration file used (for saving, can be 
NULL!)
+ * @param c configuration
+ */
+static void
+run (void *cls, char *const *args, const char *cfgfile,
+     const struct GNUNET_CONFIGURATION_Handle *c)
+{
+  if (NULL ==
+      (conversation =
+       GNUNET_CONVERSATION_connect (c, NULL, &call_handler, &reject_handler,
+                           &notification_handler, &missed_call_handler)))
+    {
+      FPRINTF (stderr, "%s", _("Could not access CONVERSATION service.  
Exiting.\n"));
+      return;
+    }
+
+  handle_cmd_task =
+    GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_UI,
+                                       &handle_command, NULL);
+  GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &do_stop_task,
+                               NULL);
+}
+
+/** * The main function to conversation.
+ *
+ * @param argc number of arguments from the command line
+ * @param argv command line arguments
+ * @return 0 ok, 1 on error
+ */
+int
+main (int argc, char *const *argv)
+{
+  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
+    GNUNET_GETOPT_OPTION_END
+  };
+
+  int flags;
+  int ret;
+
+  flags = fcntl (0, F_GETFL, 0);
+  flags |= O_NONBLOCK;
+  fcntl (0, F_SETFL, flags);
+
+  if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
+    return 2;
+
+  ret = GNUNET_PROGRAM_run (argc, argv, "gnunet-conversation",
+                           gettext_noop ("Print information about 
conversation."),
+                           options, &run, NULL);
+  GNUNET_free ((void *) argv);
+
+  return ret;
+}
+
+/* end of gnunet-conversation.c */

Added: gnunet/src/conversation/gnunet-helper-audio-playback.c
===================================================================
--- gnunet/src/conversation/gnunet-helper-audio-playback.c                      
        (rev 0)
+++ gnunet/src/conversation/gnunet-helper-audio-playback.c      2013-10-01 
11:34:38 UTC (rev 29754)
@@ -0,0 +1,391 @@
+#include <gnunet/platform.h>
+#include <gnunet/gnunet_util_lib.h>
+#include "gnunet_protocols_conversation.h"
+#include <gnunet/gnunet_constants.h>
+#include <gnunet/gnunet_core_service.h>
+
+#include <pulse/simple.h>
+#include <pulse/error.h>
+#include <pulse/rtclock.h>
+
+#include <pulse/pulseaudio.h>
+#include <opus/opus.h>
+#include <opus/opus_types.h>
+
+#define MAXLINE 4096
+
+/**
+* GNUnet Message Tokenizer
+*/
+#include "mst.c"
+
+/**
+* Pulseaudio specification. May change in the future.
+*/
+static pa_sample_spec sample_spec = {
+  .format = PA_SAMPLE_FLOAT32LE,
+  .rate = 48000,
+  .channels = 1
+};
+
+/**
+* Pulseaudio mainloop api
+*/
+static pa_mainloop_api *mainloop_api = NULL;
+
+/**
+* Pulseaudio threaded mainloop
+*/
+static pa_threaded_mainloop *m = NULL;
+
+/**
+* Pulseaudio context
+*/
+static pa_context *context = NULL;
+
+/**
+* Pulseaudio output stream
+*/
+static pa_stream *stream_out = NULL;
+
+/**
+* Pulseaudio io events
+*/
+static pa_io_event *stdio_event = NULL;
+
+/**
+* OPUS decoder
+*/
+OpusDecoder *dec = NULL;
+
+/**
+* PCM data buffer
+*/
+float *pcm_buffer;
+
+/**
+* Length of PCM buffer
+*/
+int pcm_length;
+
+/**
+* Number of samples for one frame
+*/
+int frame_size;
+
+/**
+* The sampling rate used in Pulseaudio specification
+*/
+opus_int32 sampling_rate;
+
+/**
+* Audio buffer
+*/
+static void *buffer = NULL;
+
+/**
+* Length of audio buffer
+*/
+static size_t buffer_length = 0;
+
+/**
+* Read index for transmit buffer
+*/
+static size_t buffer_index = 0;
+
+
+
+/**
+* Message callback
+*/
+static void
+stdin_receiver (void *cls, const struct GNUNET_MessageHeader *msg)
+{
+  struct AudioMessage *audio;
+
+  switch (ntohs (msg->type))
+    {
+    case GNUNET_MESSAGE_TYPE_CONVERSATION_AUDIO:
+      audio = (struct AudioMessage *) msg;
+
+      int len =
+       opus_decode_float (dec, audio->audio, audio->length, pcm_buffer,
+                          frame_size, 0);
+
+      if (pa_stream_write
+         (stream_out, (uint8_t *) pcm_buffer, pcm_length, NULL, 0,
+          PA_SEEK_RELATIVE) < 0)
+       {
+
+         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                     _("pa_stream_write() failed: %s\n"),
+                     pa_strerror (pa_context_errno (context)));
+         return;
+       }
+
+      break;
+
+    default:
+      break;
+    }
+}
+
+/**
+* Pulseaudio shutdown task
+*/
+static void
+quit (int ret)
+{
+  mainloop_api->quit (mainloop_api, ret);
+  exit (ret);
+}
+
+/**
+* Write some data to the stream 
+*/
+static void
+do_stream_write (size_t length)
+{
+  size_t l;
+  GNUNET_assert (length);
+
+  if (!buffer || !buffer_length)
+    {
+      return;
+    }
+
+
+  l = length;
+  if (l > buffer_length)
+    {
+      l = buffer_length;
+
+    }
+
+  if (pa_stream_write
+      (stream_out, (uint8_t *) buffer + buffer_index, l, NULL, 0,
+       PA_SEEK_RELATIVE) < 0)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                 _("pa_stream_write() failed: %s\n"),
+                 pa_strerror (pa_context_errno (context)));
+      quit (1);
+      return;
+    }
+
+  buffer_length -= l;
+  buffer_index += l;
+
+  if (!buffer_length)
+    {
+      pa_xfree (buffer);
+      buffer = NULL;
+      buffer_index = buffer_length = 0;
+    }
+}
+
+/**
+* Callback when data is there for playback
+*/
+static void
+stream_write_callback (pa_stream * s, size_t length, void *userdata)
+{
+
+  if (stdio_event)
+    {
+      mainloop_api->io_enable (stdio_event, PA_IO_EVENT_INPUT);
+    }
+
+
+  if (!buffer)
+    {
+      return;
+    }
+
+
+  do_stream_write (length);
+}
+
+/**
+* Exit callback for SIGTERM and SIGINT
+*/
+static void
+exit_signal_callback (pa_mainloop_api * m, pa_signal_event * e, int sig,
+                     void *userdata)
+{
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+             _("gnunet-helper-audio-playback - Got signal, exiting\n"));
+  quit (1);
+}
+
+/**
+* Pulseaudio stream state callback
+*/
+static void
+context_state_callback (pa_context * c, void *userdata)
+{
+  int p;
+  GNUNET_assert (c);
+
+  switch (pa_context_get_state (c))
+    {
+    case PA_CONTEXT_CONNECTING:
+    case PA_CONTEXT_AUTHORIZING:
+    case PA_CONTEXT_SETTING_NAME:
+      break;
+
+    case PA_CONTEXT_READY:
+      {
+       GNUNET_assert (c);
+       GNUNET_assert (!stream_out);
+
+       GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Connection established.\n"));
+
+
+       if (!
+           (stream_out =
+            pa_stream_new (c, "GNUNET VoIP playback", &sample_spec, NULL)))
+         {
+           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                       _("pa_stream_new() failed: %s\n"),
+                       pa_strerror (pa_context_errno (c)));
+           goto fail;
+         }
+
+       pa_stream_set_write_callback (stream_out, stream_write_callback,
+                                     NULL);
+
+       if ((p =
+            pa_stream_connect_playback (stream_out, NULL, NULL, 0, NULL,
+                                        NULL)) < 0)
+         {
+           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                       _("pa_stream_connect_playback() failed: %s\n"),
+                       pa_strerror (pa_context_errno (c)));
+           goto fail;
+         }
+
+       break;
+      }
+
+    case PA_CONTEXT_TERMINATED:
+      quit (0);
+      break;
+
+    case PA_CONTEXT_FAILED:
+    default:
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Connection failure: %s\n"),
+                 pa_strerror (pa_context_errno (c)));
+      goto fail;
+    }
+
+  return;
+
+fail:
+  quit (1);
+
+}
+
+/**
+* Pulseaudio initialization
+*/
+void
+pa_init ()
+{
+  int r;
+
+  if (!pa_sample_spec_valid (&sample_spec))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Wrong Spec\n"));
+    }
+
+  /* set up threaded playback mainloop */
+
+  if (!(m = pa_threaded_mainloop_new ()))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("pa_mainloop_new() failed.\n"));
+    }
+
+  mainloop_api = pa_threaded_mainloop_get_api (m);
+
+
+  /* listen to signals */
+
+  r = pa_signal_init (mainloop_api);
+  GNUNET_assert (r == 0);
+  pa_signal_new (SIGINT, exit_signal_callback, NULL);
+  pa_signal_new (SIGTERM, exit_signal_callback, NULL);
+
+
+  /* connect to the main pulseaudio context */
+
+  if (!(context = pa_context_new (mainloop_api, "GNUnet VoIP")))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("pa_context_new() failed.\n"));
+    }
+
+  pa_context_set_state_callback (context, context_state_callback, NULL);
+
+  if (pa_context_connect (context, NULL, 0, NULL) < 0)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                 _("pa_context_connect() failed: %s\n"),
+                 pa_strerror (pa_context_errno (context)));
+    }
+
+  if (pa_threaded_mainloop_start (m) < 0)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("pa_mainloop_run() failed.\n"));
+    }
+}
+
+/**
+* OPUS initialization
+*/
+void
+opus_init ()
+{
+  int err;
+  int channels = 1;
+  sampling_rate = 48000;
+  frame_size = sampling_rate / 50;
+  pcm_length = frame_size * channels * sizeof (float);
+
+  dec = opus_decoder_create (sampling_rate, channels, &err);
+  pcm_buffer = (float *) pa_xmalloc (frame_size * channels * sizeof (float));
+}
+
+/**
+ * The main function for the playback helper.
+ *
+ * @param argc number of arguments from the command line
+ * @param argv command line arguments
+ * @return 0 ok, 1 on error
+ */
+int
+main (int argc, char *argv[])
+{
+  char readbuf[MAXLINE];
+  struct MessageStreamTokenizer *stdin_mst;
+
+  stdin_mst = mst_create (&stdin_receiver, NULL);
+
+  opus_init ();
+  pa_init ();
+
+  while (1)
+    {
+      ssize_t ret = read (0, readbuf, sizeof (readbuf));
+
+      if (0 > ret)
+       {
+         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                     _("Read error from STDIN: %s\n"), strerror (errno));
+         break;
+       }
+
+      mst_receive (stdin_mst, readbuf, ret);
+    }
+
+  return 0;
+}

Added: gnunet/src/conversation/gnunet-helper-audio-record.c
===================================================================
--- gnunet/src/conversation/gnunet-helper-audio-record.c                        
        (rev 0)
+++ gnunet/src/conversation/gnunet-helper-audio-record.c        2013-10-01 
11:34:38 UTC (rev 29754)
@@ -0,0 +1,446 @@
+#include <gnunet/platform.h>
+#include <gnunet/gnunet_util_lib.h>
+#include "gnunet_protocols_conversation.h"
+#include <gnunet/gnunet_constants.h>
+#include <gnunet/gnunet_core_service.h>
+
+#include <pulse/simple.h>
+#include <pulse/error.h>
+#include <pulse/rtclock.h>
+
+#include <pulse/pulseaudio.h>
+#include <opus/opus.h>
+#include <opus/opus_types.h>
+
+/**
+* Specification for recording. May change in the future to spec negotiation.
+*/
+static pa_sample_spec sample_spec = {
+  .format = PA_SAMPLE_FLOAT32LE,
+  .rate = 48000,
+  .channels = 1
+};
+
+/**
+* Pulseaudio mainloop api
+*/
+static pa_mainloop_api *mainloop_api = NULL;
+
+/**
+* Pulseaudio mainloop
+*/
+static pa_mainloop *m = NULL;
+
+/**
+* Pulseaudio context
+*/
+static pa_context *context = NULL;
+
+/**
+* Pulseaudio recording stream
+*/
+static pa_stream *stream_in = NULL;
+
+/**
+* Pulseaudio io events
+*/
+static pa_io_event *stdio_event = NULL;
+
+/**
+* Message tokenizer
+*/
+struct MessageStreamTokenizer *stdin_mst;
+
+/**
+* OPUS encoder
+*/
+OpusEncoder *enc = NULL;
+
+/**
+*
+*/
+unsigned char *opus_data;
+
+/**
+* PCM data buffer for one OPUS frame
+*/
+float *pcm_buffer;
+
+/**
+ * Length of the pcm data needed for one OPUS frame 
+ */
+int pcm_length;
+
+/**
+* Number of samples for one frame
+*/
+int frame_size;
+
+/**
+* Maximum length of opus payload
+*/
+int max_payload_bytes = 1500;
+
+/**
+* Audio buffer
+*/
+static void *transmit_buffer = NULL;
+
+/**
+* Length of audio buffer
+*/
+static size_t transmit_buffer_length = 0;
+
+/**
+* Read index for transmit buffer
+*/
+static size_t transmit_buffer_index = 0;
+
+/**
+* Audio message skeleton
+*/
+struct AudioMessage *audio_message;
+
+
+
+/**
+* Pulseaudio shutdown task
+*/
+static void
+quit (int ret)
+{
+  mainloop_api->quit (mainloop_api, ret);
+  exit (ret);
+}
+
+
+
+/**
+* Creates OPUS packets from PCM data
+*/
+static void
+packetizer ()
+{
+
+
+  while (transmit_buffer_length >= transmit_buffer_index + pcm_length)
+    {
+
+      int ret;
+      int len;
+
+      size_t msg_size = sizeof (struct AudioMessage);
+
+      memcpy (pcm_buffer,
+             (float *) transmit_buffer +
+             (transmit_buffer_index / sizeof (float)), pcm_length);
+      len =
+       opus_encode_float (enc, pcm_buffer, frame_size, opus_data,
+                          max_payload_bytes);
+
+      audio_message->length = len;
+      memcpy (audio_message->audio, opus_data, len);
+
+      if ((ret = write (1, audio_message, msg_size)) != msg_size)
+       {
+         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("write"));
+         return;
+       }
+
+      transmit_buffer_index += pcm_length;
+    }
+
+  int new_size = transmit_buffer_length - transmit_buffer_index;
+
+  if (0 != new_size)
+    {
+
+      transmit_buffer = pa_xrealloc (transmit_buffer, new_size);
+      memcpy (transmit_buffer, transmit_buffer + transmit_buffer_index,
+             new_size);
+
+      transmit_buffer_index = 0;
+      transmit_buffer_length = new_size;
+    }
+
+}
+
+/**
+* Pulseaudio callback when new data is available.
+*/
+static void
+stream_read_callback (pa_stream * s, size_t length, void *userdata)
+{
+  const void *data;
+  GNUNET_assert (s);
+  GNUNET_assert (length > 0);
+
+  if (stdio_event)
+    mainloop_api->io_enable (stdio_event, PA_IO_EVENT_OUTPUT);
+
+  if (pa_stream_peek (s, (const void **) &data, &length) < 0)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("pa_stream_peek() failed: %s\n"),
+                 pa_strerror (pa_context_errno (context)));
+      quit (1);
+      return;
+    }
+
+  GNUNET_assert (data);
+  GNUNET_assert (length > 0);
+
+  if (transmit_buffer)
+    {
+      transmit_buffer =
+       pa_xrealloc (transmit_buffer, transmit_buffer_length + length);
+      memcpy ((uint8_t *) transmit_buffer + transmit_buffer_length, data,
+             length);
+      transmit_buffer_length += length;
+    }
+  else
+    {
+      transmit_buffer = pa_xmalloc (length);
+      memcpy (transmit_buffer, data, length);
+      transmit_buffer_length = length;
+      transmit_buffer_index = 0;
+    }
+
+  pa_stream_drop (s);
+  packetizer ();
+}
+
+/**
+* Exit callback for SIGTERM and SIGINT
+*/
+static void
+exit_signal_callback (pa_mainloop_api * m, pa_signal_event * e, int sig,
+                     void *userdata)
+{
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Got signal, exiting.\n"));
+  quit (1);
+}
+
+/**
+* Pulseaudio stream state callback
+*/
+static void
+stream_state_callback (pa_stream * s, void *userdata)
+{
+  GNUNET_assert (s);
+
+  switch (pa_stream_get_state (s))
+    {
+    case PA_STREAM_CREATING:
+    case PA_STREAM_TERMINATED:
+      break;
+
+    case PA_STREAM_READY:
+      if (1)
+       {
+         const pa_buffer_attr *a;
+         char cmt[PA_CHANNEL_MAP_SNPRINT_MAX],
+           sst[PA_SAMPLE_SPEC_SNPRINT_MAX];
+
+         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                     _("Stream successfully created.\n"));
+
+         if (!(a = pa_stream_get_buffer_attr (s)))
+           {
+             GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                         _("pa_stream_get_buffer_attr() failed: %s\n"),
+                         pa_strerror (pa_context_errno
+                                      (pa_stream_get_context (s))));
+
+           }
+         else
+           {
+             GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                         _("Buffer metrics: maxlength=%u, fragsize=%u\n"),
+                         a->maxlength, a->fragsize);
+           }
+
+         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                     _("Using sample spec '%s', channel map '%s'.\n"),
+                     pa_sample_spec_snprint (sst, sizeof (sst),
+                                             pa_stream_get_sample_spec (s)),
+                     pa_channel_map_snprint (cmt, sizeof (cmt),
+                                             pa_stream_get_channel_map (s)));
+
+         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                     _("Connected to device %s (%u, %ssuspended).\n"),
+                     pa_stream_get_device_name (s),
+                     pa_stream_get_device_index (s),
+                     pa_stream_is_suspended (s) ? "" : "not ");
+       }
+
+      break;
+
+    case PA_STREAM_FAILED:
+    default:
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Stream error: %s\n"),
+                 pa_strerror (pa_context_errno (pa_stream_get_context (s))));
+      quit (1);
+    }
+}
+
+/**
+* Pulseaudio context state callback
+*/
+static void
+context_state_callback (pa_context * c, void *userdata)
+{
+  GNUNET_assert (c);
+
+  switch (pa_context_get_state (c))
+    {
+    case PA_CONTEXT_CONNECTING:
+    case PA_CONTEXT_AUTHORIZING:
+    case PA_CONTEXT_SETTING_NAME:
+      break;
+
+    case PA_CONTEXT_READY:
+      {
+       int r;
+
+       GNUNET_assert (c);
+       GNUNET_assert (!stream_in);
+
+       GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Connection established.\n"));
+
+       if (!
+           (stream_in =
+            pa_stream_new (c, "GNUNET_VoIP recorder", &sample_spec, NULL)))
+         {
+           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                       _("pa_stream_new() failed: %s\n"),
+                       pa_strerror (pa_context_errno (c)));
+           goto fail;
+         }
+
+
+       pa_stream_set_state_callback (stream_in, stream_state_callback, NULL);
+       pa_stream_set_read_callback (stream_in, stream_read_callback, NULL);
+
+
+       if ((r = pa_stream_connect_record (stream_in, NULL, NULL, 0)) < 0)
+         {
+           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                       _("pa_stream_connect_record() failed: %s\n"),
+                       pa_strerror (pa_context_errno (c)));
+           goto fail;
+         }
+
+       break;
+      }
+
+    case PA_CONTEXT_TERMINATED:
+      quit (0);
+      break;
+
+    case PA_CONTEXT_FAILED:
+    default:
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Connection failure: %s\n"),
+                 pa_strerror (pa_context_errno (c)));
+      goto fail;
+    }
+
+  return;
+
+fail:
+  quit (1);
+
+}
+
+/**
+ * Pulsaudio init
+ */
+void
+pa_init ()
+{
+  int r;
+  int i;
+
+  if (!pa_sample_spec_valid (&sample_spec))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Wrong Spec\n"));
+    }
+
+  /* set up main record loop */
+
+  if (!(m = pa_mainloop_new ()))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("pa_mainloop_new() failed.\n"));
+    }
+
+  mainloop_api = pa_mainloop_get_api (m);
+
+  /* listen to signals */
+
+  r = pa_signal_init (mainloop_api);
+  GNUNET_assert (r == 0);
+  pa_signal_new (SIGINT, exit_signal_callback, NULL);
+  pa_signal_new (SIGTERM, exit_signal_callback, NULL);
+
+  /* connect to the main pulseaudio context */
+
+  if (!(context = pa_context_new (mainloop_api, "GNUNET VoIP")))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("pa_context_new() failed.\n"));
+    }
+
+  pa_context_set_state_callback (context, context_state_callback, NULL);
+
+  if (pa_context_connect (context, NULL, 0, NULL) < 0)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                 _("pa_context_connect() failed: %s\n"),
+                 pa_strerror (pa_context_errno (context)));
+    }
+
+  if (pa_mainloop_run (m, &i) < 0)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("pa_mainloop_run() failed.\n"));
+    }
+}
+
+/**
+ * OPUS init
+ */
+void
+opus_init ()
+{
+  opus_int32 sampling_rate = 48000;
+  frame_size = sampling_rate / 50;
+  int channels = 1;
+
+  pcm_length = frame_size * channels * sizeof (float);
+
+  int err;
+
+  enc =
+    opus_encoder_create (sampling_rate, channels, OPUS_APPLICATION_VOIP,
+                        &err);
+  pcm_buffer = (float *) pa_xmalloc (pcm_length);
+  opus_data = (unsigned char *) calloc (max_payload_bytes, sizeof (char));
+
+  audio_message = pa_xmalloc (sizeof (struct AudioMessage));
+
+  audio_message->header.size = htons (sizeof (struct AudioMessage));
+  audio_message->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_AUDIO);
+}
+
+/**
+ * The main function for the record helper.
+ *
+ * @param argc number of arguments from the command line
+ * @param argv command line arguments
+ * @return 0 ok, 1 on error
+ */
+int
+main (int argc, char *argv[])
+{
+  opus_init ();
+  pa_init ();
+
+  return 0;
+}

Added: gnunet/src/conversation/gnunet-service-conversation.c
===================================================================
--- gnunet/src/conversation/gnunet-service-conversation.c                       
        (rev 0)
+++ gnunet/src/conversation/gnunet-service-conversation.c       2013-10-01 
11:34:38 UTC (rev 29754)
@@ -0,0 +1,1786 @@
+/*
+                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.
+*/
+
+/**
+ * @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
+ */
+#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;
+};
+
+
+/**
+ * Our configuration.
+ */
+static const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+/**
+ * Head of the list of current clients.
+ */
+static struct GNUNET_CONTAINER_SList *clients;
+
+/**
+ * Notification context containing all connected clients.
+ */
+struct GNUNET_SERVER_NotificationContext *nc = NULL;
+
+/**
+* The connection status
+*/
+static struct ConnectionStatus connection;
+
+/**
+* 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
+ */
+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 %llu ms\n",
+          (unsigned long long) total_time.rel_value);
+  FPRINTF (stderr, "Test total packets: %d\n", data_sent);
+  FPRINTF (stderr, "Test bandwidth: %f kb/s\n", data_sent_size * 1.0 / 
total_time.rel_value);  // 4bytes * ms
+  FPRINTF (stderr, "Test throughput: %f packets/s\n\n", data_sent * 1000.0 / 
total_time.rel_value);    // packets * ms
+
+  FPRINTF (stderr, "\nResults of recv\n");
+  FPRINTF (stderr, "Test time %llu ms\n",
+          (unsigned long long) total_time.rel_value);
+  FPRINTF (stderr, "Test total packets: %d\n", data_received);
+  FPRINTF (stderr, "Test bandwidth: %f kb/s\n", data_received_size * 1.0 / 
total_time.rel_value);      // 4bytes * ms
+  FPRINTF (stderr, "Test throughput: %f packets/s\n\n", data_received * 1000.0 
/ total_time.rel_value);        // packets * ms
+}
+
+/**
+* Function which sets the connection state to LISTEN
+*/
+static void
+status_to_listen (void)
+{
+
+  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 ()
+{
+  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;
+    }
+
+  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)
+{
+  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;
+    }
+
+  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)
+ */
+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    
*******************/
+/******************************************************************************/
+
+/**
+ * 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
+ */
+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;
+}
+
+/**
+ * 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
+ */
+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;
+}
+
+/**
+ * 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
+ */
+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;
+}
+
+/**
+ * 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
+ */
+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;
+}
+
+/**
+ * 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
+ */
+static size_t
+transmit_server_missed_call_message (void *cls, size_t size, void *buf)
+{
+  struct ServerClientMissedCallMessage *msg;
+  msg = (struct ServerClientMissedCallMessage *) cls;
+
+  memcpy (buf, msg, size);
+  GNUNET_free (msg);
+
+  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.
+ *
+ * @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
+ */
+static size_t
+transmit_server_service_blocked_message (void *cls, size_t size, void *buf)
+{
+  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;
+}
+
+/**
+ * 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.
+ *
+ * @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
+ */
+static size_t
+transmit_server_peer_not_connected_message (void *cls, size_t size, void *buf)
+{
+  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;
+}
+
+/**
+ * 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.
+ *
+ * @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
+ */
+static size_t
+transmit_server_no_answer_message (void *cls, size_t size, void *buf)
+{
+  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;
+}
+
+/**
+ * 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.
+ *
+ * @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
+ */
+static size_t
+transmit_server_error_message (void *cls, size_t size, void *buf)
+{
+  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;
+}
+
+/******************************************************************************/
+/***********************  RECEIVE FUNCTIONS CL -> SERVER   
********************/
+/******************************************************************************/
+
+/**
+ * Function to handle a session initiate 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)
+{
+  static uint32_t port = 50002;
+  size_t msg_size;
+  struct ClientServerSessionInitiateMessage *msg =
+    (struct ClientServerSessionInitiateMessage *) message;
+  struct GNUNET_PeerIdentity *peer = &(msg->peer);
+
+  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
+ *
+ * @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)
+{
+  size_t msg_size;
+
+  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
+ *
+ * @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)
+{
+  struct ClientServerSessionRejectMessage *message_received;
+
+  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
+ *
+ * @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)
+{
+  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
+ */
+static size_t
+transmit_mesh_message (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"));
+
+  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))
+    {
+      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;
+}
+
+/**
+* Transmit a audo message over mesh
+ * @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
+ */
+static size_t
+transmit_mesh_audio_message (void *cls, size_t size, void *buf)
+{
+  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;
+}
+
+/**
+ * Task to schedule a audio transmission.
+ * 
+ * @param cls Closure.
+ * @param tc Task Context.
+ */
+static void
+transmit_audio_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  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);
+
+  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);
+    }
+}
+
+/******************************************************************************/
+/***********************       RECEIVE FUNCTIONS MESH      
********************/
+/******************************************************************************/
+
+/**
+* Function to handle a initiation 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_initiate_message (void *cls, struct GNUNET_MESH_Tunnel *tunnel,
+                             void **tunnel_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);
+
+    }
+
+  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
+ * @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)
+{
+  //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;
+       }
+    }
+
+  return GNUNET_OK;
+}
+
+/**
+* Function to handle a terminate 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_terminate_message (void *cls, struct GNUNET_MESH_Tunnel *tunnel,
+                              void **tunnel_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;
+       }
+    }
+
+  return GNUNET_OK;
+}
+
+/**
+* Function to handle a audio 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_audio_message (void *cls, struct GNUNET_MESH_Tunnel *tunnel,
+                          void **tunnel_ctx,
+                          const struct GNUNET_MessageHeader *message)
+{
+
+  GNUNET_MESH_receive_done (tunnel);
+
+  if (CONNECTED != connection.status)
+    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)
+    return GNUNET_OK;
+
+  (void) GNUNET_HELPER_send (playback_helper,
+                            message, GNUNET_YES, NULL, NULL);
+
+  data_received++;
+  data_received_size += msg_size;
+
+  return GNUNET_OK;
+}
+
+/******************************************************************************/
+/***********************                     HELPER                
*******************/
+/******************************************************************************/
+
+/**
+* Function to process the audio from the record helper
+ * @param cls closure, NULL
+ * @param client NULL
+ * @param msg the message from the helper
+ * 
+ * @return GNUNET_OK
+*/
+static int
+process_record_messages (void *cls GNUNET_UNUSED, void *client,
+                        const struct GNUNET_MessageHeader *msg)
+{
+  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);
+
+  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)
+{
+  if (NULL != playback_helper)
+    {
+      GNUNET_HELPER_stop (playback_helper, GNUNET_NO);
+      playback_helper = NULL;
+
+      GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Stopped playback helper\n"));
+    }
+}
+
+/**
+* Function to to stop the record helper
+*/
+void
+stop_record_helper (void)
+{
+  if (NULL != record_helper)
+    {
+      GNUNET_HELPER_stop (record_helper, GNUNET_NO);
+      record_helper = NULL;
+
+      GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Stopped record helper\n"));
+    }
+}
+
+/**
+* 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
+ * the other peer initiated.
+ *
+ * @param cls closure
+ * @param tunnel new handle to the tunnel
+ * @param initiator peer that started the tunnel
+ * @param port port
+ * @return initial tunnel context for the tunnel (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)
+{
+  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);
+    }
+
+  return NULL;
+}
+
+
+/**
+ * Function called whenever an inbound tunnel 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
+ */
+static void
+inbound_end (void *cls, const struct GNUNET_MESH_Tunnel *tunnel,
+            void *tunnel_ctx)
+{
+  if (tunnel == tunnel_unreliable)
+    {
+      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 ();
+    }
+}
+
+/******************************************************************************/
+/***********************          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.
+ *
+ * @param cls closure, NULL
+ * @param client identification of the client
+ */
+static void
+handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *cl)
+{
+  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;
+}
+
+/******************************************************************************/
+/***********************                     SERVICE               
*******************/
+/******************************************************************************/
+
+/**
+ * Shutdown nicely
+ * 
+ * @param cls closure, NULL
+ * @param tc the task context
+ */
+static void
+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);
+    }
+
+  if (NULL != mesh)
+    {
+      GNUNET_MESH_disconnect (mesh);
+    }
+
+  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);
+}
+
+
+/**
+ * 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.
+ *
+ * @param cls closure
+ * @param server server handle
+ * @param c configuration
+ */
+static void
+run (void *cls, struct GNUNET_SERVER_Handle *server,
+     const struct GNUNET_CONFIGURATION_Handle *c)
+{
+
+  static uint32_t ports[] = { 50002, 50003, NULL };
+  cfg = c;
+
+  mesh = GNUNET_MESH_connect (cfg,
+                             NULL,
+                             &inbound_tunnel,
+                             &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);
+
+  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,
+                               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.
+ *
+ * @param argc number of arguments from the command line
+ * @param argv command line arguments
+ * @return 0 ok, 1 on error
+ */
+int
+main (int argc, char *const *argv)
+{
+  return (GNUNET_OK ==
+         GNUNET_SERVICE_run (argc, argv, "conversation", 
GNUNET_SERVICE_OPTION_NONE,
+                             &run, NULL)) ? 0 : 1;
+}
+
+/* end of gnunet-service-conversation.c */

Added: gnunet/src/conversation/gnunet_conversation.h
===================================================================
--- gnunet/src/conversation/gnunet_conversation.h                               
(rev 0)
+++ gnunet/src/conversation/gnunet_conversation.h       2013-10-01 11:34:38 UTC 
(rev 29754)
@@ -0,0 +1,163 @@
+/*
+      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 2, 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 include/gnunet_conversation.h
+ * @brief Header to the conversation service
+ * @author Simon Dieterle
+ * @author Andreas Fuchs
+ */
+#ifndef GNUNET_CONVERSATION_H
+#define GNUNET_CONVERSATION_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#if 0                          /* keep Emacsens' auto-indent happy */
+}
+#endif
+#endif
+
+#define MAX_TRANSMIT_DELAY GNUNET_TIME_relative_multiply 
(GNUNET_TIME_UNIT_SECONDS, 60)
+
+/**
+* Reasons for rejecting an incoming call
+*/
+enum reject_reason
+{
+  REJECT_REASON_GENERIC = 0,
+  REJECT_REASON_NOT_AVAILABLE,
+  REJECT_REASON_NO_CLIENT,
+  REJECT_REASON_ACTIVE_CALL,
+  REJECT_REASON_NO_ANSWER
+};
+
+/*
+* The possible connection status
+*/
+enum connection_status
+{
+  LISTEN,
+  CALLER,
+  CALLEE,
+  CONNECTED
+};
+
+/**
+ * VoipClient.
+ */
+struct VoipClient
+{
+  /**
+   * Handle for a conversation client.
+   */
+  struct GNUNET_SERVER_Client *client;
+};
+
+/**
+* The connection status of the service
+*/
+struct ConnectionStatus
+{
+       /**
+       * The client which is in interaction
+       */
+  struct GNUNET_SERVER_Client *client;
+
+       /**
+       * The PeerIdentity of the peer
+       */
+  struct GNUNET_PeerIdentity peer;
+
+       /**
+       * The status (see enum)
+       */
+  int status;
+};
+
+/**
+* Iformation about a missed call
+*/
+struct MissedCall
+{
+       /**
+       * The PeerIdentity of the peer
+       */
+  struct GNUNET_PeerIdentity peer;
+
+       /**
+       * The time the call was
+       */
+  struct GNUNET_TIME_Absolute time;
+
+};
+
+/**
+* Transmit a mesh message
+ * @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
+ */
+static size_t transmit_mesh_message (void *cls, size_t size, void *buf);
+
+/**
+ * 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.
+ *
+ * @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
+ */
+static size_t
+transmit_server_no_answer_message (void *cls, size_t size, void *buf);
+
+/**
+ * Task to schedule a audio transmission.
+ * 
+ * @param cls Closure.
+ * @param tc Task Context.
+ */
+static void
+transmit_audio_task (void *cls,
+                    const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+/**
+* Start the audio helpers
+*/
+int start_helpers (void);
+
+/**
+* Stop the audio helpers
+*/
+void stop_helpers (void);
+
+
+
+#if 0                          /* keep Emacsens' auto-indent happy */
+{
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+#endif

Added: gnunet/src/conversation/gnunet_protocols_conversation.h
===================================================================
--- gnunet/src/conversation/gnunet_protocols_conversation.h                     
        (rev 0)
+++ gnunet/src/conversation/gnunet_protocols_conversation.h     2013-10-01 
11:34:38 UTC (rev 29754)
@@ -0,0 +1,300 @@
+/*
+     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 2, 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 include/gnunet_protocols_conversation.h
+ * @brief constants for network protocols
+ * @author Siomon Dieterle
+ * @author Andreas Fuchs
+ */
+
+#ifndef GNUNET_PROTOCOLS_CONVERSATION_H
+#define GNUNET_PROTOCOLS_CONVERSATION_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#if 0                          /* keep Emacsens' auto-indent happy */
+}
+#endif
+#endif
+
+
+/************************************************************************************************************************
+* Messages for the Client <-> Server communication
+*/
+
+/**
+* Client <-> Server message to initiate a new call
+*/
+#define GNUNET_MESSAGE_TYPE_CONVERSATION_CS_SESSION_INITIATE 30002
+struct ClientServerSessionInitiateMessage
+{
+  struct GNUNET_MessageHeader header;
+  struct GNUNET_PeerIdentity peer;
+};
+
+/**
+* Client <-> Server meessage to accept an incoming call
+*/
+#define GNUNET_MESSAGE_TYPE_CONVERSATION_CS_SESSION_ACCEPT 30003
+struct ClientServerSessionAcceptMessage
+{
+  struct GNUNET_MessageHeader header;
+};
+
+/**
+* Client <-> Server message to reject an incoming call
+*/
+#define GNUNET_MESSAGE_TYPE_CONVERSATION_CS_SESSION_REJECT 30004
+struct ClientServerSessionRejectMessage
+{
+  struct GNUNET_MessageHeader header;
+  int reason;
+};
+
+/**
+* Client <-> Server message to terminat a call
+*/
+#define GNUNET_MESSAGE_TYPE_CONVERSATION_CS_SESSION_TERMINATE 30005
+struct ClientServerSessionTerminateMessage
+{
+  struct GNUNET_MessageHeader header;
+};
+
+/**
+* Client <-> Server message to initiate a new call
+*/
+#define GNUNET_MESSAGE_TYPE_CONVERSATION_CS_TEST 30099
+struct ClientServerTestMessage
+{
+  struct GNUNET_MessageHeader header;
+  struct GNUNET_PeerIdentity peer;
+};
+
+/************************************************************************************************************************
+* Messages for the Server <-> Client communication
+*/
+
+/**
+* Server <-> Client message to initiate a new call
+*/
+#define GNUNET_MESSAGE_TYPE_CONVERSATION_SC_SESSION_INITIATE 30006
+struct ServerClientSessionInitiateMessage
+{
+  struct GNUNET_MessageHeader header;
+  struct GNUNET_PeerIdentity peer;
+};
+
+/**
+* Server <-> Client meessage to accept an incoming call
+*/
+#define GNUNET_MESSAGE_TYPE_CONVERSATION_SC_SESSION_ACCEPT 30007
+struct ServerClientSessionAcceptMessage
+{
+  struct GNUNET_MessageHeader header;
+};
+
+/**
+* Server <-> Client message to reject an incoming call
+*/
+#define GNUNET_MESSAGE_TYPE_CONVERSATION_SC_SESSION_REJECT 30008
+struct ServerClientSessionRejectMessage
+{
+  struct GNUNET_MessageHeader header;
+  int reason;
+  int notify;
+};
+
+/**
+* Server <-> Client message to terminat a call
+*/
+#define GNUNET_MESSAGE_TYPE_CONVERSATION_SC_SESSION_TERMINATE 30009
+struct ServerClientSessionTerminateMessage
+{
+  struct GNUNET_MessageHeader header;
+};
+
+/**
+* Server <-> Client message to signalize the client that the service is 
already in use
+*/
+#define GNUNET_MESSAGE_TYPE_CONVERSATION_SC_SERVICE_BLOCKED 30010
+struct ServerClientServiceBlockedMessage
+{
+  struct GNUNET_MessageHeader header;
+};
+
+/**
+* Server <-> Client message to signalize the client that the called peer is 
not connected
+*/
+#define GNUNET_MESSAGE_TYPE_CONVERSATION_SC_PEER_NOT_CONNECTED 30011
+struct ServerClientPeerNotConnectedMessage
+{
+  struct GNUNET_MessageHeader header;
+};
+
+/**
+* Server <-> Client message to signalize the client that called peer does not 
answer
+*/
+#define GNUNET_MESSAGE_TYPE_CONVERSATION_SC_NO_ANSWER 30012
+struct ServerClientNoAnswerMessage
+{
+  struct GNUNET_MessageHeader header;
+};
+
+/**
+* Server <-> Client message to notify client of missed call
+*/
+#define GNUNET_MESSAGE_TYPE_CONVERSATION_SC_MISSED_CALL 30013
+struct ServerClientMissedCallMessage
+{
+  struct GNUNET_MessageHeader header;
+  int number;
+  struct MissedCall *missed_call;
+};
+
+/**
+* Server <-> Client message to signalize the client that there occured an error
+*/
+#define GNUNET_MESSAGE_TYPE_CONVERSATION_SC_ERROR 30014
+struct ServerClientErrorMessage
+{
+  struct GNUNET_MessageHeader header;
+};
+
+/**
+* Server <-> Client message to notify client of peer being available
+*/
+#define GNUNET_MESSAGE_TYPE_CONVERSATION_SC_PEER_AVAILABLE 30015
+struct ServerClientPeerAvailableMessage
+{
+  struct GNUNET_MessageHeader header;
+  struct GNUNET_PeerIdentity peer;
+  struct GNUNET_TIME_Absolute time;
+};
+
+/************************************************************************************************************************
+* Messages for the Mesh communication
+*/
+
+struct VoIPMeshMessageHeader
+{
+  struct GNUNET_MessageHeader header;
+  int SequenceNumber;
+  struct GNUNET_TIME_Absolute time;
+};
+
+/**
+* Mesh message to sinal the remote peer the wish to initiate a new call
+*/
+#define GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_SESSION_INITIATE 40000
+struct MeshSessionInitiateMessage
+{
+  struct GNUNET_MessageHeader header;
+  int SequenceNumber;
+  struct GNUNET_TIME_Absolute time;
+  struct GNUNET_PeerIdentity peer;
+};
+
+/**
+* Mesh message to signal the remote peer the acceptance of an initiated call
+*/
+#define GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_SESSION_ACCEPT 40001
+struct MeshSessionAcceptMessage
+{
+  struct GNUNET_MessageHeader header;
+  int SequenceNumber;
+  struct GNUNET_TIME_Absolute time;
+};
+
+/**
+* Mesh message to reject an a wish to initiate a new call
+*/
+#define GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_SESSION_REJECT 40002
+struct MeshSessionRejectMessage
+{
+  struct GNUNET_MessageHeader header;
+  int SequenceNumber;
+  struct GNUNET_TIME_Absolute time;
+  int reason;
+  int notify;
+};
+
+/**
+* Mesh message to signal a remote peer the terminatation of a call
+*/
+#define GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_SESSION_TERMINATE 40003
+struct MeshSessionTerminateMessage
+{
+  struct GNUNET_MessageHeader header;
+  int SequenceNumber;
+  struct GNUNET_TIME_Absolute time;
+};
+
+/**
+* Server <-> Client message to notify client of peer being available
+*/
+#define GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PEER_AVAILABLE 40004
+struct MeshPeerAvailableMessage
+{
+  struct GNUNET_MessageHeader header;
+  int SequenceNumber;
+  struct GNUNET_TIME_Absolute time;
+  struct GNUNET_PeerIdentity peer;
+  struct GNUNET_TIME_Absolute call;
+};
+
+/************************************************************************************************************************
+* Messages for the audio communication
+*/
+
+
+#define GNUNET_MESSAGE_TYPE_CONVERSATION_TEST 50001
+struct TestMessage
+{
+  struct GNUNET_MessageHeader header;
+};
+
+/**
+* Message to transmit the audio
+*/
+#define GNUNET_MESSAGE_TYPE_CONVERSATION_AUDIO 50000
+struct AudioMessage
+{
+  struct GNUNET_MessageHeader header;
+  int SequenceNumber;
+  struct GNUNET_TIME_Absolute time;
+  int length;
+  int encrypted;
+  uint8_t audio[200];
+
+};
+
+
+#if 0                          /* keep Emacsens' auto-indent happy */
+{
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+/* ifndef GNUNET_PROTOCOLS_CONVERSATION_H */
+#endif
+/* end of gnunet_protocols_conversation.h */

Added: gnunet/src/conversation/mst.c
===================================================================
--- gnunet/src/conversation/mst.c                               (rev 0)
+++ gnunet/src/conversation/mst.c       2013-10-01 11:34:38 UTC (rev 29754)
@@ -0,0 +1,288 @@
+/*
+     This file is part of GNUnet.
+     (C) 2008, 2011 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/mst.c
+ * @brief Message tokenizer
+ * @author Christian Grothoff
+ */
+
+#include <gnunet/platform.h>
+#include <gnunet/gnunet_constants.h>
+
+/**
+ * To what multiple do we align messages?  8 byte should suffice for everyone
+ * for now.
+ */
+#define ALIGN_FACTOR 8
+
+/**
+ * Smallest supported message.
+ */
+#define MIN_BUFFER_SIZE sizeof (struct GNUNET_MessageHeader)
+
+
+/**
+ * Functions with this signature are called whenever a
+ * complete message is received by the tokenizer.
+ *
+ * @param cls closure
+ * @param message the actual message
+ */
+typedef void (*MessageTokenizerCallback) (void *cls, 
+                                         const struct
+                                         GNUNET_MessageHeader *
+                                         message);
+
+/**
+ * Handle to a message stream tokenizer.
+ */
+struct MessageStreamTokenizer
+{
+
+  /**
+   * Function to call on completed messages.
+   */
+  MessageTokenizerCallback cb;
+
+  /**
+   * Closure for cb.
+   */
+  void *cb_cls;
+
+  /**
+   * Size of the buffer (starting at 'hdr').
+   */
+  size_t curr_buf;
+
+  /**
+   * How many bytes in buffer have we already processed?
+   */
+  size_t off;
+
+  /**
+   * How many bytes in buffer are valid right now?
+   */
+  size_t pos;
+
+  /**
+   * Beginning of the buffer.  Typed like this to force alignment.
+   */
+  struct GNUNET_MessageHeader *hdr;
+
+};
+
+
+/**
+ * Create a message stream tokenizer.
+ *
+ * @param cb function to call on completed messages
+ * @param cb_cls closure for cb
+ * @return handle to tokenizer
+ */
+static struct MessageStreamTokenizer *
+mst_create (MessageTokenizerCallback cb,
+               void *cb_cls)
+{
+  struct MessageStreamTokenizer *ret;
+
+  ret = malloc (sizeof (struct MessageStreamTokenizer));
+  if (NULL == ret)
+  {
+       fprintf (stderr, "Failed to allocate buffer for tokenizer\n");
+       exit (1);
+  }
+  ret->hdr = malloc (MIN_BUFFER_SIZE);
+  if (NULL == ret->hdr)
+  {
+       fprintf (stderr, "Failed to allocate buffer for alignment\n");
+       exit (1);
+  }
+  ret->curr_buf = MIN_BUFFER_SIZE;
+  ret->cb = cb;
+  ret->cb_cls = cb_cls;
+  return ret;
+}
+
+
+/**
+ * Add incoming data to the receive buffer and call the
+ * callback for all complete messages.
+ *
+ * @param mst tokenizer to use
+ * @param buf input data to add
+ * @param size number of bytes in buf
+ * @return GNUNET_OK if we are done processing (need more data)
+ *         GNUNET_SYSERR if the data stream is corrupt
+ */
+static int
+mst_receive (struct MessageStreamTokenizer *mst,
+                const char *buf, size_t size)
+{
+  const struct GNUNET_MessageHeader *hdr;
+  size_t delta;
+  uint16_t want;
+  char *ibuf;
+  int need_align;
+  unsigned long offset;
+  int ret;
+
+  ret = GNUNET_OK;
+  ibuf = (char *) mst->hdr;
+  while (mst->pos > 0)
+  {
+do_align:
+       if ((mst->curr_buf - mst->off < sizeof (struct GNUNET_MessageHeader)) ||
+               (0 != (mst->off % ALIGN_FACTOR)))
+       {
+         /* need to align or need more space */
+         mst->pos -= mst->off;
+         memmove (ibuf, &ibuf[mst->off], mst->pos);
+         mst->off = 0;
+       }
+       if (mst->pos - mst->off < sizeof (struct GNUNET_MessageHeader))
+       {
+         delta =
+                 GNUNET_MIN (sizeof (struct GNUNET_MessageHeader) -
+                                         (mst->pos - mst->off), size);
+         memcpy (&ibuf[mst->pos], buf, delta);
+         mst->pos += delta;
+         buf += delta;
+         size -= delta;
+       }
+       if (mst->pos - mst->off < sizeof (struct GNUNET_MessageHeader))
+       {
+         return GNUNET_OK;
+       }
+       hdr = (const struct GNUNET_MessageHeader *) &ibuf[mst->off];
+       want = ntohs (hdr->size);
+       if (want < sizeof (struct GNUNET_MessageHeader))
+       {
+         fprintf (stderr,
+                  "Received invalid message from stdin\n");
+         exit (1);
+       }
+       if (mst->curr_buf - mst->off < want)
+       {
+         /* need more space */
+         mst->pos -= mst->off;
+         memmove (ibuf, &ibuf[mst->off], mst->pos);
+         mst->off = 0;
+       }
+       if (want > mst->curr_buf)
+       {
+         mst->hdr = realloc (mst->hdr, want);
+         if (NULL == mst->hdr)
+         {
+       fprintf (stderr, "Failed to allocate buffer for alignment\n");
+       exit (1);
+         }
+         ibuf = (char *) mst->hdr;
+         mst->curr_buf = want;
+       }
+       hdr = (const struct GNUNET_MessageHeader *) &ibuf[mst->off];
+       if (mst->pos - mst->off < want)
+       {
+         delta = GNUNET_MIN (want - (mst->pos - mst->off), size);
+         memcpy (&ibuf[mst->pos], buf, delta);
+         mst->pos += delta;
+         buf += delta;
+         size -= delta;
+       }
+       if (mst->pos - mst->off < want)
+       {
+         return GNUNET_OK;
+       }
+       mst->cb (mst->cb_cls, hdr);
+       mst->off += want;
+       if (mst->off == mst->pos)
+       {
+         /* reset to beginning of buffer, it's free right now! */
+         mst->off = 0;
+         mst->pos = 0;
+       }
+  }
+  while (size > 0)
+  {
+       if (size < sizeof (struct GNUNET_MessageHeader))
+         break;
+       offset = (unsigned long) buf;
+       need_align = (0 != offset % ALIGN_FACTOR) ? GNUNET_YES : GNUNET_NO;
+       if (GNUNET_NO == need_align)
+       {
+         /* can try to do zero-copy and process directly from original buffer 
*/
+         hdr = (const struct GNUNET_MessageHeader *) buf;
+         want = ntohs (hdr->size);
+         if (want < sizeof (struct GNUNET_MessageHeader))
+         {
+       fprintf (stderr,
+                "Received invalid message from stdin\n");
+       exit (1);
+         }
+         if (size < want)
+               break;                  /* or not, buffer incomplete, so copy 
to private buffer... */
+         mst->cb (mst->cb_cls, hdr);
+         buf += want;
+         size -= want;
+       }
+       else
+       {
+         /* need to copy to private buffer to align;
+          * yes, we go a bit more spagetti than usual here */
+         goto do_align;
+       }
+  }
+  if (size > 0)
+  {
+       if (size + mst->pos > mst->curr_buf)
+       {
+         mst->hdr = realloc (mst->hdr, size + mst->pos);
+         if (NULL == mst->hdr)
+         {
+       fprintf (stderr, "Failed to allocate buffer for alignment\n");
+       exit (1);
+         }
+         ibuf = (char *) mst->hdr;
+         mst->curr_buf = size + mst->pos;
+       }
+       if (mst->pos + size > mst->curr_buf)
+       {
+         fprintf (stderr,
+                  "Assertion failed\n");
+         exit (1);
+       }
+       memcpy (&ibuf[mst->pos], buf, size);
+       mst->pos += size;
+  }
+  return ret;
+}
+
+
+/**
+ * Destroys a tokenizer.
+ *
+ * @param mst tokenizer to destroy
+ */
+static void
+mst_destroy (struct MessageStreamTokenizer *mst)
+{
+  free (mst->hdr);
+  free (mst);
+}

Added: gnunet/src/conversation/test_voip.api.c
===================================================================
--- gnunet/src/conversation/test_voip.api.c                             (rev 0)
+++ gnunet/src/conversation/test_voip.api.c     2013-10-01 11:34:38 UTC (rev 
29754)
@@ -0,0 +1,85 @@
+/*
+     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.
+*/
+/**
+ * @file voip/src/test_voip_api.c
+ * @brief testcase for voip_api.c
+ */
+#include <gnunet/platform.h>
+#include <gnunet/gnunet_util_lib.h>
+#include "gnunet_voip_service.h"
+
+
+static int ok = 1;
+
+
+static void
+run (void *cls,
+     char *const *args,
+     const char *cfgfile,
+     const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+  ok = 0;
+}
+
+
+static int
+check ()
+{
+  char *const argv[] = { "test-voip-api", NULL };
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+    GNUNET_GETOPT_OPTION_END
+  };
+  struct GNUNET_OS_Process *proc;
+  char *path = GNUNET_OS_get_libexec_binary_path ( "gnunet-service-voip");
+  if (NULL == path)
+  {
+               fprintf (stderr, "Service executable not found `%s'\n", 
"gnunet-service-voip");
+               return;
+  }
+  proc = GNUNET_OS_start_process (GNUNET_NO, GNUNET_OS_INHERIT_STD_ALL, NULL, 
NULL,
+                               path,
+                                 "gnunet-service-voip",
+                                 NULL);
+
+  GNUNET_free (path);
+  GNUNET_assert (NULL != proc);
+  GNUNET_PROGRAM_run (1, argv, "test-ext-voip", "nohelp",
+                      options, &run, &ok);
+  if (0 != GNUNET_OS_process_kill (proc, SIGTERM))
+    {
+      GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
+      ok = 1;
+    }
+  GNUNET_OS_process_wait (proc);
+  GNUNET_OS_process_destroy (proc);
+  return ok;
+}
+
+
+int
+main (int argc, char *argv[])
+{
+  GNUNET_log_setup ("test_voip_api", 
+                   "WARNING",
+                   NULL);
+  return check ();
+}
+
+/* end of test_voip_api.c */




reply via email to

[Prev in Thread] Current Thread [Next in Thread]