aboutsummaryrefslogtreecommitdiff
path: root/src/conversation/gnunet-service-conversation.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/conversation/gnunet-service-conversation.c')
-rw-r--r--src/conversation/gnunet-service-conversation.c1381
1 files changed, 0 insertions, 1381 deletions
diff --git a/src/conversation/gnunet-service-conversation.c b/src/conversation/gnunet-service-conversation.c
deleted file mode 100644
index a69c95a80..000000000
--- a/src/conversation/gnunet-service-conversation.c
+++ /dev/null
@@ -1,1381 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2013, 2016, 2017 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your 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 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file conversation/gnunet-service-conversation.c
22 * @brief conversation service implementation
23 * @author Simon Dieterle
24 * @author Andreas Fuchs
25 * @author Christian Grothoff
26 */
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_protocols.h"
30#include "gnunet_applications.h"
31#include "gnunet_constants.h"
32#include "gnunet_signatures.h"
33#include "gnunet_cadet_service.h"
34#include "gnunet_conversation_service.h"
35#include "conversation.h"
36
37
38/**
39 * How long is our signature on a call valid? Needs to be long enough for time zone
40 * differences and network latency to not matter. No strong need for it to be short,
41 * but we simply like all signatures to eventually expire.
42 */
43#define RING_TIMEOUT GNUNET_TIME_UNIT_DAYS
44
45
46/**
47 * A line connects a local client with a cadet channel (or, if it is an
48 * open line, is waiting for a cadet channel).
49 */
50struct Line;
51
52/**
53 * The possible connection status
54 */
55enum ChannelStatus
56{
57 /**
58 * We just got the connection, but no introduction yet.
59 */
60 CS_CALLEE_INIT,
61
62 /**
63 * Our phone is ringing, waiting for the client to pick up.
64 */
65 CS_CALLEE_RINGING,
66
67 /**
68 * We are talking!
69 */
70 CS_CALLEE_CONNECTED,
71
72 /**
73 * We're in shutdown, sending hangup messages before cleaning up.
74 */
75 CS_CALLEE_SHUTDOWN,
76
77 /**
78 * We are waiting for the phone to be picked up.
79 */
80 CS_CALLER_CALLING,
81
82 /**
83 * We are talking!
84 */
85 CS_CALLER_CONNECTED,
86
87 /**
88 * We're in shutdown, sending hangup messages before cleaning up.
89 */
90 CS_CALLER_SHUTDOWN
91};
92
93
94/**
95 * A `struct Channel` represents a cadet channel, which is a P2P
96 * connection to another conversation service. Multiple channels can
97 * be attached the the same `struct Line`, which represents a local
98 * client. We keep them in a linked list.
99 */
100struct Channel
101{
102 /**
103 * This is a DLL.
104 */
105 struct Channel *next;
106
107 /**
108 * This is a DLL.
109 */
110 struct Channel *prev;
111
112 /**
113 * Line associated with the channel.
114 */
115 struct Line *line;
116
117 /**
118 * Handle for the channel.
119 */
120 struct GNUNET_CADET_Channel *channel;
121
122 /**
123 * Message queue for control messages
124 */
125 struct GNUNET_MQ_Handle *mq;
126
127 /**
128 * Temporary buffer for audio data in the @e mq.
129 */
130 struct GNUNET_MQ_Envelope *env;
131
132 /**
133 * Channel identifier we use for this call with the client.
134 */
135 uint32_t cid;
136
137 /**
138 * Current status of this line.
139 */
140 enum ChannelStatus status;
141
142 /**
143 * #GNUNET_YES if the channel was suspended by the other peer.
144 */
145 int8_t suspended_remote;
146
147 /**
148 * #GNUNET_YES if the channel was suspended by the local client.
149 */
150 int8_t suspended_local;
151};
152
153
154/**
155 * A `struct Line` connects a local client with cadet channels.
156 */
157struct Line
158{
159 /**
160 * This is a DLL.
161 */
162 struct Channel *channel_head;
163
164 /**
165 * This is a DLL.
166 */
167 struct Channel *channel_tail;
168
169 /**
170 * Handle to the line client.
171 */
172 struct GNUNET_SERVICE_Client *client;
173
174 /**
175 * Message queue for @e client.
176 */
177 struct GNUNET_MQ_Handle *mq;
178
179 /**
180 * Our open port.
181 */
182 struct GNUNET_CADET_Port *port;
183
184 /**
185 * Port number we are listening on (to verify signatures).
186 * Only valid if @e port is non-NULL.
187 */
188 struct GNUNET_HashCode line_port;
189
190 /**
191 * Generator for channel IDs.
192 */
193 uint32_t cid_gen;
194};
195
196
197/**
198 * Our configuration.
199 */
200static const struct GNUNET_CONFIGURATION_Handle *cfg;
201
202/**
203 * Handle for cadet
204 */
205static struct GNUNET_CADET_Handle *cadet;
206
207/**
208 * Identity of this peer.
209 */
210static struct GNUNET_PeerIdentity my_identity;
211
212
213/**
214 * Given a @a cid, find the corresponding channel given
215 * a @a line.
216 *
217 * @param line a line to search
218 * @param cid what to search for
219 * @return NULL for not found
220 */
221static struct Channel *
222find_channel_by_line (struct Line *line, uint32_t cid)
223{
224 for (struct Channel *ch = line->channel_head; NULL != ch; ch = ch->next)
225 if (cid == ch->cid)
226 return ch;
227 return NULL;
228}
229
230
231/**
232 * Function to handle a pickup request message from the client
233 *
234 * @param cls the `struct Line` of the client from which the message is
235 * @param msg the message from the client
236 */
237static void
238handle_client_pickup_message (void *cls,
239 const struct ClientPhonePickupMessage *msg)
240{
241 struct Line *line = cls;
242 struct CadetPhonePickupMessage *mppm;
243 struct GNUNET_MQ_Envelope *env;
244 struct Channel *ch;
245
246 if (NULL == line->port)
247 {
248 /* we never opened the port, bad client! */
249 GNUNET_break_op (0);
250 GNUNET_SERVICE_client_drop (line->client);
251 return;
252 }
253 for (ch = line->channel_head; NULL != ch; ch = ch->next)
254 if (msg->cid == ch->cid)
255 break;
256 if (NULL == ch)
257 {
258 /* could have been destroyed asynchronously, ignore message */
259 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Channel %u not found\n", msg->cid);
260 GNUNET_SERVICE_client_continue (line->client);
261 return;
262 }
263 switch (ch->status)
264 {
265 case CS_CALLEE_INIT:
266 GNUNET_break (0);
267 GNUNET_SERVICE_client_drop (line->client);
268 return;
269
270 case CS_CALLEE_RINGING:
271 ch->status = CS_CALLEE_CONNECTED;
272 break;
273
274 case CS_CALLEE_CONNECTED:
275 GNUNET_break (0);
276 GNUNET_SERVICE_client_drop (line->client);
277 return;
278
279 case CS_CALLEE_SHUTDOWN:
280 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
281 "Ignoring client's PICKUP message, line is in SHUTDOWN\n");
282 break;
283
284 case CS_CALLER_CALLING:
285 case CS_CALLER_CONNECTED:
286 case CS_CALLER_SHUTDOWN:
287 GNUNET_break (0);
288 GNUNET_SERVICE_client_drop (line->client);
289 return;
290 }
291 GNUNET_break (CS_CALLEE_CONNECTED == ch->status);
292 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending PICK_UP message to cadet\n");
293 env =
294 GNUNET_MQ_msg (mppm, GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_PICK_UP);
295 GNUNET_MQ_send (ch->mq, env);
296 GNUNET_SERVICE_client_continue (line->client);
297}
298
299
300/**
301 * Channel went down, notify client and free data
302 * structure.
303 *
304 * @param ch channel that went down
305 */
306static void
307clean_up_channel (struct Channel *ch)
308{
309 struct Line *line = ch->line;
310 struct GNUNET_MQ_Envelope *env;
311 struct ClientPhoneHangupMessage *hup;
312
313 switch (ch->status)
314 {
315 case CS_CALLEE_INIT:
316 case CS_CALLEE_SHUTDOWN:
317 case CS_CALLER_SHUTDOWN:
318 break;
319
320 case CS_CALLEE_RINGING:
321 case CS_CALLEE_CONNECTED:
322 case CS_CALLER_CALLING:
323 case CS_CALLER_CONNECTED:
324 if (NULL != line)
325 {
326 env =
327 GNUNET_MQ_msg (hup, GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP);
328 hup->cid = ch->cid;
329 GNUNET_MQ_send (line->mq, env);
330 }
331 break;
332 }
333 if (NULL != line)
334 GNUNET_CONTAINER_DLL_remove (line->channel_head, line->channel_tail, ch);
335 GNUNET_free (ch);
336}
337
338
339/**
340 * Destroy a channel.
341 *
342 * @param ch channel to destroy.
343 */
344static void
345destroy_line_cadet_channels (struct Channel *ch)
346{
347 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Destroying cadet channels\n");
348 if (NULL != ch->channel)
349 {
350 GNUNET_CADET_channel_destroy (ch->channel);
351 ch->channel = NULL;
352 }
353 clean_up_channel (ch);
354}
355
356
357/**
358 * We are done signalling shutdown to the other peer. Close down
359 * the channel.
360 *
361 * @param cls the `struct Channel` to reset/terminate
362 */
363static void
364mq_done_finish_caller_shutdown (void *cls)
365{
366 struct Channel *ch = cls;
367
368 switch (ch->status)
369 {
370 case CS_CALLEE_INIT:
371 GNUNET_break (0);
372 break;
373
374 case CS_CALLEE_RINGING:
375 GNUNET_break (0);
376 break;
377
378 case CS_CALLEE_CONNECTED:
379 GNUNET_break (0);
380 break;
381
382 case CS_CALLEE_SHUTDOWN:
383 destroy_line_cadet_channels (ch);
384 break;
385
386 case CS_CALLER_CALLING:
387 GNUNET_break (0);
388 break;
389
390 case CS_CALLER_CONNECTED:
391 GNUNET_break (0);
392 break;
393
394 case CS_CALLER_SHUTDOWN:
395 destroy_line_cadet_channels (ch);
396 break;
397 }
398}
399
400
401/**
402 * Function to handle a hangup request message from the client
403 *
404 * @param cls the `struct Line` the hangup is for
405 * @param msg the message from the client
406 */
407static void
408handle_client_hangup_message (void *cls,
409 const struct ClientPhoneHangupMessage *msg)
410{
411 struct Line *line = cls;
412 struct GNUNET_MQ_Envelope *e;
413 struct CadetPhoneHangupMessage *mhum;
414 struct Channel *ch;
415
416 for (ch = line->channel_head; NULL != ch; ch = ch->next)
417 if (msg->cid == ch->cid)
418 break;
419 if (NULL == ch)
420 {
421 /* could have been destroyed asynchronously, ignore message */
422 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Channel %u not found\n", msg->cid);
423 GNUNET_SERVICE_client_continue (line->client);
424 return;
425 }
426 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
427 "Received HANGUP for channel %u which is in state %d\n",
428 msg->cid,
429 ch->status);
430 switch (ch->status)
431 {
432 case CS_CALLEE_INIT:
433 GNUNET_break (0);
434 GNUNET_SERVICE_client_drop (line->client);
435 return;
436
437 case CS_CALLEE_RINGING:
438 ch->status = CS_CALLEE_SHUTDOWN;
439 break;
440
441 case CS_CALLEE_CONNECTED:
442 ch->status = CS_CALLEE_SHUTDOWN;
443 break;
444
445 case CS_CALLEE_SHUTDOWN:
446 /* maybe the other peer closed asynchronously... */
447 GNUNET_SERVICE_client_continue (line->client);
448 return;
449
450 case CS_CALLER_CALLING:
451 ch->status = CS_CALLER_SHUTDOWN;
452 break;
453
454 case CS_CALLER_CONNECTED:
455 ch->status = CS_CALLER_SHUTDOWN;
456 break;
457
458 case CS_CALLER_SHUTDOWN:
459 /* maybe the other peer closed asynchronously... */
460 GNUNET_SERVICE_client_continue (line->client);
461 return;
462 }
463 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending HANG_UP message via cadet\n");
464 e =
465 GNUNET_MQ_msg (mhum, GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_HANG_UP);
466 GNUNET_MQ_notify_sent (e, &mq_done_finish_caller_shutdown, ch);
467 GNUNET_MQ_send (ch->mq, e);
468 GNUNET_SERVICE_client_continue (line->client);
469}
470
471
472/**
473 * Function to handle a suspend request message from the client
474 *
475 * @param cls the `struct Line` the message is about
476 * @param msg the message from the client
477 */
478static void
479handle_client_suspend_message (void *cls,
480 const struct ClientPhoneSuspendMessage *msg)
481{
482 struct Line *line = cls;
483 struct GNUNET_MQ_Envelope *e;
484 struct CadetPhoneSuspendMessage *mhum;
485 struct Channel *ch;
486
487 for (ch = line->channel_head; NULL != ch; ch = ch->next)
488 if (msg->cid == ch->cid)
489 break;
490 if (NULL == ch)
491 {
492 /* could have been destroyed asynchronously, ignore message */
493 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Channel %u not found\n", msg->cid);
494 GNUNET_SERVICE_client_continue (line->client);
495 return;
496 }
497 if (GNUNET_YES == ch->suspended_local)
498 {
499 GNUNET_break (0);
500 GNUNET_SERVICE_client_drop (line->client);
501 return;
502 }
503 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
504 "Received SUSPEND for channel %u which is in state %d\n",
505 msg->cid,
506 ch->status);
507 switch (ch->status)
508 {
509 case CS_CALLEE_INIT:
510 GNUNET_break (0);
511 GNUNET_SERVICE_client_drop (line->client);
512 return;
513
514 case CS_CALLEE_RINGING:
515 GNUNET_break (0);
516 GNUNET_SERVICE_client_drop (line->client);
517 return;
518
519 case CS_CALLEE_CONNECTED:
520 ch->suspended_local = GNUNET_YES;
521 break;
522
523 case CS_CALLEE_SHUTDOWN:
524 /* maybe the other peer closed asynchronously... */
525 GNUNET_SERVICE_client_continue (line->client);
526 return;
527
528 case CS_CALLER_CALLING:
529 GNUNET_break (0);
530 GNUNET_SERVICE_client_drop (line->client);
531 return;
532
533 case CS_CALLER_CONNECTED:
534 ch->suspended_local = GNUNET_YES;
535 break;
536
537 case CS_CALLER_SHUTDOWN:
538 /* maybe the other peer closed asynchronously... */
539 GNUNET_SERVICE_client_continue (line->client);
540 return;
541 }
542 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending SUSPEND message via cadet\n");
543 e =
544 GNUNET_MQ_msg (mhum, GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_SUSPEND);
545 GNUNET_MQ_send (ch->mq, e);
546 GNUNET_SERVICE_client_continue (line->client);
547}
548
549
550/**
551 * Function to handle a resume request message from the client
552 *
553 * @param cls the `struct Line` the message is about
554 * @param msg the message from the client
555 */
556static void
557handle_client_resume_message (void *cls,
558 const struct ClientPhoneResumeMessage *msg)
559{
560 struct Line *line = cls;
561 struct GNUNET_MQ_Envelope *e;
562 struct CadetPhoneResumeMessage *mhum;
563 struct Channel *ch;
564
565 for (ch = line->channel_head; NULL != ch; ch = ch->next)
566 if (msg->cid == ch->cid)
567 break;
568 if (NULL == ch)
569 {
570 /* could have been destroyed asynchronously, ignore message */
571 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Channel %u not found\n", msg->cid);
572 GNUNET_SERVICE_client_continue (line->client);
573 return;
574 }
575 if (GNUNET_YES != ch->suspended_local)
576 {
577 GNUNET_break (0);
578 GNUNET_SERVICE_client_drop (line->client);
579 return;
580 }
581 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
582 "Received RESUME for channel %u which is in state %d\n",
583 msg->cid,
584 ch->status);
585 switch (ch->status)
586 {
587 case CS_CALLEE_INIT:
588 GNUNET_break (0);
589 GNUNET_SERVICE_client_drop (line->client);
590 return;
591
592 case CS_CALLEE_RINGING:
593 GNUNET_break (0);
594 GNUNET_SERVICE_client_drop (line->client);
595 return;
596
597 case CS_CALLEE_CONNECTED:
598 ch->suspended_local = GNUNET_NO;
599 break;
600
601 case CS_CALLEE_SHUTDOWN:
602 /* maybe the other peer closed asynchronously... */
603 GNUNET_SERVICE_client_continue (line->client);
604 return;
605
606 case CS_CALLER_CALLING:
607 GNUNET_break (0);
608 GNUNET_SERVICE_client_drop (line->client);
609 return;
610
611 case CS_CALLER_CONNECTED:
612 ch->suspended_local = GNUNET_NO;
613 break;
614
615 case CS_CALLER_SHUTDOWN:
616 /* maybe the other peer closed asynchronously... */
617 GNUNET_SERVICE_client_drop (line->client);
618 return;
619 }
620 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending RESUME message via cadet\n");
621 e = GNUNET_MQ_msg (mhum, GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_RESUME);
622 GNUNET_MQ_send (ch->mq, e);
623 GNUNET_SERVICE_client_continue (line->client);
624}
625
626
627/**
628 * Transmission of audio data via cadet channel finished.
629 *
630 * @param cls the `struct Channel` we are transmitting for
631 */
632static void
633channel_audio_sent_notify (void *cls)
634{
635 struct Channel *ch = cls;
636
637 ch->env = NULL;
638}
639
640
641/**
642 * Function to check audio data from the client
643 *
644 * @param cls the `struct Line` the message is about
645 * @param msg the message from the client
646 * @return #GNUNET_OK (any data is ok)
647 */
648static int
649check_client_audio_message (void *cls, const struct ClientAudioMessage *msg)
650{
651 (void) cls;
652 (void) msg;
653 return GNUNET_OK;
654}
655
656
657/**
658 * Function to handle audio data from the client
659 *
660 * @param cls the `struct Line` the message is about
661 * @param msg the message from the client
662 */
663static void
664handle_client_audio_message (void *cls, const struct ClientAudioMessage *msg)
665{
666 struct Line *line = cls;
667 struct CadetAudioMessage *mam;
668 struct Channel *ch;
669 size_t size;
670
671 size = ntohs (msg->header.size) - sizeof(struct ClientAudioMessage);
672 ch = find_channel_by_line (line, msg->cid);
673 if (NULL == ch)
674 {
675 /* could have been destroyed asynchronously, ignore message */
676 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Channel %u not found\n", msg->cid);
677 GNUNET_SERVICE_client_continue (line->client);
678 return;
679 }
680
681 switch (ch->status)
682 {
683 case CS_CALLEE_INIT:
684 case CS_CALLEE_RINGING:
685 case CS_CALLER_CALLING:
686 GNUNET_break (0);
687 GNUNET_SERVICE_client_drop (line->client);
688 return;
689
690 case CS_CALLEE_CONNECTED:
691 case CS_CALLER_CONNECTED:
692 /* common case, handled below */
693 break;
694
695 case CS_CALLEE_SHUTDOWN:
696 case CS_CALLER_SHUTDOWN:
697 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
698 "Cadet audio channel in shutdown; audio data dropped\n");
699 GNUNET_SERVICE_client_continue (line->client);
700 return;
701 }
702 if (GNUNET_YES == ch->suspended_local)
703 {
704 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
705 "This channel is suspended locally\n");
706 GNUNET_SERVICE_client_drop (line->client);
707 return;
708 }
709 if (NULL != ch->env)
710 {
711 /* NOTE: we may want to not do this and instead combine the data */
712 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
713 "Bandwidth insufficient; dropping previous audio data segment\n");
714 GNUNET_MQ_send_cancel (ch->env);
715 ch->env = NULL;
716 }
717
718 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
719 "Received %u bytes of AUDIO data from client CID %u\n",
720 (unsigned int) size,
721 msg->cid);
722 ch->env = GNUNET_MQ_msg_extra (mam,
723 size,
724 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_AUDIO);
725 GNUNET_memcpy (&mam[1], &msg[1], size);
726 /* FIXME: set options for unreliable transmission */
727 GNUNET_MQ_notify_sent (ch->env, &channel_audio_sent_notify, ch);
728 GNUNET_MQ_send (ch->mq, ch->env);
729 GNUNET_SERVICE_client_continue (line->client);
730}
731
732
733/**
734 * Function to handle a ring message incoming over cadet
735 *
736 * @param cls closure, NULL
737 * @param msg the incoming message
738 */
739static void
740handle_cadet_ring_message (void *cls, const struct CadetPhoneRingMessage *msg)
741{
742 struct Channel *ch = cls;
743 struct Line *line = ch->line;
744 struct GNUNET_MQ_Envelope *env;
745 struct ClientPhoneRingMessage *cring;
746 struct CadetPhoneRingInfoPS rs;
747
748 rs.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CONVERSATION_RING);
749 rs.purpose.size = htonl (sizeof(struct CadetPhoneRingInfoPS));
750 rs.line_port = line->line_port;
751 rs.target_peer = my_identity;
752 rs.expiration_time = msg->expiration_time;
753
754 if (GNUNET_OK !=
755 GNUNET_IDENTITY_signature_verify (
756 GNUNET_SIGNATURE_PURPOSE_CONVERSATION_RING,
757 &rs,
758 &msg->signature,
759 &msg->caller_id))
760 {
761 GNUNET_break_op (0);
762 destroy_line_cadet_channels (ch);
763 return;
764 }
765 if (0 == GNUNET_TIME_absolute_get_remaining (
766 GNUNET_TIME_absolute_ntoh (msg->expiration_time))
767 .rel_value_us)
768 {
769 /* ancient call, replay? */
770 GNUNET_break_op (0);
771 /* Note that our reliance on time here is awkward; better would be
772 to use a more complex challenge-response protocol against
773 replay attacks. Left for future work ;-). */
774 destroy_line_cadet_channels (ch);
775 return;
776 }
777 if (CS_CALLEE_INIT != ch->status)
778 {
779 GNUNET_break_op (0);
780 destroy_line_cadet_channels (ch);
781 return;
782 }
783 GNUNET_CADET_receive_done (ch->channel);
784 ch->status = CS_CALLEE_RINGING;
785 env = GNUNET_MQ_msg (cring, GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RING);
786 cring->cid = ch->cid;
787 cring->caller_id = msg->caller_id;
788 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
789 "Sending RING message to client. CID is %u\n",
790 (unsigned int) ch->cid);
791 GNUNET_MQ_send (line->mq, env);
792}
793
794
795/**
796 * Function to handle a hangup message incoming over cadet
797 *
798 * @param cls closure, our `struct Channel *`
799 * @param message the incoming message
800 */
801static void
802handle_cadet_hangup_message (void *cls,
803 const struct CadetPhoneHangupMessage *message)
804{
805 struct Channel *ch = cls;
806 struct Line *line = ch->line;
807 struct GNUNET_MQ_Envelope *env;
808 struct ClientPhoneHangupMessage *hup;
809 enum ChannelStatus status;
810 uint32_t cid;
811
812 (void) message;
813 GNUNET_CADET_receive_done (ch->channel);
814 cid = ch->cid;
815 status = ch->status;
816 destroy_line_cadet_channels (ch);
817 switch (status)
818 {
819 case CS_CALLEE_INIT:
820 GNUNET_break_op (0);
821 return;
822
823 case CS_CALLEE_RINGING:
824 case CS_CALLEE_CONNECTED:
825 break;
826
827 case CS_CALLEE_SHUTDOWN:
828 return;
829
830 case CS_CALLER_CALLING:
831 case CS_CALLER_CONNECTED:
832 break;
833
834 case CS_CALLER_SHUTDOWN:
835 return;
836 }
837 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending HANG UP message to client\n");
838 env = GNUNET_MQ_msg (hup, GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP);
839 hup->cid = cid;
840 GNUNET_MQ_send (line->mq, env);
841}
842
843
844/**
845 * Function to handle a pickup message incoming over cadet
846 *
847 * @param cls closure, our `struct Channel *`
848 * @param message the incoming message
849 */
850static void
851handle_cadet_pickup_message (void *cls,
852 const struct CadetPhonePickupMessage *message)
853{
854 struct Channel *ch = cls;
855 struct Line *line = ch->line;
856 struct GNUNET_MQ_Envelope *env;
857 struct ClientPhonePickedupMessage *pick;
858
859 (void) message;
860 GNUNET_CADET_receive_done (ch->channel);
861 switch (ch->status)
862 {
863 case CS_CALLEE_INIT:
864 case CS_CALLEE_RINGING:
865 case CS_CALLEE_CONNECTED:
866 GNUNET_break_op (0);
867 destroy_line_cadet_channels (ch);
868 return;
869
870 case CS_CALLEE_SHUTDOWN:
871 GNUNET_break_op (0);
872 destroy_line_cadet_channels (ch);
873 return;
874
875 case CS_CALLER_CALLING:
876 ch->status = CS_CALLER_CONNECTED;
877 break;
878
879 case CS_CALLER_CONNECTED:
880 GNUNET_break_op (0);
881 return;
882
883 case CS_CALLER_SHUTDOWN:
884 GNUNET_break_op (0);
885 mq_done_finish_caller_shutdown (ch);
886 return;
887 }
888 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending PICKED UP message to client\n");
889 env =
890 GNUNET_MQ_msg (pick, GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICKED_UP);
891 pick->cid = ch->cid;
892 GNUNET_MQ_send (line->mq, env);
893}
894
895
896/**
897 * Function to handle a suspend message incoming over cadet
898 *
899 * @param cls closure, our `struct Channel *`
900 * @param message the incoming message
901 */
902static void
903handle_cadet_suspend_message (void *cls,
904 const struct CadetPhoneSuspendMessage *message)
905{
906 struct Channel *ch = cls;
907 struct Line *line = ch->line;
908 struct GNUNET_MQ_Envelope *env;
909 struct ClientPhoneSuspendMessage *suspend;
910
911 (void) message;
912 GNUNET_CADET_receive_done (ch->channel);
913 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Suspending channel CID: %u\n", ch->cid);
914 switch (ch->status)
915 {
916 case CS_CALLEE_INIT:
917 GNUNET_break_op (0);
918 break;
919
920 case CS_CALLEE_RINGING:
921 GNUNET_break_op (0);
922 break;
923
924 case CS_CALLEE_CONNECTED:
925 ch->suspended_remote = GNUNET_YES;
926 break;
927
928 case CS_CALLEE_SHUTDOWN:
929 return;
930
931 case CS_CALLER_CALLING:
932 GNUNET_break_op (0);
933 break;
934
935 case CS_CALLER_CONNECTED:
936 ch->suspended_remote = GNUNET_YES;
937 break;
938
939 case CS_CALLER_SHUTDOWN:
940 return;
941 }
942 env =
943 GNUNET_MQ_msg (suspend, GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_SUSPEND);
944 suspend->cid = ch->cid;
945 GNUNET_MQ_send (line->mq, env);
946}
947
948
949/**
950 * Function to handle a resume message incoming over cadet
951 *
952 * @param cls closure, our `struct Channel *`
953 * @param msg the incoming message
954 */
955static void
956handle_cadet_resume_message (void *cls,
957 const struct CadetPhoneResumeMessage *msg)
958{
959 struct Channel *ch = cls;
960 struct Line *line;
961 struct GNUNET_MQ_Envelope *env;
962 struct ClientPhoneResumeMessage *resume;
963
964 (void) msg;
965 line = ch->line;
966 GNUNET_CADET_receive_done (ch->channel);
967 if (GNUNET_YES != ch->suspended_remote)
968 {
969 GNUNET_log (
970 GNUNET_ERROR_TYPE_DEBUG,
971 "RESUME message received for non-suspended channel, dropping channel.\n");
972 destroy_line_cadet_channels (ch);
973 return;
974 }
975 switch (ch->status)
976 {
977 case CS_CALLEE_INIT:
978 GNUNET_break (0);
979 break;
980
981 case CS_CALLEE_RINGING:
982 GNUNET_break (0);
983 break;
984
985 case CS_CALLEE_CONNECTED:
986 ch->suspended_remote = GNUNET_NO;
987 break;
988
989 case CS_CALLEE_SHUTDOWN:
990 return;
991
992 case CS_CALLER_CALLING:
993 GNUNET_break (0);
994 break;
995
996 case CS_CALLER_CONNECTED:
997 ch->suspended_remote = GNUNET_NO;
998 break;
999
1000 case CS_CALLER_SHUTDOWN:
1001 return;
1002 }
1003 env =
1004 GNUNET_MQ_msg (resume, GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RESUME);
1005 resume->cid = ch->cid;
1006 GNUNET_MQ_send (line->mq, env);
1007}
1008
1009
1010/**
1011 * Function to check an audio message incoming over cadet
1012 *
1013 * @param cls closure, our `struct Channel *`
1014 * @param msg the incoming message
1015 * @return #GNUNET_OK (always)
1016 */
1017static int
1018check_cadet_audio_message (void *cls, const struct CadetAudioMessage *msg)
1019{
1020 (void) cls;
1021 (void) msg;
1022 return GNUNET_OK; /* any payload is fine */
1023}
1024
1025
1026/**
1027 * Function to handle an audio message incoming over cadet
1028 *
1029 * @param cls closure, our `struct Channel *`
1030 * @param msg the incoming message
1031 */
1032static void
1033handle_cadet_audio_message (void *cls, const struct CadetAudioMessage *msg)
1034{
1035 struct Channel *ch = cls;
1036 size_t msize = ntohs (msg->header.size) - sizeof(struct CadetAudioMessage);
1037 struct GNUNET_MQ_Envelope *env;
1038 struct ClientAudioMessage *cam;
1039
1040 GNUNET_CADET_receive_done (ch->channel);
1041 if ((GNUNET_YES == ch->suspended_local) ||
1042 (GNUNET_YES == ch->suspended_remote))
1043 {
1044 GNUNET_log (
1045 GNUNET_ERROR_TYPE_DEBUG,
1046 "Received %u bytes of AUDIO data on suspended channel CID %u; dropping\n",
1047 (unsigned int) msize,
1048 ch->cid);
1049 return;
1050 }
1051 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1052 "Forwarding %u bytes of AUDIO data to client CID %u\n",
1053 (unsigned int) msize,
1054 ch->cid);
1055 env =
1056 GNUNET_MQ_msg_extra (cam, msize, GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO);
1057 cam->cid = ch->cid;
1058 GNUNET_memcpy (&cam[1], &msg[1], msize);
1059 GNUNET_MQ_send (ch->line->mq, env);
1060}
1061
1062
1063/**
1064 * Function called whenever an inbound channel is destroyed. Should clean up
1065 * any associated state.
1066 *
1067 * @param cls closure (set from #GNUNET_CADET_connect)
1068 * @param channel connection to the other end (henceforth invalid)
1069 */
1070static void
1071inbound_end (void *cls, const struct GNUNET_CADET_Channel *channel)
1072{
1073 struct Channel *ch = cls;
1074
1075 GNUNET_assert (channel == ch->channel);
1076 ch->channel = NULL;
1077 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1078 "Channel destroyed by CADET in state %d\n",
1079 ch->status);
1080 clean_up_channel (ch);
1081}
1082
1083
1084/**
1085 * Function to handle call request from the client
1086 *
1087 * @param cls the `struct Line` the message is about
1088 * @param msg the message from the client
1089 */
1090static void
1091handle_client_call_message (void *cls, const struct ClientCallMessage *msg)
1092{
1093 struct Line *line = cls;
1094 struct Channel *ch = GNUNET_new (struct Channel);
1095 struct GNUNET_MQ_MessageHandler cadet_handlers[] =
1096 { GNUNET_MQ_hd_fixed_size (cadet_hangup_message,
1097 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_HANG_UP,
1098 struct CadetPhoneHangupMessage,
1099 ch),
1100 GNUNET_MQ_hd_fixed_size (cadet_pickup_message,
1101 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_PICK_UP,
1102 struct CadetPhonePickupMessage,
1103 ch),
1104 GNUNET_MQ_hd_fixed_size (cadet_suspend_message,
1105 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_SUSPEND,
1106 struct CadetPhoneSuspendMessage,
1107 ch),
1108 GNUNET_MQ_hd_fixed_size (cadet_resume_message,
1109 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_RESUME,
1110 struct CadetPhoneResumeMessage,
1111 ch),
1112 GNUNET_MQ_hd_var_size (cadet_audio_message,
1113 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_AUDIO,
1114 struct CadetAudioMessage,
1115 ch),
1116 GNUNET_MQ_handler_end () };
1117 struct GNUNET_MQ_Envelope *e;
1118 struct CadetPhoneRingMessage *ring;
1119 struct CadetPhoneRingInfoPS rs;
1120
1121 line->line_port = msg->line_port;
1122 rs.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CONVERSATION_RING);
1123 rs.purpose.size = htonl (sizeof(struct CadetPhoneRingInfoPS));
1124 rs.line_port = line->line_port;
1125 rs.target_peer = msg->target;
1126 rs.expiration_time =
1127 GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (RING_TIMEOUT));
1128 ch->line = line;
1129 GNUNET_CONTAINER_DLL_insert (line->channel_head, line->channel_tail, ch);
1130 ch->status = CS_CALLER_CALLING;
1131 ch->channel = GNUNET_CADET_channel_create (cadet,
1132 ch,
1133 &msg->target,
1134 &msg->line_port,
1135 NULL,
1136 &inbound_end,
1137 cadet_handlers);
1138 ch->mq = GNUNET_CADET_get_mq (ch->channel);
1139 e = GNUNET_MQ_msg (ring, GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_RING);
1140 GNUNET_IDENTITY_key_get_public (&msg->caller_id, &ring->caller_id);
1141 ring->expiration_time = rs.expiration_time;
1142 GNUNET_IDENTITY_sign (&msg->caller_id, &rs, &ring->signature);
1143 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending RING message via CADET\n");
1144 GNUNET_MQ_send (ch->mq, e);
1145 GNUNET_SERVICE_client_continue (line->client);
1146}
1147
1148
1149/**
1150 * Method called whenever another peer has added us to a channel
1151 * the other peer initiated.
1152 *
1153 * @param cls the `struct Line` receiving a connection
1154 * @param channel new handle to the channel
1155 * @param initiator peer that started the channel
1156 * @return initial channel context for the channel
1157 */
1158static void *
1159inbound_channel (void *cls,
1160 struct GNUNET_CADET_Channel *channel,
1161 const struct GNUNET_PeerIdentity *initiator)
1162{
1163 struct Line *line = cls;
1164 struct Channel *ch;
1165
1166 (void) initiator;
1167 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1168 "Received incoming cadet channel on line %p\n",
1169 line);
1170 ch = GNUNET_new (struct Channel);
1171 ch->status = CS_CALLEE_INIT;
1172 ch->line = line;
1173 ch->channel = channel;
1174 ch->mq = GNUNET_CADET_get_mq (ch->channel);
1175 ch->cid = line->cid_gen++;
1176 GNUNET_CONTAINER_DLL_insert (line->channel_head, line->channel_tail, ch);
1177 return ch;
1178}
1179
1180
1181/**
1182 * A client connected. Initialize the `struct Line` data structure.
1183 *
1184 * @param cls closure, NULL
1185 * @param client identification of the client
1186 * @param mq message queue for @a client
1187 * @return the `struct Line` for the client
1188 */
1189static void *
1190client_connect_cb (void *cls,
1191 struct GNUNET_SERVICE_Client *client,
1192 struct GNUNET_MQ_Handle *mq)
1193{
1194 struct Line *line;
1195
1196 (void) cls;
1197 line = GNUNET_new (struct Line);
1198 line->client = client;
1199 line->mq = mq;
1200 return line;
1201}
1202
1203
1204/**
1205 * A client disconnected. Remove all of its data structure entries.
1206 *
1207 * @param cls closure, NULL
1208 * @param client identification of the client
1209 * @param app_ctx our `struct Line *` for @a client
1210 */
1211static void
1212client_disconnect_cb (void *cls,
1213 struct GNUNET_SERVICE_Client *client,
1214 void *app_ctx)
1215{
1216 struct Line *line = app_ctx;
1217 struct Channel *chn;
1218
1219 (void) cls;
1220 (void) client;
1221 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client disconnected, closing line\n");
1222 if (NULL != line->port)
1223 {
1224 GNUNET_CADET_close_port (line->port);
1225 line->port = NULL;
1226 }
1227 for (struct Channel *ch = line->channel_head; NULL != ch; ch = chn)
1228 {
1229 chn = ch->next;
1230 ch->line = NULL;
1231 destroy_line_cadet_channels (ch);
1232 }
1233 GNUNET_free (line);
1234}
1235
1236
1237/**
1238 * Function to register a phone.
1239 *
1240 * @param cls the `struct Line` of the client from which the message is
1241 * @param msg the message from the client
1242 */
1243static void
1244handle_client_register_message (void *cls,
1245 const struct ClientPhoneRegisterMessage *msg)
1246{
1247 struct Line *line = cls;
1248 struct GNUNET_MQ_MessageHandler cadet_handlers[] =
1249 { GNUNET_MQ_hd_fixed_size (cadet_ring_message,
1250 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_RING,
1251 struct CadetPhoneRingMessage,
1252 NULL),
1253 GNUNET_MQ_hd_fixed_size (cadet_hangup_message,
1254 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_HANG_UP,
1255 struct CadetPhoneHangupMessage,
1256 NULL),
1257 GNUNET_MQ_hd_fixed_size (cadet_pickup_message,
1258 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_PICK_UP,
1259 struct CadetPhonePickupMessage,
1260 NULL),
1261 GNUNET_MQ_hd_fixed_size (cadet_suspend_message,
1262 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_SUSPEND,
1263 struct CadetPhoneSuspendMessage,
1264 NULL),
1265 GNUNET_MQ_hd_fixed_size (cadet_resume_message,
1266 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_RESUME,
1267 struct CadetPhoneResumeMessage,
1268 NULL),
1269 GNUNET_MQ_hd_var_size (cadet_audio_message,
1270 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_AUDIO,
1271 struct CadetAudioMessage,
1272 NULL),
1273 GNUNET_MQ_handler_end () };
1274
1275 line->line_port = msg->line_port;
1276 line->port = GNUNET_CADET_open_port (cadet,
1277 &msg->line_port,
1278 &inbound_channel,
1279 line,
1280 NULL,
1281 &inbound_end,
1282 cadet_handlers);
1283 if (NULL == line->port)
1284 {
1285 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1286 _ ("Could not open line, port %s already in use!\n"),
1287 GNUNET_h2s (&msg->line_port));
1288 GNUNET_SERVICE_client_drop (line->client);
1289 return;
1290 }
1291 GNUNET_SERVICE_client_continue (line->client);
1292}
1293
1294
1295/**
1296 * Shutdown nicely
1297 *
1298 * @param cls closure, NULL
1299 */
1300static void
1301do_shutdown (void *cls)
1302{
1303 (void) cls;
1304 if (NULL != cadet)
1305 {
1306 GNUNET_CADET_disconnect (cadet);
1307 cadet = NULL;
1308 }
1309}
1310
1311
1312/**
1313 * Main function that will be run by the scheduler.
1314 *
1315 * @param cls closure
1316 * @param c configuration
1317 * @param service service handle
1318 */
1319static void
1320run (void *cls,
1321 const struct GNUNET_CONFIGURATION_Handle *c,
1322 struct GNUNET_SERVICE_Handle *service)
1323{
1324 (void) cls;
1325 (void) service;
1326 cfg = c;
1327 GNUNET_assert (GNUNET_OK ==
1328 GNUNET_CRYPTO_get_peer_identity (cfg, &my_identity));
1329 cadet = GNUNET_CADET_connect (cfg);
1330 if (NULL == cadet)
1331 {
1332 GNUNET_break (0);
1333 GNUNET_SCHEDULER_shutdown ();
1334 return;
1335 }
1336 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
1337}
1338
1339
1340/**
1341 * Define "main" method using service macro.
1342 */
1343GNUNET_SERVICE_MAIN (
1344 "conversation",
1345 GNUNET_SERVICE_OPTION_NONE,
1346 &run,
1347 &client_connect_cb,
1348 &client_disconnect_cb,
1349 NULL,
1350 GNUNET_MQ_hd_fixed_size (client_register_message,
1351 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_REGISTER,
1352 struct ClientPhoneRegisterMessage,
1353 NULL),
1354 GNUNET_MQ_hd_fixed_size (client_pickup_message,
1355 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICK_UP,
1356 struct ClientPhonePickupMessage,
1357 NULL),
1358 GNUNET_MQ_hd_fixed_size (client_suspend_message,
1359 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_SUSPEND,
1360 struct ClientPhoneSuspendMessage,
1361 NULL),
1362 GNUNET_MQ_hd_fixed_size (client_resume_message,
1363 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RESUME,
1364 struct ClientPhoneResumeMessage,
1365 NULL),
1366 GNUNET_MQ_hd_fixed_size (client_hangup_message,
1367 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP,
1368 struct ClientPhoneHangupMessage,
1369 NULL),
1370 GNUNET_MQ_hd_fixed_size (client_call_message,
1371 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_CALL,
1372 struct ClientCallMessage,
1373 NULL),
1374 GNUNET_MQ_hd_var_size (client_audio_message,
1375 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO,
1376 struct ClientAudioMessage,
1377 NULL),
1378 GNUNET_MQ_handler_end ());
1379
1380
1381/* end of gnunet-service-conversation.c */