-sync before server reboot, work on conversation service
[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    * Transmit handle for pending audio messages
116    */
117   struct GNUNET_MQ_Handle *reliable_mq;
118
119   /**
120    * Our line number.
121    */
122   uint32_t line;
123
124   /**
125    * Current status of this line.
126    */ 
127   enum LineStatus status;
128
129 };
130
131
132 /**
133  * Our configuration.
134  */
135 static const struct GNUNET_CONFIGURATION_Handle *cfg;
136
137 /**
138  * Notification context containing all connected clients.
139  */
140 static struct GNUNET_SERVER_NotificationContext *nc;
141
142 /**
143  * Handle for mesh
144  */
145 static struct GNUNET_MESH_Handle *mesh;
146
147 /**
148  * Identity of this peer.
149  */
150 static struct GNUNET_PeerIdentity my_identity;
151
152 /**
153  * Head of DLL of active lines.
154  */
155 static struct Line *lines_head;
156
157 /**
158  * Tail of DLL of active lines.
159  */
160 static struct Line *lines_tail;
161
162
163 /**
164  * Function to register a phone.
165  *
166  * @param cls closure, NULL
167  * @param client the client from which the message is
168  * @param message the message from the client
169  */
170 static void
171 handle_client_register_message (void *cls,
172                                 struct GNUNET_SERVER_Client *client,
173                                 const struct GNUNET_MessageHeader *message)
174 {
175   const struct ClientPhoneRegisterMessage *msg;
176   struct Line *line;
177
178   msg = (struct ClientPhoneRegisterMessage *) message;
179   line = GNUNET_SERVER_client_get_user_context (client, struct Line);
180   if (NULL != line)
181   {
182     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
183     return;
184   }
185   line = GNUNET_new (struct Line);
186   GNUNET_CONTAINER_DLL_insert (lines_head,
187                                lines_tail,
188                                line);
189   line->line = ntohl (msg->line);
190   GNUNET_SERVER_client_set_user_context (client, line);
191   GNUNET_SERVER_receive_done (client, GNUNET_OK);
192 }
193
194
195 /**
196  * Function to handle a pickup request message from the client
197  *
198  * @param cls closure, NULL
199  * @param client the client from which the message is
200  * @param message the message from the client
201  */
202 static void
203 handle_client_pickup_message (void *cls,
204                               struct GNUNET_SERVER_Client *client,
205                               const struct GNUNET_MessageHeader *message)
206 {
207   const struct ClientPhonePickupMessage *msg;
208
209   msg = (struct ClientPhonePickupMessage *) message;
210   GNUNET_break (0); // FIXME
211   GNUNET_SERVER_receive_done (client, GNUNET_OK);
212 }
213
214
215 /**
216  * Function to handle a hangup request message from the client
217  *
218  * @param cls closure, NULL
219  * @param client the client from which the message is
220  * @param message the message from the client
221  */
222 static void
223 handle_client_hangup_message (void *cls,
224                               struct GNUNET_SERVER_Client *client,
225                               const struct GNUNET_MessageHeader *message)
226 {
227   const struct ClientPhoneHangupMessage *msg;
228
229   msg = (struct ClientPhoneHangupMessage *) message;
230   GNUNET_break (0); // FIXME
231   GNUNET_SERVER_receive_done (client, GNUNET_OK);
232 }
233
234
235 /**
236  * Function to handle call request the client
237  *
238  * @param cls closure, NULL
239  * @param client the client from which the message is
240  * @param message the message from the client
241  */
242 static void
243 handle_client_call_message (void *cls,
244                             struct GNUNET_SERVER_Client *client,
245                             const struct GNUNET_MessageHeader *message)
246 {
247   const struct ClientCallMessage *msg;
248   struct Line *line;
249   struct GNUNET_MQ_Envelope *e;
250   struct MeshPhoneRingMessage *ring;
251
252   msg = (struct ClientCallMessage *) message;
253   line = GNUNET_SERVER_client_get_user_context (client, struct Line);
254   if (NULL != line)
255   {
256     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
257     return;
258   }
259   line = GNUNET_new (struct Line);
260   GNUNET_CONTAINER_DLL_insert (lines_head,
261                                lines_tail,
262                                line);
263   line->line = ntohl (msg->line);
264   line->status = LS_CALLER_CALLING;
265   line->tunnel_reliable = GNUNET_MESH_tunnel_create (mesh,
266                                                      line,
267                                                      &msg->target,
268                                                      GNUNET_APPLICATION_TYPE_CONVERSATION_CONTROL,
269                                                      GNUNET_NO,
270                                                      GNUNET_YES);
271   line->tunnel_unreliable = GNUNET_MESH_tunnel_create (mesh,
272                                                        line,
273                                                        &msg->target,
274                                                        GNUNET_APPLICATION_TYPE_CONVERSATION_AUDIO,
275                                                        GNUNET_YES,
276                                                        GNUNET_NO);
277   line->reliable_mq = GNUNET_MESH_mq_create (line->tunnel_reliable);
278   e = GNUNET_MQ_msg (ring, GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_RING);
279   ring->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CONVERSATION_RING);
280   ring->purpose.size = htonl (sizeof (struct GNUNET_PeerIdentity) * 2 +
281                               sizeof (struct GNUNET_TIME_AbsoluteNBO) +
282                               sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
283                               sizeof (struct GNUNET_CRYPTO_EccPublicSignKey));
284   GNUNET_CRYPTO_ecc_key_get_public_for_signature (&msg->caller_id,
285                                                   &ring->caller_id);
286   ring->line = msg->line;
287   ring->target = msg->target;
288   ring->source = my_identity;
289   ring->expiration_time = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (RING_TIMEOUT));
290   GNUNET_CRYPTO_ecc_sign (&msg->caller_id,
291                           &ring->purpose,
292                           &ring->signature);
293   GNUNET_MQ_send (line->reliable_mq, e);
294   GNUNET_SERVER_client_set_user_context (client, line);
295   GNUNET_SERVER_receive_done (client, GNUNET_OK);
296 }
297
298
299 /**
300  * Function to handle audio data from the client
301  *
302  * @param cls closure, NULL
303  * @param client the client from which the message is
304  * @param message the message from the client
305  */
306 static void
307 handle_client_audio_message (void *cls,
308                              struct GNUNET_SERVER_Client *client,
309                              const struct GNUNET_MessageHeader *message)
310 {
311   const struct ClientAudioMessage *msg;
312
313   msg = (struct ClientAudioMessage *) message;
314   GNUNET_break (0); // FIXME
315   GNUNET_SERVER_receive_done (client, GNUNET_OK);
316 }
317
318
319 /**
320  * Function to handle a ring message incoming over mesh
321  *
322  * @param cls closure, NULL
323  * @param tunnel the tunnel over which the message arrived
324  * @param tunnel_ctx the tunnel context, can be NULL
325  * @param message the incoming message
326  * @return #GNUNET_OK
327  */
328 static int
329 handle_mesh_ring_message (void *cls,
330                           struct GNUNET_MESH_Tunnel *tunnel,
331                           void **tunnel_ctx,
332                           const struct GNUNET_MessageHeader *message)
333 {
334   const struct MeshPhoneRingMessage *msg;
335   
336   msg = (const struct MeshPhoneRingMessage *) message;
337   GNUNET_break (0); // FIXME
338   return GNUNET_OK;
339 }
340
341
342 /**
343  * Function to handle a hangup message incoming over mesh
344  *
345  * @param cls closure, NULL
346  * @param tunnel the tunnel over which the message arrived
347  * @param tunnel_ctx the tunnel context, can be NULL
348  * @param message the incoming message
349  * @return #GNUNET_OK
350  */
351 static int
352 handle_mesh_hangup_message (void *cls,
353                             struct GNUNET_MESH_Tunnel *tunnel,
354                             void **tunnel_ctx,
355                             const struct GNUNET_MessageHeader *message)
356 {
357   const struct MeshPhoneHangupMessage *msg;
358   
359   msg = (const struct MeshPhoneHangupMessage *) message;
360   GNUNET_break (0); // FIXME
361   return GNUNET_OK;
362 }
363
364
365 /**
366  * Function to handle a pickup message incoming over mesh
367  *
368  * @param cls closure, NULL
369  * @param tunnel the tunnel over which the message arrived
370  * @param tunnel_ctx the tunnel context, can be NULL
371  * @param message the incoming message
372  * @return #GNUNET_OK
373  */
374 static int
375 handle_mesh_pickup_message (void *cls,
376                             struct GNUNET_MESH_Tunnel *tunnel,
377                             void **tunnel_ctx,
378                             const struct GNUNET_MessageHeader *message)
379 {
380   const struct MeshPhonePickupMessage *msg;
381   
382   msg = (const struct MeshPhonePickupMessage *) message;
383   GNUNET_break (0); // FIXME
384   return GNUNET_OK;
385 }
386
387
388 /**
389  * Function to handle a busy message incoming over mesh
390  *
391  * @param cls closure, NULL
392  * @param tunnel the tunnel over which the message arrived
393  * @param tunnel_ctx the tunnel context, can be NULL
394  * @param message the incoming message
395  * @return #GNUNET_OK
396  */
397 static int
398 handle_mesh_busy_message (void *cls,
399                           struct GNUNET_MESH_Tunnel *tunnel,
400                           void **tunnel_ctx,
401                           const struct GNUNET_MessageHeader *message)
402 {
403   const struct MeshPhoneBusyMessage *msg;
404   
405   msg = (const struct MeshPhoneBusyMessage *) message;
406   GNUNET_break (0); // FIXME
407   return GNUNET_OK;
408 }
409
410
411 /**
412  * Function to handle an audio message incoming over mesh
413  *
414  * @param cls closure, NULL
415  * @param tunnel the tunnel over which the message arrived
416  * @param tunnel_ctx the tunnel context, can be NULL
417  * @param message the incoming message
418  * @return #GNUNET_OK
419  */
420 static int
421 handle_mesh_audio_message (void *cls,
422                            struct GNUNET_MESH_Tunnel *tunnel,
423                            void **tunnel_ctx,
424                            const struct GNUNET_MessageHeader *message)
425 {
426   const struct MeshAudioMessage *msg;
427   
428   msg = (const struct MeshAudioMessage *) message;
429   GNUNET_break (0); // FIXME
430   return GNUNET_OK;
431 }
432
433
434 /**
435  * Method called whenever another peer has added us to a tunnel
436  * the other peer initiated.
437  *
438  * @param cls closure
439  * @param tunnel new handle to the tunnel
440  * @param initiator peer that started the tunnel
441  * @param port port
442  * @return initial tunnel context for the tunnel (can be NULL -- that's not an error)
443  */
444 static void *
445 inbound_tunnel (void *cls,
446                 struct GNUNET_MESH_Tunnel *tunnel,
447                 const struct GNUNET_PeerIdentity *initiator, 
448                 uint32_t port)
449 {
450   
451   GNUNET_break (0); // FIXME
452   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
453               _("Received incoming tunnel on port %d\n"), port);
454   return NULL;
455 }
456
457
458 /**
459  * Function called whenever an inbound tunnel is destroyed.  Should clean up
460  * any associated state.
461  *
462  * @param cls closure (set from #GNUNET_MESH_connect)
463  * @param tunnel connection to the other end (henceforth invalid)
464  * @param tunnel_ctx place where local state associated
465  *                   with the tunnel is stored
466  */
467 static void
468 inbound_end (void *cls,
469              const struct GNUNET_MESH_Tunnel *tunnel,
470              void *tunnel_ctx)
471 {
472   GNUNET_break (0); // FIXME
473 }
474
475
476 /**
477  * A client disconnected.  Remove all of its data structure entries.
478  *
479  * @param cls closure, NULL
480  * @param client identification of the client
481  */
482 static void
483 handle_client_disconnect (void *cls, 
484                           struct GNUNET_SERVER_Client *client)
485 {
486   struct Line *line;
487
488   line = GNUNET_SERVER_client_get_user_context (client, struct Line);
489   if (NULL == line)
490     return;
491   GNUNET_CONTAINER_DLL_remove (lines_head,
492                                lines_tail,
493                                line);
494   GNUNET_free (line);
495   GNUNET_SERVER_client_set_user_context (client, NULL);
496 }
497
498
499 /**
500  * Shutdown nicely
501  * 
502  * @param cls closure, NULL
503  * @param tc the task context
504  */
505 static void
506 do_shutdown (void *cls,
507              const struct GNUNET_SCHEDULER_TaskContext *tc)
508 {
509   GNUNET_break (0); // FIXME
510   if (NULL != mesh)
511   {
512     GNUNET_MESH_disconnect (mesh);
513     mesh = NULL;
514   }
515   if (NULL != nc)
516   {
517     GNUNET_SERVER_notification_context_destroy (nc);
518     nc = NULL;
519   }
520 }
521
522
523 /**
524  * Main function that will be run by the scheduler.
525  *
526  * @param cls closure
527  * @param server server handle
528  * @param c configuration
529  */
530 static void
531 run (void *cls, 
532      struct GNUNET_SERVER_Handle *server,
533      const struct GNUNET_CONFIGURATION_Handle *c)
534 {
535   static const struct GNUNET_SERVER_MessageHandler server_handlers[] = {
536     {&handle_client_register_message, NULL,
537      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_REGISTER,
538      sizeof (struct ClientPhoneRegisterMessage)},
539     {&handle_client_pickup_message, NULL,
540      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICK_UP,
541      0},
542     {&handle_client_hangup_message, NULL,
543      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP,
544      0},
545     {&handle_client_call_message, NULL,
546      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_CALL,
547      0},
548     {&handle_client_audio_message, NULL,
549      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO,
550      0},
551     {NULL, NULL, 0, 0}
552   };
553   static struct GNUNET_MESH_MessageHandler mesh_handlers[] = {
554     {&handle_mesh_ring_message,
555      GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_RING,
556      sizeof (struct MeshPhoneRingMessage)},
557     {&handle_mesh_hangup_message, 
558      GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_HANG_UP,
559      0},
560     {&handle_mesh_pickup_message, 
561      GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_PICK_UP,
562      0},
563     {&handle_mesh_busy_message, 
564      GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_BUSY,
565      sizeof (struct MeshPhoneBusyMessage)},
566     {&handle_mesh_audio_message, GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_AUDIO,
567      0},
568     {NULL, 0, 0}
569   };
570   static uint32_t ports[] = { 
571     GNUNET_APPLICATION_TYPE_CONVERSATION_CONTROL,
572     GNUNET_APPLICATION_TYPE_CONVERSATION_AUDIO,
573     0 
574   };
575
576   cfg = c;
577   GNUNET_assert (GNUNET_OK ==
578                  GNUNET_CRYPTO_get_host_identity (cfg,
579                                                   &my_identity));
580   mesh = GNUNET_MESH_connect (cfg,
581                               NULL,
582                               &inbound_tunnel,
583                               &inbound_end, 
584                               mesh_handlers, 
585                               ports);
586
587   if (NULL == mesh)
588   {
589     GNUNET_break (0);
590     GNUNET_SCHEDULER_shutdown ();
591     return;
592   }
593   nc = GNUNET_SERVER_notification_context_create (server, 16);
594   GNUNET_SERVER_add_handlers (server, server_handlers);
595   GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL);
596   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, 
597                                 &do_shutdown,
598                                 NULL);
599 }
600
601
602 /**
603  * The main function for the conversation service.
604  *
605  * @param argc number of arguments from the command line
606  * @param argv command line arguments
607  * @return 0 ok, 1 on error
608  */
609 int
610 main (int argc, 
611       char *const *argv)
612 {
613   return (GNUNET_OK ==
614           GNUNET_SERVICE_run (argc, argv,
615                               "conversation", 
616                               GNUNET_SERVICE_OPTION_NONE,
617                               &run, NULL)) ? 0 : 1;
618 }
619
620 /* end of gnunet-service-conversation.c */