aboutsummaryrefslogtreecommitdiff
path: root/src/conversation/gnunet-service-conversation.c
diff options
context:
space:
mode:
authorAndreas Fuchs <fuchandr@in.tum.de>2013-10-01 11:34:38 +0000
committerAndreas Fuchs <fuchandr@in.tum.de>2013-10-01 11:34:38 +0000
commit70c7532c4d0c684afc4158984f9a37ae7cf05ba3 (patch)
tree693ef5a8b848db69c6e4b79c2d6f2a583f99db0c /src/conversation/gnunet-service-conversation.c
parent408c3426ad378e8eef910ca6fea1144110346b0b (diff)
downloadgnunet-70c7532c4d0c684afc4158984f9a37ae7cf05ba3.tar.gz
gnunet-70c7532c4d0c684afc4158984f9a37ae7cf05ba3.zip
Initial conversation (experimental) commit
Diffstat (limited to 'src/conversation/gnunet-service-conversation.c')
-rw-r--r--src/conversation/gnunet-service-conversation.c1786
1 files changed, 1786 insertions, 0 deletions
diff --git a/src/conversation/gnunet-service-conversation.c b/src/conversation/gnunet-service-conversation.c
new file mode 100644
index 000000000..9b9b4f316
--- /dev/null
+++ b/src/conversation/gnunet-service-conversation.c
@@ -0,0 +1,1786 @@
1/*
2 This file is part of GNUnet.
3 (C)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file conversation/gnunet-service-conversation.c
23 * @brief conversation service implementation
24 * @author Simon Dieterle
25 * @author Andreas Fuchs
26 * STRUCTURE:
27 * - Variables
28 * - AUXILIARY FUNCTIONS
29 * - SENDING FUNCTIONS CL -> SERVER
30 * - RECEIVE FUNCTIONS CL -> SERVER
31 * - SENDING FUNCTIONS MESH
32 * - RECEIVE FUNCTIONS MESH
33 * - HELPER
34 * - TUNNEL HANDLING
35 * - CLIENT HANDLING
36 */
37#include <gnunet/platform.h>
38#include <gnunet/gnunet_util_lib.h>
39#include <gnunet/gnunet_constants.h>
40#include <gnunet/gnunet_mesh_service.h>
41#include "gnunet_conversation.h"
42#include "gnunet_protocols_conversation.h"
43
44/********************************************************
45 * Ugly hack because of not working MESH API
46*/
47typedef uint32_t MESH_TunnelNumber;
48struct GNUNET_MESH_Tunnel
49{
50 struct GNUNET_MESH_Tunnel *next;
51 struct GNUNET_MESH_Tunnel *prev;
52 struct GNUNET_MESH_Handle *mesh;
53 MESH_TunnelNumber tid;
54 uint32_t port;
55 GNUNET_PEER_Id peer;
56 void *ctx;
57 unsigned int packet_size;
58 int buffering;
59 int reliable;
60 int allow_send;
61};
62
63
64/**
65 * Our configuration.
66 */
67static const struct GNUNET_CONFIGURATION_Handle *cfg;
68
69/**
70 * Head of the list of current clients.
71 */
72static struct GNUNET_CONTAINER_SList *clients;
73
74/**
75 * Notification context containing all connected clients.
76 */
77struct GNUNET_SERVER_NotificationContext *nc = NULL;
78
79/**
80* The connection status
81*/
82static struct ConnectionStatus connection;
83
84/**
85* Handle for the record helper
86*/
87static struct GNUNET_HELPER_Handle *record_helper;
88
89/** Handle for the playback handler
90*
91*/
92static struct GNUNET_HELPER_Handle *playback_helper;
93
94/**
95* Handle for mesh
96*/
97static struct GNUNET_MESH_Handle *mesh;
98
99/**
100* Transmit handle for audio messages
101*/
102static struct GNUNET_MESH_TransmitHandle *mth = NULL;
103
104/**
105* Handle for the reliable tunnel (contol data)
106*/
107static struct GNUNET_MESH_Tunnel *tunnel_reliable;
108
109/**
110* Handle for unreliable tunnel (audio data)
111*/
112static struct GNUNET_MESH_Tunnel *tunnel_unreliable;
113
114/**
115* List for missed calls
116*/
117struct GNUNET_CONTAINER_SList *missed_calls;
118
119/**
120* List for peers to notify that we are available again
121*/
122struct GNUNET_CONTAINER_SList *peers_to_notify;
123
124/**
125* Audio buffer (outgoing)
126*/
127struct GNUNET_CONTAINER_SList *audio_buffer;
128
129/**
130* The pointer to the task for sending audio
131*/
132GNUNET_SCHEDULER_TaskIdentifier audio_task;
133
134/**
135* The pointer to the task for checking timeouts an calling a peer
136*/
137GNUNET_SCHEDULER_TaskIdentifier timeout_task;
138
139/**
140* Sequencenumber for the pakets (for evaltuation purposes)
141*/
142int SequenceNumber = 0;
143
144/**
145* Timestamp for call statistics
146*/
147static struct GNUNET_TIME_Absolute start_time;
148
149/**
150 * Number of payload packes sent
151 */
152static int data_sent;
153static int data_sent_size;
154
155/**
156 * Number of payload packets received
157 */
158static int data_received;
159static int data_received_size;
160
161/******************************************************************************/
162/*********************** AUXILIARY FUNCTIONS *************************/
163/******************************************************************************/
164
165/**
166* Function which displays some call stats
167*/
168static void
169show_end_data (void)
170{
171 static struct GNUNET_TIME_Absolute end_time;
172 static struct GNUNET_TIME_Relative total_time;
173
174 end_time = GNUNET_TIME_absolute_get ();
175 total_time = GNUNET_TIME_absolute_get_difference (start_time, end_time);
176 FPRINTF (stderr, "\nResults of send\n");
177 FPRINTF (stderr, "Test time %llu ms\n",
178 (unsigned long long) total_time.rel_value);
179 FPRINTF (stderr, "Test total packets: %d\n", data_sent);
180 FPRINTF (stderr, "Test bandwidth: %f kb/s\n", data_sent_size * 1.0 / total_time.rel_value); // 4bytes * ms
181 FPRINTF (stderr, "Test throughput: %f packets/s\n\n", data_sent * 1000.0 / total_time.rel_value); // packets * ms
182
183 FPRINTF (stderr, "\nResults of recv\n");
184 FPRINTF (stderr, "Test time %llu ms\n",
185 (unsigned long long) total_time.rel_value);
186 FPRINTF (stderr, "Test total packets: %d\n", data_received);
187 FPRINTF (stderr, "Test bandwidth: %f kb/s\n", data_received_size * 1.0 / total_time.rel_value); // 4bytes * ms
188 FPRINTF (stderr, "Test throughput: %f packets/s\n\n", data_received * 1000.0 / total_time.rel_value); // packets * ms
189}
190
191/**
192* Function which sets the connection state to LISTEN
193*/
194static void
195status_to_listen (void)
196{
197
198 if (CONNECTED == connection.status)
199 {
200 show_end_data ();
201 }
202
203 if (timeout_task != GNUNET_SCHEDULER_NO_TASK)
204 {
205 GNUNET_SCHEDULER_cancel (timeout_task);
206 timeout_task = GNUNET_SCHEDULER_NO_TASK;
207 }
208
209 stop_helpers ();
210
211 connection.status = LISTEN;
212 connection.client = NULL;
213
214 data_sent = 0;
215 data_sent_size = 0;
216 data_received = 0;
217 data_received_size = 0;
218
219 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Changed connection status to %s\n"),
220 "LISTEN");
221}
222
223/**
224* Function to terminate the active call
225*/
226static void
227terminate_call ()
228{
229 size_t msg_size;
230 msg_size = sizeof (struct MeshSessionTerminateMessage);
231 struct MeshSessionTerminateMessage *message_mesh_terminate =
232 (struct MeshSessionTerminateMessage *) GNUNET_malloc (msg_size);
233
234 if (NULL == message_mesh_terminate)
235 {
236 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
237 _("Could not create MeshSessionTerminateMessage\n"));
238 status_to_listen ();
239
240 return;
241 }
242
243 message_mesh_terminate->header.size = htons (msg_size);
244 message_mesh_terminate->header.type =
245 htons (GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_SESSION_TERMINATE);
246
247 if (NULL ==
248 GNUNET_MESH_notify_transmit_ready (tunnel_reliable, 0,
249 MAX_TRANSMIT_DELAY, msg_size,
250 &transmit_mesh_message,
251 (void *) message_mesh_terminate))
252 {
253 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
254 _("Could not queue MeshSessionTerminateMessage\n"));
255 GNUNET_free (message_mesh_terminate);
256 status_to_listen ();
257 }
258}
259
260/**
261* Function to reject a call
262*
263* @param tunnel the tunnel where to reject the incoming call
264* @param reason te reson why the call is rejected
265*/
266static void
267reject_call (struct GNUNET_MESH_Tunnel *tunnel, int reason)
268{
269 size_t msg_size;
270 msg_size = sizeof (struct MeshSessionRejectMessage);
271 struct MeshSessionRejectMessage *message_mesh_reject =
272 (struct MeshSessionRejectMessage *) GNUNET_malloc (msg_size);
273
274 if (NULL == message_mesh_reject)
275 {
276 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
277 _("Could not create MeshSessionRejectMessage\n"));
278 status_to_listen ();
279
280 return;
281 }
282
283 message_mesh_reject->header.size = htons (msg_size);
284 message_mesh_reject->header.type =
285 htons (GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_SESSION_REJECT);
286 message_mesh_reject->reason = htons (reason);
287
288 if (NULL ==
289 GNUNET_MESH_notify_transmit_ready (tunnel_reliable, 0,
290 MAX_TRANSMIT_DELAY, msg_size,
291 &transmit_mesh_message,
292 (void *) message_mesh_reject))
293 {
294 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
295 _("Could not queue MeshSessionRejectMessage\n"));
296 GNUNET_free (message_mesh_reject);
297 status_to_listen ();
298 }
299}
300
301/**
302 * Check for timeout when calling a peer
303 *
304 * @param cls closure, NULL
305 * @param tc the task context (can be NULL)
306 */
307static void
308check_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
309{
310 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Call timeout\n");
311
312 if (NULL ==
313 GNUNET_SERVER_notify_transmit_ready (connection.client,
314 sizeof (struct
315 ServerClientNoAnswerMessage),
316 MAX_TRANSMIT_DELAY,
317 &transmit_server_no_answer_message,
318 NULL))
319 {
320 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
321 _("Could not queue ServerClientNoAnswerMessage\n"));
322 }
323
324 terminate_call ();
325}
326
327/******************************************************************************/
328/*********************** SENDING FUNCTIONS CL -> SERVER *******************/
329/******************************************************************************/
330
331/**
332 * Function called to send a session initiate message to the client.
333 * "buf" will be NULL and "size" zero if the socket was closed for writing in
334 * the meantime.
335 *
336 * @param cls closure, NULL
337 * @param size number of bytes available in buf
338 * @param buf where the callee should write the initiate message
339 * @return number of bytes written to buf
340 */
341static size_t
342transmit_server_initiate_message (void *cls, size_t size, void *buf)
343{
344 struct ServerClientSessionInitiateMessage *msg;
345 size_t msg_size;
346
347 msg_size = sizeof (struct ServerClientSessionInitiateMessage);
348
349 GNUNET_assert (size >= msg_size);
350
351 msg = (struct ServerClientSessionInitiateMessage *) buf;
352 msg->header.size = htons (msg_size);
353 msg->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_SC_SESSION_INITIATE);
354 memcpy (&(msg->peer), (struct GNUNET_PeerIdentity *) cls,
355 sizeof (struct GNUNET_PeerIdentity));
356
357 return msg_size;
358}
359
360/**
361 * Function called to send a session accept message to the client.
362 * "buf" will be NULL and "size" zero if the socket was closed for writing in
363 * the meantime.
364 *
365 * @param cls closure, NULL
366 * @param size number of bytes available in buf
367 * @param buf where the callee should write the accept message
368 * @return number of bytes written to buf
369 */
370static size_t
371transmit_server_accept_message (void *cls, size_t size, void *buf)
372{
373 struct ServerClientSessionAcceptMessage *msg;
374 size_t msg_size;
375
376 msg_size = sizeof (struct ServerClientSessionAcceptMessage);
377
378 GNUNET_assert (size >= msg_size);
379
380 msg = (struct ServerClientSessionAcceptMessage *) buf;
381 msg->header.size = htons (msg_size);
382 msg->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_SC_SESSION_ACCEPT);
383
384 return msg_size;
385}
386
387/**
388 * Function called to send a session reject message to the client.
389 * "buf" will be NULL and "size" zero if the socket was closed for writing in
390 * the meantime.
391 *
392 * @param cls closure, NULL
393 * @param size number of bytes available in buf
394 * @param buf where the callee should write the reject message
395 * @return number of bytes written to buf
396 */
397static size_t
398transmit_server_reject_message (void *cls, size_t size, void *buf)
399{
400 struct ServerClientSessionRejectMessage *msg;
401 size_t msg_size;
402
403 msg_size = sizeof (struct ServerClientSessionRejectMessage);
404
405 GNUNET_assert (size >= msg_size);
406
407 msg = (struct ServerClientSessionRejectMessage *) buf;
408 msg->header.size = htons (msg_size);
409 msg->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_SC_SESSION_REJECT);
410
411 if (NULL == cls)
412 {
413 msg->reason = htons (REJECT_REASON_NOT_AVAILABLE);
414 }
415 else
416 {
417 msg->reason = ((struct MeshSessionRejectMessage *) cls)->reason;
418 }
419
420 return msg_size;
421}
422
423/**
424 * Function called to send a session terminate message to the client.
425 * "buf" will be NULL and "size" zero if the socket was closed for writing in
426 * the meantime.
427 *
428 * @param cls closure, NULL
429 * @param size number of bytes available in buf
430 * @param buf where the callee should write the terminate message
431 * @return number of bytes written to buf
432 */
433static size_t
434transmit_server_terminate_message (void *cls, size_t size, void *buf)
435{
436 struct ServerClientSessionTerminateMessage *msg;
437 size_t msg_size;
438
439 msg_size = sizeof (struct ServerClientSessionTerminateMessage);
440
441 GNUNET_assert (size >= msg_size);
442
443 msg = (struct ServerClientSessionTerminateMessage *) buf;
444 msg->header.size = htons (msg_size);
445 msg->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_SC_SESSION_TERMINATE);
446
447 return msg_size;
448}
449
450/**
451 * Function called to send a missed call message to the client.
452 * "buf" will be NULL and "size" zero if the socket was closed for writing in
453 * the meantime.
454 *
455 * @param cls closure, NULL
456 * @param size number of bytes available in buf
457 * @param buf where the callee should write the missed call message
458 * @return number of bytes written to buf
459 */
460static size_t
461transmit_server_missed_call_message (void *cls, size_t size, void *buf)
462{
463 struct ServerClientMissedCallMessage *msg;
464 msg = (struct ServerClientMissedCallMessage *) cls;
465
466 memcpy (buf, msg, size);
467 GNUNET_free (msg);
468
469 return size;
470}
471
472/**
473 * Function called to send a service blocked message to the client.
474 * "buf" will be NULL and "size" zero if the socket was closed for writing in
475 * the meantime.
476 *
477 * @param cls closure, NULL
478 * @param size number of bytes available in buf
479 * @param buf where the callee should write the service blocked message
480 * @return number of bytes written to buf
481 */
482static size_t
483transmit_server_service_blocked_message (void *cls, size_t size, void *buf)
484{
485 struct ServerClientServiceBlockedMessage *msg;
486 size_t msg_size;
487
488 msg_size = sizeof (struct ServerClientServiceBlockedMessage);
489
490 GNUNET_assert (size >= msg_size);
491
492 msg = (struct ServerClientServiceBlockedMessage *) buf;
493 msg->header.size = htons (msg_size);
494 msg->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_SC_SERVICE_BLOCKED);
495
496 return msg_size;
497}
498
499/**
500 * Function called to send a peer not connected message to the client.
501 * "buf" will be NULL and "size" zero if the socket was closed for writing in
502 * the meantime.
503 *
504 * @param cls closure, NULL
505 * @param size number of bytes available in buf
506 * @param buf where the callee should write the peer not connected message
507 * @return number of bytes written to buf
508 */
509static size_t
510transmit_server_peer_not_connected_message (void *cls, size_t size, void *buf)
511{
512 struct ServerClientPeerNotConnectedMessage *msg;
513 size_t msg_size;
514
515 msg_size = sizeof (struct ServerClientPeerNotConnectedMessage);
516
517 GNUNET_assert (size >= msg_size);
518
519 msg = (struct ServerClientPeerNotConnectedMessage *) buf;
520 msg->header.size = htons (msg_size);
521 msg->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_SC_PEER_NOT_CONNECTED);
522
523 return msg_size;
524}
525
526/**
527 * Function called to send a peer no answer message to the client.
528 * "buf" will be NULL and "size" zero if the socket was closed for writing in
529 * the meantime.
530 *
531 * @param cls closure, NULL
532 * @param size number of bytes available in buf
533 * @param buf where the callee should write the peer no answer message
534 * @return number of bytes written to buf
535 */
536static size_t
537transmit_server_no_answer_message (void *cls, size_t size, void *buf)
538{
539 struct ServerClientNoAnswerMessage *msg;
540 size_t msg_size;
541
542 msg_size = sizeof (struct ServerClientNoAnswerMessage);
543
544 GNUNET_assert (size >= msg_size);
545
546 msg = (struct ServerClientNoAnswerMessage *) buf;
547 msg->header.size = htons (msg_size);
548 msg->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_SC_NO_ANSWER);
549
550 return msg_size;
551}
552
553/**
554 * Function called to send a error message to the client.
555 * "buf" will be NULL and "size" zero if the socket was closed for writing in
556 * the meantime.
557 *
558 * @param cls closure, NULL
559 * @param size number of bytes available in buf
560 * @param buf where the callee should write the error message
561 * @return number of bytes written to buf
562 */
563static size_t
564transmit_server_error_message (void *cls, size_t size, void *buf)
565{
566 struct ServerClientErrorMessage *msg;
567 size_t msg_size;
568
569 msg_size = sizeof (struct ServerClientErrorMessage);
570
571 GNUNET_assert (size >= msg_size);
572
573 msg = (struct ServerClientErrorMessage *) buf;
574 msg->header.size = htons (msg_size);
575 msg->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_SC_ERROR);
576
577 return msg_size;
578}
579
580/******************************************************************************/
581/*********************** RECEIVE FUNCTIONS CL -> SERVER ********************/
582/******************************************************************************/
583
584/**
585 * Function to handle a session initiate message from the client
586 *
587 * @param cls closure, NULL
588 * @param client the client from which the message is
589 * @param message the message from the client
590*/
591static void
592handle_session_initiate_message (void *cls,
593 struct GNUNET_SERVER_Client *client,
594 const struct GNUNET_MessageHeader *message)
595{
596 static uint32_t port = 50002;
597 size_t msg_size;
598 struct ClientServerSessionInitiateMessage *msg =
599 (struct ClientServerSessionInitiateMessage *) message;
600 struct GNUNET_PeerIdentity *peer = &(msg->peer);
601
602 GNUNET_SERVER_receive_done (client, GNUNET_OK);
603
604 if (NULL != connection.client)
605 {
606 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
607 _("There is already a peer in interaction\n"));
608 GNUNET_SERVER_notify_transmit_ready (client,
609 sizeof (struct
610 ServerClientServiceBlockedMessage),
611 MAX_TRANSMIT_DELAY,
612 &transmit_server_service_blocked_message,
613 NULL);
614
615 return;
616 }
617
618 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Creating tunnel to: %s\n"),
619 GNUNET_i2s_full (peer));
620 tunnel_reliable =
621 GNUNET_MESH_tunnel_create (mesh, NULL, peer, port, GNUNET_NO, GNUNET_NO);
622 if (NULL == tunnel_reliable)
623 {
624 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
625 _("Could not create reliable tunnel\n"));
626 GNUNET_SERVER_notify_transmit_ready (client,
627 sizeof (struct
628 ServerClientPeerNotConnectedMessage),
629 MAX_TRANSMIT_DELAY,
630 &transmit_server_peer_not_connected_message,
631 NULL);
632
633 return;
634 }
635
636 msg_size = sizeof (struct MeshSessionInitiateMessage);
637 struct MeshSessionInitiateMessage *message_mesh_initiate =
638 (struct MeshSessionInitiateMessage *) GNUNET_malloc (msg_size);
639
640 if (NULL == message_mesh_initiate)
641 {
642 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
643 _("Could not create MeshSessionInitiateMessage\n"));
644 GNUNET_MESH_tunnel_destroy (tunnel_reliable);
645 tunnel_reliable = NULL;
646 GNUNET_SERVER_notify_transmit_ready (client,
647 sizeof (struct
648 ServerClientErrorMessage),
649 MAX_TRANSMIT_DELAY,
650 &transmit_server_error_message,
651 NULL);
652
653 return;
654 }
655
656 message_mesh_initiate->header.size = htons (msg_size);
657 message_mesh_initiate->header.type =
658 htons (GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_SESSION_INITIATE);
659
660 if (NULL ==
661 GNUNET_MESH_notify_transmit_ready (tunnel_reliable, 0,
662 MAX_TRANSMIT_DELAY, msg_size,
663 &transmit_mesh_message,
664 (void *) message_mesh_initiate))
665 {
666 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
667 _("Could not queue MeshSessionInitiateMessage\n"));
668 GNUNET_MESH_tunnel_destroy (tunnel_reliable);
669 tunnel_reliable = NULL;
670 GNUNET_free (message_mesh_initiate);
671 GNUNET_SERVER_notify_transmit_ready (client,
672 sizeof (struct
673 ServerClientErrorMessage),
674 MAX_TRANSMIT_DELAY,
675 &transmit_server_error_message,
676 NULL);
677
678 return;
679 }
680
681 connection.status = CALLER;
682 connection.client = client;
683 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Changed connection status to %d\n"),
684 connection.status);
685 memcpy (&(connection.peer), peer, sizeof (struct GNUNET_PeerIdentity));
686
687 return;
688}
689
690/**
691 * Function to handle a session accept message from the client
692 *
693 * @param cls closure, NULL
694 * @param client the client from which the message is
695 * @param message the message from the client
696*/
697static void
698handle_session_accept_message (void *cls, struct GNUNET_SERVER_Client *client,
699 const struct GNUNET_MessageHeader *message)
700{
701 size_t msg_size;
702
703 GNUNET_SERVER_receive_done (client, GNUNET_OK);
704
705 if (connection.status != CALLEE)
706 {
707 // TODO send illegal command
708 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
709 _
710 ("handle_session_accept_message called when not allowed\n"));
711 return;
712 }
713
714 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Accepting the call of: %s\n"),
715 GNUNET_i2s_full (&(connection.peer)));
716
717 msg_size = sizeof (struct MeshSessionAcceptMessage);
718 struct MeshSessionAcceptMessage *message_mesh_accept =
719 (struct MeshSessionAcceptMessage *) GNUNET_malloc (msg_size);
720
721 if (NULL == message_mesh_accept)
722 {
723 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
724 _("Could not create MeshSessionAcceptMessage\n"));
725 return;
726 }
727
728 message_mesh_accept->header.size = htons (msg_size);
729 message_mesh_accept->header.type =
730 htons (GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_SESSION_ACCEPT);
731
732 if (NULL ==
733 GNUNET_MESH_notify_transmit_ready (tunnel_reliable, 0,
734 MAX_TRANSMIT_DELAY, msg_size,
735 &transmit_mesh_message,
736 (void *) message_mesh_accept))
737 {
738 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
739 _("Could not queue MeshSessionAcceptMessage\n"));
740 GNUNET_free (message_mesh_accept);
741 return;
742 }
743
744 connection.status = CONNECTED;
745 connection.client = client;
746 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Changed connection status to %d\n"),
747 connection.status);
748
749 return;
750}
751
752/**
753 * Function to handle a session reject message from the client
754 *
755 * @param cls closure, NULL
756 * @param client the client from which the message is
757 * @param message the message from the client
758*/
759static void
760handle_session_reject_message (void *cls, struct GNUNET_SERVER_Client *client,
761 const struct GNUNET_MessageHeader *message)
762{
763 struct ClientServerSessionRejectMessage *message_received;
764
765 GNUNET_SERVER_receive_done (client, GNUNET_OK);
766
767 if (connection.status != CALLEE)
768 {
769 // TODO send illegal command
770 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
771 _
772 ("handle_session_reject_message called when not allowed\n"));
773 return;
774 }
775
776 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Rejecting the call of: %s\n"),
777 GNUNET_i2s_full (&(connection.peer)));
778 message_received = (struct ClientServerSessionRejectMessage *) message;
779 reject_call (tunnel_reliable, ntohs (message_received->reason));
780
781 return;
782}
783
784/**
785 * Function to handle a session terminate message from the client
786 *
787 * @param cls closure, NULL
788 * @param client the client from which the message is
789 * @param message the message from the client
790*/
791static void
792handle_session_terminate_message (void *cls,
793 struct GNUNET_SERVER_Client *client,
794 const struct GNUNET_MessageHeader *message)
795{
796 GNUNET_SERVER_receive_done (client, GNUNET_OK);
797
798 if (connection.client == NULL || connection.status == CALLEE)
799 {
800 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
801 _
802 ("handle_session_terminate_message called when not allowed\n"));
803 return;
804 }
805
806 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Terminating the call with: %s\n"),
807 GNUNET_i2s_full (&(connection.peer)));
808 terminate_call ();
809}
810
811/******************************************************************************/
812/*********************** SENDING FUNCTIONS MESH *******************/
813/******************************************************************************/
814
815/**
816* Transmit a mesh message
817 * @param cls closure, NULL
818 * @param size number of bytes available in buf
819 * @param buf where the callee should write the message
820 * @return number of bytes written to buf
821 */
822static size_t
823transmit_mesh_message (void *cls, size_t size, void *buf)
824{
825 struct VoIPMeshMessageHeader *msg_header =
826 (struct VoIPMeshMessageHeader *) cls;
827 msg_header->SequenceNumber = SequenceNumber += 1;
828 msg_header->time = GNUNET_TIME_absolute_get ();
829
830 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transmitting message over mesh\n"));
831
832 memcpy (buf, cls, size);
833 // Check if this is correct
834
835
836 if ((GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_SESSION_TERMINATE ==
837 ntohs (msg_header->header.type))
838 || (GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_SESSION_REJECT ==
839 ntohs (msg_header->header.type)))
840 {
841 status_to_listen ();
842 }
843 else if (GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_SESSION_INITIATE ==
844 ntohs (msg_header->header.type))
845 {
846 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Starting timeout task.\n"));
847 timeout_task =
848 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
849 (GNUNET_TIME_UNIT_SECONDS, 30),
850 &check_timeout, NULL);
851 }
852
853 GNUNET_free (cls);
854
855 return size;
856}
857
858/**
859* Transmit a audo message over mesh
860 * @param cls closure, NULL
861 * @param size number of bytes available in buf
862 * @param buf where the callee should write the message
863 * @return number of bytes written to buf
864 */
865static size_t
866transmit_mesh_audio_message (void *cls, size_t size, void *buf)
867{
868 struct AudioMessage *message = (struct AudioMessage *) cls;
869
870 if (size < sizeof (struct AudioMessage) || NULL == buf)
871 {
872 GNUNET_break (0);
873 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
874 "size %u, buf %p, data_sent %u, data_received %u\n",
875 size, buf, data_sent, data_received);
876 return 0;
877 }
878
879 memcpy (buf, message, size);
880
881 data_sent++;
882 data_sent_size += size;
883
884 GNUNET_log (GNUNET_ERROR_TYPE_INFO, " Sent packet %d\n", data_sent);
885
886 audio_task = GNUNET_SCHEDULER_add_now (&transmit_audio_task, NULL);
887
888 return size;
889}
890
891/**
892 * Task to schedule a audio transmission.
893 *
894 * @param cls Closure.
895 * @param tc Task Context.
896 */
897static void
898transmit_audio_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
899{
900 struct GNUNET_CONTAINER_SList_Iterator iterator;
901 struct AudioMessage *msg;
902 int ab_length = GNUNET_CONTAINER_slist_count (audio_buffer);
903
904 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "We have %d packets.\n", ab_length);
905
906 if (NULL == cls)
907 {
908 if (0 == ab_length && CONNECTED == connection.status)
909 {
910 audio_task =
911 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
912 (GNUNET_TIME_UNIT_MILLISECONDS, 10),
913 &transmit_audio_task, NULL);
914 return;
915 }
916
917 iterator = GNUNET_CONTAINER_slist_begin (audio_buffer);
918 msg =
919 (struct AudioMessage *) GNUNET_CONTAINER_slist_get (&iterator, NULL);
920 msg->SequenceNumber = SequenceNumber += 1;
921 msg->time = GNUNET_TIME_absolute_get ();
922
923 GNUNET_CONTAINER_slist_erase (&iterator);
924 GNUNET_CONTAINER_slist_iter_destroy (&iterator);
925 }
926 else
927 {
928 msg = (struct AudioMessage *) cls;
929 }
930
931 if (NULL == tunnel_unreliable)
932 {
933 GNUNET_CONTAINER_slist_clear (audio_buffer);
934 return;
935 }
936
937 mth = GNUNET_MESH_notify_transmit_ready (tunnel_unreliable, GNUNET_NO,
938 MAX_TRANSMIT_DELAY,
939 sizeof (struct AudioMessage),
940 &transmit_mesh_audio_message,
941 (void *) msg);
942
943 if (NULL == mth)
944 {
945 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
946 "Need to retransmit audio packet\n");
947 GNUNET_log (GNUNET_ERROR_TYPE_INFO, " in 1 ms\n");
948 audio_task =
949 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS,
950 &transmit_audio_task, (void *) msg);
951 }
952}
953
954/******************************************************************************/
955/*********************** RECEIVE FUNCTIONS MESH ********************/
956/******************************************************************************/
957
958/**
959* Function to handle a initiation messaage incoming over mesh
960 * @param cls closure, NULL
961 * @param tunnel the tunnel over which the message arrived
962 * @pram tunnel_ctx the tunnel context, can be NULL
963 * @pram message the incoming message
964 *
965 * @return GNUNET_OK
966*/
967int
968handle_mesh_initiate_message (void *cls, struct GNUNET_MESH_Tunnel *tunnel,
969 void **tunnel_ctx,
970 const struct GNUNET_MessageHeader *message)
971{
972 int reject_reason;
973 //struct GNUNET_PeerIdentity *peer = (GNUNET_MESH_tunnel_get_info(tunnel, GNUNET_MESH_OPTION_PEER))->peer;
974 const struct GNUNET_PeerIdentity *peer =
975 GNUNET_PEER_resolve2 (tunnel->peer);
976
977 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
978 _("Handling MeshSessionInitiateMessage from peer: %s\n"),
979 GNUNET_i2s_full (peer));
980 GNUNET_MESH_receive_done (tunnel);
981
982 if (LISTEN != connection.status
983 || 1 > GNUNET_CONTAINER_slist_count (clients))
984 {
985
986 if (CONNECTED == connection.status)
987 {
988 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
989 _
990 ("Rejected call from %s because there is an active call"),
991 GNUNET_i2s_full (peer));
992 reject_reason = htons (REJECT_REASON_ACTIVE_CALL);
993
994 // Notifying client about missed call
995 size_t msg_size =
996 sizeof (struct ServerClientMissedCallMessage) +
997 sizeof (struct MissedCall);
998 struct ServerClientMissedCallMessage *message =
999 GNUNET_malloc (msg_size);
1000
1001 message->header.size = htons (msg_size);
1002 message->header.type =
1003 htons (GNUNET_MESSAGE_TYPE_CONVERSATION_SC_MISSED_CALL);
1004 message->number = 1;
1005
1006 memcpy (&(message->missed_call->peer), peer,
1007 sizeof (struct GNUNET_PeerIdentity));
1008 message->missed_call->time = GNUNET_TIME_absolute_get ();
1009
1010 if (NULL ==
1011 GNUNET_SERVER_notify_transmit_ready (connection.client,
1012 sizeof (struct
1013 ServerClientMissedCallMessage),
1014 MAX_TRANSMIT_DELAY,
1015 &transmit_server_missed_call_message,
1016 (void *) message))
1017 {
1018 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1019 _
1020 ("Could not queue ServerClientMissedCallMessage\n"));
1021 GNUNET_free (message);
1022 }
1023 }
1024
1025 if (1 > GNUNET_CONTAINER_slist_count (clients))
1026 {
1027 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1028 _("Got a call from %s while no client connected.\n"),
1029 GNUNET_i2s_full (peer));
1030 reject_reason = htons (REJECT_REASON_NO_CLIENT);
1031 // Store missed calls
1032 struct MissedCall call;
1033 memcpy (&(call.peer), peer, sizeof (struct GNUNET_PeerIdentity));
1034 call.time = GNUNET_TIME_absolute_get ();
1035 GNUNET_CONTAINER_slist_add_end (missed_calls,
1036 GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
1037 &call, sizeof (struct MissedCall));
1038
1039 }
1040
1041 reject_call (tunnel, reject_reason);
1042 }
1043 else
1044 {
1045 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Initiated call from: %s\n"),
1046 GNUNET_i2s_full (peer));
1047 tunnel_reliable = tunnel;
1048 connection.status = CALLEE;
1049 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1050 _("Changed connection status to %d\n"), connection.status);
1051 memcpy (&(connection.peer), peer, sizeof (struct GNUNET_PeerIdentity));
1052
1053 struct GNUNET_CONTAINER_SList_Iterator iterator =
1054 GNUNET_CONTAINER_slist_begin (clients);
1055 do
1056 {
1057 struct VoipClient *conversation_client =
1058 (struct VoipClient *) GNUNET_CONTAINER_slist_get (&iterator,
1059 NULL);
1060 struct GNUNET_SERVER_Client *client = conversation_client->client;
1061 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Client found: %p\n"),
1062 client);
1063
1064 if (NULL ==
1065 GNUNET_SERVER_notify_transmit_ready (client,
1066 sizeof (struct
1067 ServerClientSessionInitiateMessage),
1068 MAX_TRANSMIT_DELAY,
1069 &transmit_server_initiate_message,
1070 (void *) peer))
1071 {
1072 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1073 _
1074 ("Could not queue ServerClientSessionInitiateMessage\n"));
1075 }
1076
1077 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Client notified.\n"));
1078 }
1079 while (GNUNET_OK == GNUNET_CONTAINER_slist_next (&iterator));
1080
1081 GNUNET_CONTAINER_slist_iter_destroy (&iterator);
1082
1083 }
1084
1085 return GNUNET_OK;
1086}
1087
1088/**
1089* Function to handle an accept messaage incoming over mesh
1090 * @param cls closure, NULL
1091 * @param tunnel the tunnel over which the message arrived
1092 * @pram tunnel_ctx the tunnel context, can be NULL
1093 * @pram message the incoming message
1094 *
1095 * @return GNUNET_OK
1096*/
1097int
1098handle_mesh_accept_message (void *cls, struct GNUNET_MESH_Tunnel *tunnel,
1099 void **tunnel_ctx,
1100 const struct GNUNET_MessageHeader *message)
1101{
1102 static uint32_t port = 50003;
1103 //struct GNUNET_PeerIdentity *peer = (GNUNET_MESH_tunnel_get_info(tunnel, GNUNET_MESH_OPTION_PEER))->peer;
1104 const struct GNUNET_PeerIdentity *peer =
1105 GNUNET_PEER_resolve2 (tunnel->peer);
1106
1107 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1108 _
1109 ("Handling MeshSessionAccpetMessage from peer: %s (connection.peer: %s)\n"),
1110 GNUNET_i2s_full (peer), GNUNET_i2s_full (&(connection.peer)));
1111 GNUNET_MESH_receive_done (tunnel);
1112
1113 if (0 ==
1114 memcmp (peer, &(connection.peer), sizeof (struct GNUNET_PeerIdentity))
1115 && connection.status == CALLER)
1116 {
1117 tunnel_unreliable =
1118 GNUNET_MESH_tunnel_create (mesh, NULL, peer, port, GNUNET_NO,
1119 GNUNET_NO);
1120 if (NULL == tunnel_unreliable)
1121 {
1122 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1123 _("Could not create unreliable tunnel\n"));
1124
1125 status_to_listen ();
1126
1127 GNUNET_SERVER_notify_transmit_ready (connection.client,
1128 sizeof (struct
1129 ServerClientSessionRejectMessage),
1130 MAX_TRANSMIT_DELAY,
1131 &transmit_server_reject_message,
1132 NULL);
1133 return GNUNET_SYSERR;
1134 }
1135
1136 if (timeout_task != GNUNET_SCHEDULER_NO_TASK)
1137 {
1138 GNUNET_SCHEDULER_cancel (timeout_task);
1139 timeout_task = GNUNET_SCHEDULER_NO_TASK;
1140 }
1141
1142 connection.status = CONNECTED;
1143 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1144 _("Changed connection status to %d\n"), connection.status);
1145
1146 if (NULL ==
1147 GNUNET_SERVER_notify_transmit_ready (connection.client,
1148 sizeof (struct
1149 ServerClientSessionAcceptMessage),
1150 MAX_TRANSMIT_DELAY,
1151 &transmit_server_accept_message,
1152 (void *) message))
1153 {
1154 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1155 _
1156 ("Could not queue ServerClientSessionAcceptMessage\n"));
1157 return GNUNET_SYSERR;
1158 }
1159
1160 start_time = GNUNET_TIME_absolute_get ();
1161 start_helpers ();
1162 audio_task = GNUNET_SCHEDULER_add_now (&transmit_audio_task, NULL);
1163 }
1164
1165 return GNUNET_OK;
1166}
1167
1168/**
1169* Function to handle a reject messaage incoming over mesh
1170 * @param cls closure, NULL
1171 * @param tunnel the tunnel over which the message arrived
1172 * @pram tunnel_ctx the tunnel context, can be NULL
1173 * @pram message the incoming message
1174 *
1175 * @return GNUNET_OK
1176*/
1177int
1178handle_mesh_reject_message (void *cls, struct GNUNET_MESH_Tunnel *tunnel,
1179 void **tunnel_ctx,
1180 const struct GNUNET_MessageHeader *message)
1181{
1182 //struct GNUNET_PeerIdentity *peer = (GNUNET_MESH_tunnel_get_info(tunnel, GNUNET_MESH_OPTION_PEER))->peer;
1183 const struct GNUNET_PeerIdentity *peer =
1184 GNUNET_PEER_resolve2 (tunnel->peer);
1185
1186 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1187 _
1188 ("Handling MeshSessionRejectMessage from peer: %s (connection.peer: %s)\n"),
1189 GNUNET_i2s_full (peer), GNUNET_i2s_full (&(connection.peer)));
1190 GNUNET_MESH_receive_done (tunnel);
1191
1192 if (0 ==
1193 memcmp (peer, &(connection.peer), sizeof (struct GNUNET_PeerIdentity))
1194 && connection.status == CALLER)
1195 {
1196 if (NULL ==
1197 GNUNET_SERVER_notify_transmit_ready (connection.client,
1198 sizeof (struct
1199 ServerClientSessionRejectMessage),
1200 MAX_TRANSMIT_DELAY,
1201 &transmit_server_reject_message,
1202 (void *) message))
1203 {
1204 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1205 _
1206 ("Could not queue ServerClientSessionRejectMessage\n"));
1207 }
1208
1209 status_to_listen ();
1210
1211 if (NULL != tunnel_reliable)
1212 {
1213 GNUNET_MESH_tunnel_destroy (tunnel_reliable);
1214 tunnel_reliable = NULL;
1215 }
1216 }
1217
1218 return GNUNET_OK;
1219}
1220
1221/**
1222* Function to handle a terminate messaage incoming over mesh
1223 * @param cls closure, NULL
1224 * @param tunnel the tunnel over which the message arrived
1225 * @pram tunnel_ctx the tunnel context, can be NULL
1226 * @pram message the incoming message
1227 *
1228 * @return GNUNET_OK
1229*/
1230int
1231handle_mesh_terminate_message (void *cls, struct GNUNET_MESH_Tunnel *tunnel,
1232 void **tunnel_ctx,
1233 const struct GNUNET_MessageHeader *message)
1234{
1235 //struct GNUNET_PeerIdentity *peer = (GNUNET_MESH_tunnel_get_info(tunnel, GNUNET_MESH_OPTION_PEER))->peer;
1236 const struct GNUNET_PeerIdentity *peer =
1237 GNUNET_PEER_resolve2 (tunnel->peer);
1238
1239 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1240 _
1241 ("Handling MeshSessionTerminateMessage from peer: %s (connection.peer: %s)\n"),
1242 GNUNET_i2s_full (peer), GNUNET_i2s_full (&(connection.peer)));
1243 GNUNET_MESH_receive_done (tunnel);
1244
1245 if (!memcmp (peer, &(connection.peer), sizeof (struct GNUNET_PeerIdentity))
1246 && (connection.status == CONNECTED || connection.status == CALLEE))
1247 {
1248 status_to_listen ();
1249
1250 if (NULL != tunnel_unreliable)
1251 {
1252 GNUNET_MESH_tunnel_destroy (tunnel_unreliable);
1253 tunnel_unreliable = NULL;
1254 }
1255
1256 if (NULL != tunnel_reliable)
1257 {
1258 GNUNET_MESH_tunnel_destroy (tunnel_reliable);
1259 tunnel_reliable = NULL;
1260 }
1261 }
1262
1263 return GNUNET_OK;
1264}
1265
1266/**
1267* Function to handle a audio messaage incoming over mesh
1268 * @param cls closure, NULL
1269 * @param tunnel the tunnel over which the message arrived
1270 * @pram tunnel_ctx the tunnel context, can be NULL
1271 * @pram message the incoming message
1272 *
1273 * @return GNUNET_OK
1274*/
1275int
1276handle_mesh_audio_message (void *cls, struct GNUNET_MESH_Tunnel *tunnel,
1277 void **tunnel_ctx,
1278 const struct GNUNET_MessageHeader *message)
1279{
1280
1281 GNUNET_MESH_receive_done (tunnel);
1282
1283 if (CONNECTED != connection.status)
1284 return GNUNET_OK;
1285
1286
1287 struct AudioMessage *audio;
1288 size_t msg_size;
1289 msg_size = sizeof (struct AudioMessage);
1290
1291 audio = (struct AudioMessage *) message;
1292
1293 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "[RECV] %dbytes\n", audio->length);
1294
1295 if (NULL == playback_helper)
1296 return GNUNET_OK;
1297
1298 (void) GNUNET_HELPER_send (playback_helper,
1299 message, GNUNET_YES, NULL, NULL);
1300
1301 data_received++;
1302 data_received_size += msg_size;
1303
1304 return GNUNET_OK;
1305}
1306
1307/******************************************************************************/
1308/*********************** HELPER *******************/
1309/******************************************************************************/
1310
1311/**
1312* Function to process the audio from the record helper
1313 * @param cls closure, NULL
1314 * @param client NULL
1315 * @param msg the message from the helper
1316 *
1317 * @return GNUNET_OK
1318*/
1319static int
1320process_record_messages (void *cls GNUNET_UNUSED, void *client,
1321 const struct GNUNET_MessageHeader *msg)
1322{
1323 size_t msg_size;
1324 struct AudioMessage *message = (struct AudioMessage *) msg;
1325 msg_size = sizeof (struct AudioMessage);
1326
1327 GNUNET_log (GNUNET_ERROR_TYPE_INFO, " [REC] %dbyte\n", message->length);
1328 GNUNET_CONTAINER_slist_add_end (audio_buffer,
1329 GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
1330 message, msg_size);
1331
1332 return GNUNET_OK;
1333}
1334
1335/**
1336* Function to to start the playback helper
1337 *
1338 * @return 0 ok, 1 on error
1339*/
1340int
1341start_playback_helper (void)
1342{
1343 static char *playback_helper_argv[1];
1344 int success = 1;
1345
1346 playback_helper_argv[0] = "gnunet-helper-audio-playback";
1347 playback_helper = GNUNET_HELPER_start (GNUNET_NO,
1348 "gnunet-helper-audio-playback",
1349 playback_helper_argv,
1350 NULL, NULL, NULL);
1351
1352 if (NULL == playback_helper)
1353 {
1354 success = 0;
1355 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1356 _("Could not start playback audio helper.\n"));
1357 }
1358
1359 return success;
1360}
1361
1362/**
1363* Function to to start the record helper
1364 *
1365 * @return 0 ok, 1 on error
1366*/
1367int
1368start_record_helper (void)
1369{
1370 static char *record_helper_argv[1];
1371 int success = 1;
1372
1373 record_helper_argv[0] = "gnunet-helper-audio-record";
1374 record_helper = GNUNET_HELPER_start (GNUNET_NO,
1375 "gnunet-helper-audio-record",
1376 record_helper_argv,
1377 &process_record_messages, NULL, NULL);
1378
1379 if (NULL == record_helper)
1380 {
1381 success = 0;
1382 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1383 _("Could not start record audio helper\n"));
1384 }
1385
1386 return success;
1387}
1388
1389
1390/**
1391* Function to to start both helpers
1392 *
1393 * @return 0 ok, 1 on error
1394*/
1395int
1396start_helpers (void)
1397{
1398
1399 if (0 == start_playback_helper () || 0 == start_record_helper ())
1400 {
1401 stop_helpers ();
1402 return 0;
1403 }
1404
1405 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Started helpers\n"));
1406
1407 return 1;
1408}
1409
1410/**
1411* Function to to stop the playback helper
1412*/
1413void
1414stop_playback_helper (void)
1415{
1416 if (NULL != playback_helper)
1417 {
1418 GNUNET_HELPER_stop (playback_helper, GNUNET_NO);
1419 playback_helper = NULL;
1420
1421 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Stopped playback helper\n"));
1422 }
1423}
1424
1425/**
1426* Function to to stop the record helper
1427*/
1428void
1429stop_record_helper (void)
1430{
1431 if (NULL != record_helper)
1432 {
1433 GNUNET_HELPER_stop (record_helper, GNUNET_NO);
1434 record_helper = NULL;
1435
1436 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Stopped record helper\n"));
1437 }
1438}
1439
1440/**
1441* Function to stop both audio helpers
1442*/
1443void
1444stop_helpers (void)
1445{
1446 stop_playback_helper ();
1447 stop_record_helper ();
1448}
1449
1450/******************************************************************************/
1451/*********************** TUNNEL HANDLING *******************/
1452/******************************************************************************/
1453
1454/**
1455 * Method called whenever another peer has added us to a tunnel
1456 * the other peer initiated.
1457 *
1458 * @param cls closure
1459 * @param tunnel new handle to the tunnel
1460 * @param initiator peer that started the tunnel
1461 * @param port port
1462 * @return initial tunnel context for the tunnel (can be NULL -- that's not an error)
1463 */
1464static void *
1465inbound_tunnel (void *cls, struct GNUNET_MESH_Tunnel *tunnel,
1466 const struct GNUNET_PeerIdentity *initiator, uint32_t port)
1467{
1468 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1469 _("Received incoming tunnel on port %d\n"), port);
1470 if (50003 == port)
1471 {
1472 tunnel_unreliable = tunnel;
1473
1474 start_time = GNUNET_TIME_absolute_get ();
1475
1476 start_helpers ();
1477 audio_task = GNUNET_SCHEDULER_add_now (&transmit_audio_task, NULL);
1478 }
1479
1480 return NULL;
1481}
1482
1483
1484/**
1485 * Function called whenever an inbound tunnel is destroyed. Should clean up
1486 * any associated state.
1487 *
1488 * @param cls closure (set from GNUNET_MESH_connect)
1489 * @param tunnel connection to the other end (henceforth invalid)
1490 * @param tunnel_ctx place where local state associated
1491 * with the tunnel is stored
1492 */
1493static void
1494inbound_end (void *cls, const struct GNUNET_MESH_Tunnel *tunnel,
1495 void *tunnel_ctx)
1496{
1497 if (tunnel == tunnel_unreliable)
1498 {
1499 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Tunnel closed: audio\n");
1500
1501 stop_helpers ();
1502 tunnel_unreliable = NULL;
1503 }
1504
1505 if (tunnel == tunnel_reliable)
1506 {
1507 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Tunnel closed: control\n");
1508
1509 if (LISTEN != connection.status && NULL != connection.client)
1510 {
1511 if (NULL ==
1512 GNUNET_SERVER_notify_transmit_ready (connection.client,
1513 sizeof (struct
1514 ServerClientSessionTerminateMessage),
1515 MAX_TRANSMIT_DELAY,
1516 &transmit_server_terminate_message,
1517 NULL))
1518 {
1519 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1520 _
1521 ("Could not queue ServerClientSessionTerminateMessage\n"));
1522 }
1523 }
1524
1525 status_to_listen ();
1526 }
1527}
1528
1529/******************************************************************************/
1530/*********************** CLIENT HANDLING *******************/
1531/******************************************************************************/
1532
1533/**
1534 * A client connected.
1535 *
1536 * @param cls closure, NULL
1537 * @param client identification of the client
1538 */
1539
1540static void
1541handle_client_connect (void *cls, struct GNUNET_SERVER_Client *cl)
1542{
1543 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client connected\n");
1544 struct ServerClientMissedCallMessage *message;
1545 size_t msg_size;
1546 struct VoipClient c;
1547 c.client = cl;
1548
1549 GNUNET_CONTAINER_slist_add_end (clients,
1550 GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
1551 &c, sizeof (struct VoipClient));
1552 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Client added: %p\n"), cl);
1553
1554 if (0 < GNUNET_CONTAINER_slist_count (missed_calls))
1555 {
1556 int i = 0;
1557 msg_size =
1558 sizeof (struct ServerClientMissedCallMessage) +
1559 GNUNET_CONTAINER_slist_count (missed_calls) *
1560 sizeof (struct MissedCall);
1561 message =
1562 (struct ServerClientMissedCallMessage *) GNUNET_malloc (msg_size);
1563
1564 message->header.size = htons (msg_size);
1565 message->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_SC_MISSED_CALL);
1566 message->number = GNUNET_CONTAINER_slist_count (missed_calls);
1567
1568 struct GNUNET_CONTAINER_SList_Iterator iterator =
1569 GNUNET_CONTAINER_slist_begin (missed_calls);
1570 do
1571 {
1572 memcpy (&(message->missed_call[i]),
1573 GNUNET_CONTAINER_slist_get (&iterator, NULL),
1574 sizeof (struct MissedCall));
1575 i++;
1576 }
1577 while (GNUNET_OK == GNUNET_CONTAINER_slist_next (&iterator));
1578
1579 GNUNET_CONTAINER_slist_iter_destroy (&iterator);
1580 GNUNET_CONTAINER_slist_clear (missed_calls);
1581
1582
1583 if (NULL ==
1584 GNUNET_SERVER_notify_transmit_ready (cl, msg_size,
1585 MAX_TRANSMIT_DELAY,
1586 &transmit_server_missed_call_message,
1587 (void *) message))
1588 {
1589 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1590 _("Could not queue ServerClientMissedCallMessage\n"));
1591 GNUNET_free (message);
1592 }
1593 }
1594
1595 return;
1596}
1597
1598/**
1599 * A client disconnected. Remove all of its data structure entries.
1600 *
1601 * @param cls closure, NULL
1602 * @param client identification of the client
1603 */
1604static void
1605handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *cl)
1606{
1607 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client disconnected\n");
1608
1609 if (connection.client == cl)
1610 {
1611 if (CONNECTED == connection.status)
1612 {
1613 terminate_call ();
1614 }
1615 else
1616 {
1617 status_to_listen ();
1618 }
1619 }
1620
1621 struct GNUNET_CONTAINER_SList_Iterator iterator =
1622 GNUNET_CONTAINER_slist_begin (clients);
1623 do
1624 {
1625 if (((struct VoipClient *)
1626 GNUNET_CONTAINER_slist_get (&iterator, NULL))->client == cl)
1627 {
1628 GNUNET_CONTAINER_slist_erase (&iterator);
1629 }
1630 }
1631 while (GNUNET_OK == GNUNET_CONTAINER_slist_next (&iterator));
1632
1633 GNUNET_CONTAINER_slist_iter_destroy (&iterator);
1634
1635 return;
1636}
1637
1638/******************************************************************************/
1639/*********************** SERVICE *******************/
1640/******************************************************************************/
1641
1642/**
1643 * Shutdown nicely
1644 *
1645 * @param cls closure, NULL
1646 * @param tc the task context
1647 */
1648static void
1649do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1650{
1651 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Shutdown\n");
1652
1653 stop_helpers ();
1654
1655 if (NULL != tunnel_reliable)
1656 {
1657 GNUNET_MESH_tunnel_destroy (tunnel_reliable);
1658 }
1659
1660 if (NULL != tunnel_unreliable)
1661 {
1662 GNUNET_MESH_tunnel_destroy (tunnel_unreliable);
1663 }
1664
1665 if (NULL != mesh)
1666 {
1667 GNUNET_MESH_disconnect (mesh);
1668 }
1669
1670 if (NULL != nc)
1671 {
1672 GNUNET_SERVER_notification_context_destroy (nc);
1673 nc = NULL;
1674 }
1675
1676 GNUNET_CONTAINER_slist_destroy (audio_buffer);
1677 GNUNET_CONTAINER_slist_destroy (clients);
1678 GNUNET_CONTAINER_slist_destroy (missed_calls);
1679 GNUNET_CONTAINER_slist_destroy (peers_to_notify);
1680}
1681
1682
1683/**
1684 * Handler array for traffic received
1685 */
1686static struct GNUNET_MESH_MessageHandler mesh_handlers[] = {
1687 {&handle_mesh_initiate_message,
1688 GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_SESSION_INITIATE,
1689 sizeof (struct MeshSessionInitiateMessage)},
1690 {&handle_mesh_accept_message, GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_SESSION_ACCEPT,
1691 sizeof (struct MeshSessionAcceptMessage)},
1692 {&handle_mesh_reject_message, GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_SESSION_REJECT,
1693 sizeof (struct MeshSessionRejectMessage)},
1694 {&handle_mesh_terminate_message,
1695 GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_SESSION_TERMINATE,
1696 sizeof (struct MeshSessionTerminateMessage)},
1697 {&handle_mesh_audio_message, GNUNET_MESSAGE_TYPE_CONVERSATION_AUDIO,
1698 sizeof (struct AudioMessage)},
1699 {NULL, 0, 0}
1700};
1701
1702/**
1703 * Main function that will be run by the scheduler.
1704 *
1705 * @param cls closure
1706 * @param server server handle
1707 * @param c configuration
1708 */
1709static void
1710run (void *cls, struct GNUNET_SERVER_Handle *server,
1711 const struct GNUNET_CONFIGURATION_Handle *c)
1712{
1713
1714 static uint32_t ports[] = { 50002, 50003, NULL };
1715 cfg = c;
1716
1717 mesh = GNUNET_MESH_connect (cfg,
1718 NULL,
1719 &inbound_tunnel,
1720 &inbound_end, mesh_handlers, ports);
1721
1722 if (NULL == mesh)
1723 {
1724 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Couldn't connect to mesh\n");
1725 return;
1726 }
1727 else
1728 {
1729 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Connected to mesh\n");
1730 }
1731
1732 static const struct GNUNET_SERVER_MessageHandler server_handlers[] = {
1733 {&handle_session_initiate_message, NULL,
1734 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_SESSION_INITIATE,
1735 sizeof (struct ClientServerSessionInitiateMessage)},
1736 {&handle_session_accept_message, NULL,
1737 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_SESSION_ACCEPT,
1738 sizeof (struct ClientServerSessionAcceptMessage)},
1739 {&handle_session_reject_message, NULL,
1740 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_SESSION_REJECT,
1741 sizeof (struct ClientServerSessionRejectMessage)},
1742 {&handle_session_terminate_message, NULL,
1743 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_SESSION_TERMINATE,
1744 sizeof (struct ClientServerSessionTerminateMessage)},
1745 {NULL, NULL, 0, 0}
1746 };
1747
1748 connection.status = LISTEN;
1749
1750 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Changed connection status to %d\n"),
1751 connection.status);
1752
1753 nc = GNUNET_SERVER_notification_context_create (server, 16);
1754
1755 GNUNET_SERVER_add_handlers (server, server_handlers);
1756 GNUNET_SERVER_connect_notify (server, &handle_client_connect, NULL);
1757 GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL);
1758 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &do_shutdown,
1759 NULL);
1760
1761 clients = GNUNET_CONTAINER_slist_create ();
1762
1763 // Missed calls
1764 missed_calls = GNUNET_CONTAINER_slist_create ();
1765 peers_to_notify = GNUNET_CONTAINER_slist_create ();
1766 audio_buffer = GNUNET_CONTAINER_slist_create ();
1767
1768 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Voip service running\n"));
1769}
1770
1771/**
1772 * The main function for the conversation service.
1773 *
1774 * @param argc number of arguments from the command line
1775 * @param argv command line arguments
1776 * @return 0 ok, 1 on error
1777 */
1778int
1779main (int argc, char *const *argv)
1780{
1781 return (GNUNET_OK ==
1782 GNUNET_SERVICE_run (argc, argv, "conversation", GNUNET_SERVICE_OPTION_NONE,
1783 &run, NULL)) ? 0 : 1;
1784}
1785
1786/* end of gnunet-service-conversation.c */