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