-sending RING signal
[oweals/gnunet.git] / src / conversation / gnunet-service-conversation-new.c
1 /*
2   This file is part of GNUnet.
3   (C) 2013 Christian Grothoff (and other contributing authors)
4   
5   GNUnet is free software; you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published
7   by the Free Software Foundation; either version 3, or (at your
8   option) any later version.
9   
10   GNUnet is distributed in the hope that it will be useful, but
11   WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13   General Public License for more details.
14   
15   You should have received a copy of the GNU General Public License
16   along with GNUnet; see the file COPYING.  If not, write to the
17   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18   Boston, MA 02111-1307, USA.
19 */
20 /**
21  * @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_mesh_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  * The possible connection status
48  */
49 enum LineStatus
50 {
51   /**
52    * We are waiting for incoming calls.
53    */
54   LS_CALLEE_LISTEN,
55
56   /**
57    * Our phone is ringing, waiting for the client to pick up.
58    */
59   LS_CALLEE_RINGING,
60
61   /**
62    * We are talking!
63    */
64   LS_CALLEE_CONNECTED,
65
66   /**
67    * We are waiting for the phone to be picked up.
68    */
69   LS_CALLER_CALLING,
70
71   /**
72    * We are talking!
73    */
74   LS_CALLER_CONNECTED,
75
76   /**
77    * We're in shutdown, sending hangup messages before cleaning up.
78    */
79   LS_CALLER_SHUTDOWN
80 };
81
82
83 /**
84  * A line connects a local client with a mesh tunnel (or, if it is an
85  * open line, is waiting for a mesh tunnel).
86  */
87 struct Line
88 {
89   /**
90    * Kept in a DLL.
91    */
92   struct Line *next;
93
94   /**
95    * Kept in a DLL.
96    */
97   struct Line *prev;
98
99   /**
100    * Handle for the reliable tunnel (contol data)
101    */
102   struct GNUNET_MESH_Tunnel *tunnel_reliable;
103   
104   /**
105    * Handle for unreliable tunnel (audio data)
106    */
107   struct GNUNET_MESH_Tunnel *tunnel_unreliable;
108
109   /**
110    * Transmit handle for pending audio messages
111    */
112   struct GNUNET_MESH_TransmitHandle *unreliable_mth;
113
114   /**
115    * Message queue for control messages
116    */
117   struct GNUNET_MQ_Handle *reliable_mq;
118
119   /**
120    * Handle to the line client.
121    */
122   struct GNUNET_SERVER_Client *client;
123
124   /**
125    * Target of the line, if we are the caller.
126    */
127   struct GNUNET_PeerIdentity target;
128
129   /**
130    * Our line number.
131    */
132   uint32_t local_line;
133
134   /**
135    * Remote line number.
136    */
137   uint32_t remote_line;
138
139   /**
140    * Current status of this line.
141    */ 
142   enum LineStatus status;
143
144 };
145
146
147 /**
148  * Our configuration.
149  */
150 static const struct GNUNET_CONFIGURATION_Handle *cfg;
151
152 /**
153  * Notification context containing all connected clients.
154  */
155 static struct GNUNET_SERVER_NotificationContext *nc;
156
157 /**
158  * Handle for mesh
159  */
160 static struct GNUNET_MESH_Handle *mesh;
161
162 /**
163  * Identity of this peer.
164  */
165 static struct GNUNET_PeerIdentity my_identity;
166
167 /**
168  * Head of DLL of active lines.
169  */
170 static struct Line *lines_head;
171
172 /**
173  * Tail of DLL of active lines.
174  */
175 static struct Line *lines_tail;
176
177 /**
178  * Counter for generating local line numbers.
179  * FIXME: randomize generation in the future
180  * to eliminate information leakage.
181  */
182 static uint32_t local_line_cnt;
183
184
185 /**
186  * Function to register a phone.
187  *
188  * @param cls closure, NULL
189  * @param client the client from which the message is
190  * @param message the message from the client
191  */
192 static void
193 handle_client_register_message (void *cls,
194                                 struct GNUNET_SERVER_Client *client,
195                                 const struct GNUNET_MessageHeader *message)
196 {
197   const struct ClientPhoneRegisterMessage *msg;
198   struct Line *line;
199
200   msg = (struct ClientPhoneRegisterMessage *) message;
201   line = GNUNET_SERVER_client_get_user_context (client, struct Line);
202   if (NULL != line)
203   {
204     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
205     return;
206   }
207   line = GNUNET_new (struct Line);
208   line->client = client;
209   GNUNET_SERVER_notification_context_add (nc, client);
210   GNUNET_CONTAINER_DLL_insert (lines_head,
211                                lines_tail,
212                                line);
213   line->local_line = ntohl (msg->line);
214   GNUNET_SERVER_client_set_user_context (client, line);
215   GNUNET_SERVER_receive_done (client, GNUNET_OK);
216 }
217
218
219 /**
220  * Function to handle a pickup request message from the client
221  *
222  * @param cls closure, NULL
223  * @param client the client from which the message is
224  * @param message the message from the client
225  */
226 static void
227 handle_client_pickup_message (void *cls,
228                               struct GNUNET_SERVER_Client *client,
229                               const struct GNUNET_MessageHeader *message)
230 {
231   const struct ClientPhonePickupMessage *msg;
232
233   msg = (struct ClientPhonePickupMessage *) message;
234   GNUNET_break (0); // FIXME
235   GNUNET_SERVER_receive_done (client, GNUNET_OK);
236 }
237
238
239 /**
240  * Function to handle a hangup request message from the client
241  *
242  * @param cls closure, NULL
243  * @param client the client from which the message is
244  * @param message the message from the client
245  */
246 static void
247 handle_client_hangup_message (void *cls,
248                               struct GNUNET_SERVER_Client *client,
249                               const struct GNUNET_MessageHeader *message)
250 {
251   const struct ClientPhoneHangupMessage *msg;
252
253   msg = (struct ClientPhoneHangupMessage *) message;
254   GNUNET_break (0); // FIXME
255   GNUNET_SERVER_receive_done (client, GNUNET_OK);
256 }
257
258
259 /**
260  * Function to handle call request the client
261  *
262  * @param cls closure, NULL
263  * @param client the client from which the message is
264  * @param message the message from the client
265  */
266 static void
267 handle_client_call_message (void *cls,
268                             struct GNUNET_SERVER_Client *client,
269                             const struct GNUNET_MessageHeader *message)
270 {
271   const struct ClientCallMessage *msg;
272   struct Line *line;
273   struct GNUNET_MQ_Envelope *e;
274   struct MeshPhoneRingMessage *ring;
275
276   msg = (struct ClientCallMessage *) message;
277   line = GNUNET_SERVER_client_get_user_context (client, struct Line);
278   if (NULL != line)
279   {
280     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
281     return;
282   }
283   line = GNUNET_new (struct Line);
284   line->target = msg->target;
285   GNUNET_CONTAINER_DLL_insert (lines_head,
286                                lines_tail,
287                                line);
288   line->remote_line = ntohl (msg->line);
289   line->status = LS_CALLER_CALLING;
290   line->tunnel_reliable = GNUNET_MESH_tunnel_create (mesh,
291                                                      line,
292                                                      &msg->target,
293                                                      GNUNET_APPLICATION_TYPE_CONVERSATION_CONTROL,
294                                                      GNUNET_NO,
295                                                      GNUNET_YES);
296   line->reliable_mq = GNUNET_MESH_mq_create (line->tunnel_reliable);
297   line->local_line = local_line_cnt++;
298   e = GNUNET_MQ_msg (ring, GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_RING);
299   ring->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CONVERSATION_RING);
300   ring->purpose.size = htonl (sizeof (struct GNUNET_PeerIdentity) * 2 +
301                               sizeof (struct GNUNET_TIME_AbsoluteNBO) +
302                               sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
303                               sizeof (struct GNUNET_CRYPTO_EccPublicSignKey));
304   GNUNET_CRYPTO_ecc_key_get_public_for_signature (&msg->caller_id,
305                                                   &ring->caller_id);
306   ring->remote_line = msg->line;
307   ring->source_line = line->local_line;
308   ring->target = msg->target;
309   ring->source = my_identity;
310   ring->expiration_time = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (RING_TIMEOUT));
311   GNUNET_CRYPTO_ecc_sign (&msg->caller_id,
312                           &ring->purpose,
313                           &ring->signature);
314   GNUNET_MQ_send (line->reliable_mq, e);
315   GNUNET_SERVER_client_set_user_context (client, line);
316   GNUNET_SERVER_receive_done (client, GNUNET_OK);
317 }
318
319
320 /**
321  * Function to handle audio data from the client
322  *
323  * @param cls closure, NULL
324  * @param client the client from which the message is
325  * @param message the message from the client
326  */
327 static void
328 handle_client_audio_message (void *cls,
329                              struct GNUNET_SERVER_Client *client,
330                              const struct GNUNET_MessageHeader *message)
331 {
332   const struct ClientAudioMessage *msg;
333
334   msg = (struct ClientAudioMessage *) message;
335   GNUNET_break (0); // FIXME
336   GNUNET_SERVER_receive_done (client, GNUNET_OK);
337 }
338
339
340 /**
341  * Function to handle a ring message incoming over mesh
342  *
343  * @param cls closure, NULL
344  * @param tunnel the tunnel over which the message arrived
345  * @param tunnel_ctx the tunnel context, can be NULL
346  * @param message the incoming message
347  * @return #GNUNET_OK
348  */
349 static int
350 handle_mesh_ring_message (void *cls,
351                           struct GNUNET_MESH_Tunnel *tunnel,
352                           void **tunnel_ctx,
353                           const struct GNUNET_MessageHeader *message)
354 {
355   const struct MeshPhoneRingMessage *msg;
356   struct Line *line;
357   struct GNUNET_MQ_Envelope *e;
358   struct MeshPhoneBusyMessage *busy;
359   struct ClientPhoneRingMessage cring;
360   
361   msg = (const struct MeshPhoneRingMessage *) message;
362   if ( (msg->purpose.size != htonl (sizeof (struct GNUNET_PeerIdentity) * 2 +
363                                     sizeof (struct GNUNET_TIME_AbsoluteNBO) +
364                                     sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
365                                     sizeof (struct GNUNET_CRYPTO_EccPublicSignKey))) ||
366        (GNUNET_OK !=
367         GNUNET_CRYPTO_ecc_verify (GNUNET_SIGNATURE_PURPOSE_CONVERSATION_RING,
368                                   &msg->purpose,
369                                   &msg->signature,
370                                   &msg->caller_id)) )
371   {
372     GNUNET_break_op (0);
373     return GNUNET_SYSERR;
374   }
375   for (line = lines_head; NULL != line; line = line->next)  
376     if ( (line->local_line == ntohl (msg->remote_line)) &&
377          (LS_CALLEE_LISTEN == line->status) )
378       break;
379   if (NULL == line) 
380   {
381     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
382                 _("No available phone for incoming call on line %u, sending BUSY signal\n"),
383                 ntohl (msg->remote_line));
384     e = GNUNET_MQ_msg (busy, GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_BUSY);
385     GNUNET_MQ_send (line->reliable_mq, e);
386     return GNUNET_OK;
387   }
388   line->status = LS_CALLEE_RINGING;
389   line->remote_line = ntohl (msg->source_line);
390   line->tunnel_reliable = tunnel;
391   cring.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RING);
392   cring.header.size = htons (sizeof (cring));
393   cring.reserved = htonl (0);
394   cring.caller_id = msg->caller_id;
395   GNUNET_SERVER_notification_context_unicast (nc,
396                                               line->client,
397                                               &cring.header,
398                                               GNUNET_NO);
399   return GNUNET_OK;
400 }
401
402
403 /**
404  * Function to handle a hangup message incoming over mesh
405  *
406  * @param cls closure, NULL
407  * @param tunnel the tunnel over which the message arrived
408  * @param tunnel_ctx the tunnel context, can be NULL
409  * @param message the incoming message
410  * @return #GNUNET_OK
411  */
412 static int
413 handle_mesh_hangup_message (void *cls,
414                             struct GNUNET_MESH_Tunnel *tunnel,
415                             void **tunnel_ctx,
416                             const struct GNUNET_MessageHeader *message)
417 {
418   const struct MeshPhoneHangupMessage *msg;
419   
420   msg = (const struct MeshPhoneHangupMessage *) message;
421   GNUNET_break (0); // FIXME
422   return GNUNET_OK;
423 }
424
425
426 /**
427  * Function to handle a pickup message incoming over mesh
428  *
429  * @param cls closure, NULL
430  * @param tunnel the tunnel over which the message arrived
431  * @param tunnel_ctx the tunnel context, can be NULL
432  * @param message the incoming message
433  * @return #GNUNET_OK
434  */
435 static int
436 handle_mesh_pickup_message (void *cls,
437                             struct GNUNET_MESH_Tunnel *tunnel,
438                             void **tunnel_ctx,
439                             const struct GNUNET_MessageHeader *message)
440 {
441   const struct MeshPhonePickupMessage *msg;
442   struct Line *line = *tunnel_ctx;
443   
444   msg = (const struct MeshPhonePickupMessage *) message;
445   GNUNET_break (0); // FIXME
446
447
448   line->tunnel_unreliable = GNUNET_MESH_tunnel_create (mesh,
449                                                        line,
450                                                        &line->target,
451                                                        GNUNET_APPLICATION_TYPE_CONVERSATION_AUDIO,
452                                                        GNUNET_YES,
453                                                        GNUNET_NO);
454   
455
456   return GNUNET_OK;
457 }
458
459
460 /**
461  * Function to handle a busy message incoming over mesh
462  *
463  * @param cls closure, NULL
464  * @param tunnel the tunnel over which the message arrived
465  * @param tunnel_ctx the tunnel context, can be NULL
466  * @param message the incoming message
467  * @return #GNUNET_OK
468  */
469 static int
470 handle_mesh_busy_message (void *cls,
471                           struct GNUNET_MESH_Tunnel *tunnel,
472                           void **tunnel_ctx,
473                           const struct GNUNET_MessageHeader *message)
474 {
475   const struct MeshPhoneBusyMessage *msg;
476   
477   msg = (const struct MeshPhoneBusyMessage *) message;
478   GNUNET_break (0); // FIXME
479   return GNUNET_OK;
480 }
481
482
483 /**
484  * Function to handle an audio message incoming over mesh
485  *
486  * @param cls closure, NULL
487  * @param tunnel the tunnel over which the message arrived
488  * @param tunnel_ctx the tunnel context, can be NULL
489  * @param message the incoming message
490  * @return #GNUNET_OK
491  */
492 static int
493 handle_mesh_audio_message (void *cls,
494                            struct GNUNET_MESH_Tunnel *tunnel,
495                            void **tunnel_ctx,
496                            const struct GNUNET_MessageHeader *message)
497 {
498   const struct MeshAudioMessage *msg;
499   
500   msg = (const struct MeshAudioMessage *) message;
501   GNUNET_break (0); // FIXME
502   return GNUNET_OK;
503 }
504
505
506 /**
507  * Method called whenever another peer has added us to a tunnel
508  * the other peer initiated.
509  *
510  * @param cls closure
511  * @param tunnel new handle to the tunnel
512  * @param initiator peer that started the tunnel
513  * @param port port
514  * @return initial tunnel context for the tunnel (can be NULL -- that's not an error)
515  */
516 static void *
517 inbound_tunnel (void *cls,
518                 struct GNUNET_MESH_Tunnel *tunnel,
519                 const struct GNUNET_PeerIdentity *initiator, 
520                 uint32_t port)
521 {
522   
523   GNUNET_break (0); // FIXME
524   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
525               _("Received incoming tunnel on port %d\n"), port);
526   return NULL;
527 }
528
529
530 /**
531  * Function called whenever an inbound tunnel is destroyed.  Should clean up
532  * any associated state.
533  *
534  * @param cls closure (set from #GNUNET_MESH_connect)
535  * @param tunnel connection to the other end (henceforth invalid)
536  * @param tunnel_ctx place where local state associated
537  *                   with the tunnel is stored
538  */
539 static void
540 inbound_end (void *cls,
541              const struct GNUNET_MESH_Tunnel *tunnel,
542              void *tunnel_ctx)
543 {
544   GNUNET_break (0); // FIXME
545 }
546
547
548 /**
549  * A client disconnected.  Remove all of its data structure entries.
550  *
551  * @param cls closure, NULL
552  * @param client identification of the client
553  */
554 static void
555 handle_client_disconnect (void *cls, 
556                           struct GNUNET_SERVER_Client *client)
557 {
558   struct Line *line;
559
560   line = GNUNET_SERVER_client_get_user_context (client, struct Line);
561   if (NULL == line)
562     return;
563   GNUNET_CONTAINER_DLL_remove (lines_head,
564                                lines_tail,
565                                line);
566   GNUNET_free (line);
567   GNUNET_SERVER_client_set_user_context (client, NULL);
568 }
569
570
571 /**
572  * Shutdown nicely
573  * 
574  * @param cls closure, NULL
575  * @param tc the task context
576  */
577 static void
578 do_shutdown (void *cls,
579              const struct GNUNET_SCHEDULER_TaskContext *tc)
580 {
581   GNUNET_break (0); // FIXME
582   if (NULL != mesh)
583   {
584     GNUNET_MESH_disconnect (mesh);
585     mesh = NULL;
586   }
587   if (NULL != nc)
588   {
589     GNUNET_SERVER_notification_context_destroy (nc);
590     nc = NULL;
591   }
592 }
593
594
595 /**
596  * Main function that will be run by the scheduler.
597  *
598  * @param cls closure
599  * @param server server handle
600  * @param c configuration
601  */
602 static void
603 run (void *cls, 
604      struct GNUNET_SERVER_Handle *server,
605      const struct GNUNET_CONFIGURATION_Handle *c)
606 {
607   static const struct GNUNET_SERVER_MessageHandler server_handlers[] = {
608     {&handle_client_register_message, NULL,
609      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_REGISTER,
610      sizeof (struct ClientPhoneRegisterMessage)},
611     {&handle_client_pickup_message, NULL,
612      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICK_UP,
613      0},
614     {&handle_client_hangup_message, NULL,
615      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP,
616      0},
617     {&handle_client_call_message, NULL,
618      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_CALL,
619      0},
620     {&handle_client_audio_message, NULL,
621      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO,
622      0},
623     {NULL, NULL, 0, 0}
624   };
625   static struct GNUNET_MESH_MessageHandler mesh_handlers[] = {
626     {&handle_mesh_ring_message,
627      GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_RING,
628      sizeof (struct MeshPhoneRingMessage)},
629     {&handle_mesh_hangup_message, 
630      GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_HANG_UP,
631      0},
632     {&handle_mesh_pickup_message, 
633      GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_PICK_UP,
634      0},
635     {&handle_mesh_busy_message, 
636      GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_BUSY,
637      sizeof (struct MeshPhoneBusyMessage)},
638     {&handle_mesh_audio_message, GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_AUDIO,
639      0},
640     {NULL, 0, 0}
641   };
642   static uint32_t ports[] = { 
643     GNUNET_APPLICATION_TYPE_CONVERSATION_CONTROL,
644     GNUNET_APPLICATION_TYPE_CONVERSATION_AUDIO,
645     0 
646   };
647
648   cfg = c;
649   GNUNET_assert (GNUNET_OK ==
650                  GNUNET_CRYPTO_get_host_identity (cfg,
651                                                   &my_identity));
652   mesh = GNUNET_MESH_connect (cfg,
653                               NULL,
654                               &inbound_tunnel,
655                               &inbound_end, 
656                               mesh_handlers, 
657                               ports);
658
659   if (NULL == mesh)
660   {
661     GNUNET_break (0);
662     GNUNET_SCHEDULER_shutdown ();
663     return;
664   }
665   nc = GNUNET_SERVER_notification_context_create (server, 16);
666   GNUNET_SERVER_add_handlers (server, server_handlers);
667   GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL);
668   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, 
669                                 &do_shutdown,
670                                 NULL);
671 }
672
673
674 /**
675  * The main function for the conversation service.
676  *
677  * @param argc number of arguments from the command line
678  * @param argv command line arguments
679  * @return 0 ok, 1 on error
680  */
681 int
682 main (int argc, 
683       char *const *argv)
684 {
685   return (GNUNET_OK ==
686           GNUNET_SERVICE_run (argc, argv,
687                               "conversation", 
688                               GNUNET_SERVICE_OPTION_NONE,
689                               &run, NULL)) ? 0 : 1;
690 }
691
692 /* end of gnunet-service-conversation.c */