[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,
+ ¬ification_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 */
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [GNUnet-SVN] r29754 - in gnunet: . src src/conversation,
gnunet <=