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