-more control logic
[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're in shutdown, sending hangup messages before cleaning up.
68    */
69   LS_CALLEE_SHUTDOWN,
70
71   /**
72    * We are waiting for the phone to be picked up.
73    */
74   LS_CALLER_CALLING,
75
76   /**
77    * We are talking!
78    */
79   LS_CALLER_CONNECTED,
80
81   /**
82    * We're in shutdown, sending hangup messages before cleaning up.
83    */
84   LS_CALLER_SHUTDOWN
85 };
86
87
88 /**
89  * A line connects a local client with a mesh tunnel (or, if it is an
90  * open line, is waiting for a mesh tunnel).
91  */
92 struct Line
93 {
94   /**
95    * Kept in a DLL.
96    */
97   struct Line *next;
98
99   /**
100    * Kept in a DLL.
101    */
102   struct Line *prev;
103
104   /**
105    * Handle for the reliable tunnel (contol data)
106    */
107   struct GNUNET_MESH_Tunnel *tunnel_reliable;
108   
109   /**
110    * Handle for unreliable tunnel (audio data)
111    */
112   struct GNUNET_MESH_Tunnel *tunnel_unreliable;
113
114   /**
115    * Transmit handle for pending audio messages
116    */
117   struct GNUNET_MESH_TransmitHandle *unreliable_mth;
118
119   /**
120    * Message queue for control messages
121    */
122   struct GNUNET_MQ_Handle *reliable_mq;
123
124   /**
125    * Handle to the line client.
126    */
127   struct GNUNET_SERVER_Client *client;
128
129   /**
130    * Target of the line, if we are the caller.
131    */
132   struct GNUNET_PeerIdentity target;
133
134   /**
135    * Our line number.
136    */
137   uint32_t local_line;
138
139   /**
140    * Remote line number.
141    */
142   uint32_t remote_line;
143
144   /**
145    * Current status of this line.
146    */ 
147   enum LineStatus status;
148
149 };
150
151
152 /**
153  * Our configuration.
154  */
155 static const struct GNUNET_CONFIGURATION_Handle *cfg;
156
157 /**
158  * Notification context containing all connected clients.
159  */
160 static struct GNUNET_SERVER_NotificationContext *nc;
161
162 /**
163  * Handle for mesh
164  */
165 static struct GNUNET_MESH_Handle *mesh;
166
167 /**
168  * Identity of this peer.
169  */
170 static struct GNUNET_PeerIdentity my_identity;
171
172 /**
173  * Head of DLL of active lines.
174  */
175 static struct Line *lines_head;
176
177 /**
178  * Tail of DLL of active lines.
179  */
180 static struct Line *lines_tail;
181
182 /**
183  * Counter for generating local line numbers.
184  * FIXME: randomize generation in the future
185  * to eliminate information leakage.
186  */
187 static uint32_t local_line_cnt;
188
189
190 /**
191  * Function to register a phone.
192  *
193  * @param cls closure, NULL
194  * @param client the client from which the message is
195  * @param message the message from the client
196  */
197 static void
198 handle_client_register_message (void *cls,
199                                 struct GNUNET_SERVER_Client *client,
200                                 const struct GNUNET_MessageHeader *message)
201 {
202   const struct ClientPhoneRegisterMessage *msg;
203   struct Line *line;
204
205   msg = (struct ClientPhoneRegisterMessage *) message;
206   line = GNUNET_SERVER_client_get_user_context (client, struct Line);
207   if (NULL != line)
208   {
209     GNUNET_break (0);
210     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
211     return;
212   }
213   line = GNUNET_new (struct Line);
214   line->client = client;
215   GNUNET_SERVER_notification_context_add (nc, client);
216   GNUNET_CONTAINER_DLL_insert (lines_head,
217                                lines_tail,
218                                line);
219   line->local_line = ntohl (msg->line);
220   GNUNET_SERVER_client_set_user_context (client, line);
221   GNUNET_SERVER_receive_done (client, GNUNET_OK);
222 }
223
224
225 /**
226  * Function to handle a pickup request message from the client
227  *
228  * @param cls closure, NULL
229  * @param client the client from which the message is
230  * @param message the message from the client
231  */
232 static void
233 handle_client_pickup_message (void *cls,
234                               struct GNUNET_SERVER_Client *client,
235                               const struct GNUNET_MessageHeader *message)
236 {
237   const struct ClientPhonePickupMessage *msg;
238   struct GNUNET_MQ_Envelope *e;
239   struct MeshPhonePickupMessage *mppm;
240   const char *meta;
241   struct Line *line;
242   size_t len;
243
244   msg = (struct ClientPhonePickupMessage *) message;
245   meta = (const char *) &msg[1];
246   len = ntohs (msg->header.size) - sizeof (struct ClientPhonePickupMessage);
247   if ( (0 == len) ||
248        ('\0' != meta[len - 1]) )
249   {
250     meta = NULL;
251     len = 0;
252   }
253   line = GNUNET_SERVER_client_get_user_context (client, struct Line);
254   if (NULL == line)
255   {
256     GNUNET_break (0);
257     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
258     return;
259   }
260   switch (line->status)
261   {
262   case LS_CALLEE_LISTEN:
263     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
264                 "Ignoring client's PICKUP message, caller has HUNG UP already\n");
265     GNUNET_SERVER_receive_done (client, GNUNET_OK);
266     break;
267   case LS_CALLEE_RINGING:
268     line->status = LS_CALLEE_CONNECTED;
269     break;
270   case LS_CALLEE_CONNECTED:
271     GNUNET_break (0);
272     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
273     return;
274   case LS_CALLEE_SHUTDOWN:
275     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
276                 "Ignoring client's PICKUP message, line is in SHUTDOWN\n");
277     GNUNET_SERVER_receive_done (client, GNUNET_OK);
278     break;
279   case LS_CALLER_CALLING:
280   case LS_CALLER_CONNECTED:
281   case LS_CALLER_SHUTDOWN:
282     GNUNET_break (0);
283     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
284     return;
285   }
286   line->status = LS_CALLEE_CONNECTED;
287   e = GNUNET_MQ_msg_extra (mppm,
288                            len,
289                            GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_PICK_UP);
290   memcpy (&mppm[1], meta, len);
291   GNUNET_MQ_send (line->reliable_mq, e);
292   GNUNET_SERVER_receive_done (client, GNUNET_OK);
293 }
294
295
296 /**
297  * Destroy the mesh tunnels of a line.
298  *
299  * @param line line to shutdown tunnels of
300  */
301 static void
302 destroy_line_mesh_tunnels (struct Line *line)
303 {
304   if (NULL != line->reliable_mq)
305   {
306     GNUNET_MQ_destroy (line->reliable_mq);
307     line->reliable_mq = NULL;
308   }
309   if (NULL != line->tunnel_unreliable)
310   {
311     GNUNET_MESH_tunnel_destroy (line->tunnel_unreliable);
312     line->tunnel_unreliable = NULL;
313   }
314   if (NULL != line->tunnel_reliable)
315   {
316     GNUNET_MESH_tunnel_destroy (line->tunnel_reliable);
317     line->tunnel_reliable = NULL;
318   }
319 }
320
321
322 /**
323  * We are done signalling shutdown to the other peer.  Close down
324  * (or reset) the line.
325  *
326  * @param cls the `struct Line` to reset/terminate
327  */
328 static void
329 mq_done_finish_caller_shutdown (void *cls)
330 {
331   struct Line *line = cls;
332
333   switch (line->status)
334   {
335   case LS_CALLEE_LISTEN:
336     GNUNET_break (0);
337     break;
338   case LS_CALLEE_RINGING:
339     GNUNET_break (0);
340     break;
341   case LS_CALLEE_CONNECTED:
342     GNUNET_break (0);
343     break;
344   case LS_CALLEE_SHUTDOWN:
345     line->status = LS_CALLEE_LISTEN;
346     destroy_line_mesh_tunnels (line);
347     return;
348   case LS_CALLER_CALLING:
349     line->status = LS_CALLER_SHUTDOWN;
350     break;
351   case LS_CALLER_CONNECTED:
352     line->status = LS_CALLER_SHUTDOWN;
353     break;
354   case LS_CALLER_SHUTDOWN:
355     destroy_line_mesh_tunnels (line);
356     GNUNET_CONTAINER_DLL_remove (lines_head,
357                                  lines_tail,
358                                  line);
359     GNUNET_free (line);
360     break;
361   }  
362 }
363
364
365 /**
366  * Function to handle a hangup request message from the client
367  *
368  * @param cls closure, NULL
369  * @param client the client from which the message is
370  * @param message the message from the client
371  */
372 static void
373 handle_client_hangup_message (void *cls,
374                               struct GNUNET_SERVER_Client *client,
375                               const struct GNUNET_MessageHeader *message)
376 {
377   const struct ClientPhoneHangupMessage *msg;
378   struct GNUNET_MQ_Envelope *e;
379   struct MeshPhoneHangupMessage *mhum;
380   const char *meta;
381   struct Line *line;
382   size_t len;
383
384   msg = (struct ClientPhoneHangupMessage *) message;
385   meta = (const char *) &msg[1];
386   len = ntohs (msg->header.size) - sizeof (struct ClientPhoneHangupMessage);
387   if ( (0 == len) ||
388        ('\0' != meta[len - 1]) )
389   {
390     meta = NULL;
391     len = 0;
392   }
393   line = GNUNET_SERVER_client_get_user_context (client, struct Line);
394   if (NULL == line)
395   {
396     GNUNET_break (0);
397     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
398     return;
399   }
400   switch (line->status)
401   {
402   case LS_CALLEE_LISTEN:
403     GNUNET_break (0);
404     GNUNET_SERVER_receive_done (client, GNUNET_OK);
405     return;
406   case LS_CALLEE_RINGING:
407     line->status = LS_CALLEE_SHUTDOWN;
408     break;
409   case LS_CALLEE_CONNECTED:
410     line->status = LS_CALLEE_SHUTDOWN;
411     break;
412   case LS_CALLEE_SHUTDOWN:
413     GNUNET_break (0);
414     GNUNET_SERVER_receive_done (client, GNUNET_OK);
415     return;
416   case LS_CALLER_CALLING:
417     line->status = LS_CALLER_SHUTDOWN;
418     break;
419   case LS_CALLER_CONNECTED:
420     line->status = LS_CALLER_SHUTDOWN;
421     break;
422   case LS_CALLER_SHUTDOWN:
423     GNUNET_break (0);
424     GNUNET_SERVER_receive_done (client, GNUNET_OK);
425     return;
426   }
427   e = GNUNET_MQ_msg_extra (mhum,
428                            len,
429                            GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_HANG_UP);
430   memcpy (&mhum[1], meta, len);
431   GNUNET_MQ_notify_sent (e,
432                          &mq_done_finish_caller_shutdown,
433                          line);
434   GNUNET_MQ_send (line->reliable_mq, e);
435   GNUNET_SERVER_receive_done (client, GNUNET_OK);
436 }
437
438
439 /**
440  * Function to handle call request the client
441  *
442  * @param cls closure, NULL
443  * @param client the client from which the message is
444  * @param message the message from the client
445  */
446 static void
447 handle_client_call_message (void *cls,
448                             struct GNUNET_SERVER_Client *client,
449                             const struct GNUNET_MessageHeader *message)
450 {
451   const struct ClientCallMessage *msg;
452   struct Line *line;
453   struct GNUNET_MQ_Envelope *e;
454   struct MeshPhoneRingMessage *ring;
455
456   msg = (struct ClientCallMessage *) message;
457   line = GNUNET_SERVER_client_get_user_context (client, struct Line);
458   if (NULL != line)
459   {
460     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
461     return;
462   }
463   line = GNUNET_new (struct Line);
464   line->target = msg->target;
465   GNUNET_CONTAINER_DLL_insert (lines_head,
466                                lines_tail,
467                                line);
468   line->remote_line = ntohl (msg->line);
469   line->status = LS_CALLER_CALLING;
470   line->tunnel_reliable = GNUNET_MESH_tunnel_create (mesh,
471                                                      line,
472                                                      &msg->target,
473                                                      GNUNET_APPLICATION_TYPE_CONVERSATION_CONTROL,
474                                                      GNUNET_NO,
475                                                      GNUNET_YES);
476   line->reliable_mq = GNUNET_MESH_mq_create (line->tunnel_reliable);
477   line->local_line = local_line_cnt++;
478   e = GNUNET_MQ_msg (ring, GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_RING);
479   ring->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CONVERSATION_RING);
480   ring->purpose.size = htonl (sizeof (struct GNUNET_PeerIdentity) * 2 +
481                               sizeof (struct GNUNET_TIME_AbsoluteNBO) +
482                               sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
483                               sizeof (struct GNUNET_CRYPTO_EccPublicSignKey));
484   GNUNET_CRYPTO_ecc_key_get_public_for_signature (&msg->caller_id,
485                                                   &ring->caller_id);
486   ring->remote_line = msg->line;
487   ring->source_line = line->local_line;
488   ring->target = msg->target;
489   ring->source = my_identity;
490   ring->expiration_time = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (RING_TIMEOUT));
491   GNUNET_CRYPTO_ecc_sign (&msg->caller_id,
492                           &ring->purpose,
493                           &ring->signature);
494   GNUNET_MQ_send (line->reliable_mq, e);
495   GNUNET_SERVER_client_set_user_context (client, line);
496   GNUNET_SERVER_receive_done (client, GNUNET_OK);
497 }
498
499
500 /**
501  * Function to handle audio data from the client
502  *
503  * @param cls closure, NULL
504  * @param client the client from which the message is
505  * @param message the message from the client
506  */
507 static void
508 handle_client_audio_message (void *cls,
509                              struct GNUNET_SERVER_Client *client,
510                              const struct GNUNET_MessageHeader *message)
511 {
512   const struct ClientAudioMessage *msg;
513
514   msg = (struct ClientAudioMessage *) message;
515   GNUNET_break (0); // FIXME
516   GNUNET_SERVER_receive_done (client, GNUNET_OK);
517 }
518
519
520 /**
521  * We are done signalling shutdown to the other peer.  
522  * Destroy the tunnel.
523  *
524  * @param cls the `struct GNUNET_MESH_tunnel` to destroy
525  */
526 static void
527 mq_done_destroy_tunnel (void *cls)
528 {
529   struct GNUNET_MESH_Tunnel *tunnel = cls;
530   
531   GNUNET_MESH_tunnel_destroy (tunnel);
532 }
533
534
535 /**
536  * Function to handle a ring message incoming over mesh
537  *
538  * @param cls closure, NULL
539  * @param tunnel the tunnel over which the message arrived
540  * @param tunnel_ctx the tunnel context, can be NULL
541  * @param message the incoming message
542  * @return #GNUNET_OK
543  */
544 static int
545 handle_mesh_ring_message (void *cls,
546                           struct GNUNET_MESH_Tunnel *tunnel,
547                           void **tunnel_ctx,
548                           const struct GNUNET_MessageHeader *message)
549 {
550   const struct MeshPhoneRingMessage *msg;
551   struct Line *line;
552   struct GNUNET_MQ_Envelope *e;
553   struct MeshPhoneBusyMessage *busy;
554   struct ClientPhoneRingMessage cring;
555   
556   msg = (const struct MeshPhoneRingMessage *) message;
557   if ( (msg->purpose.size != htonl (sizeof (struct GNUNET_PeerIdentity) * 2 +
558                                     sizeof (struct GNUNET_TIME_AbsoluteNBO) +
559                                     sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
560                                     sizeof (struct GNUNET_CRYPTO_EccPublicSignKey))) ||
561        (GNUNET_OK !=
562         GNUNET_CRYPTO_ecc_verify (GNUNET_SIGNATURE_PURPOSE_CONVERSATION_RING,
563                                   &msg->purpose,
564                                   &msg->signature,
565                                   &msg->caller_id)) )
566   {
567     GNUNET_break_op (0);
568     return GNUNET_SYSERR;
569   }
570   for (line = lines_head; NULL != line; line = line->next)  
571     if ( (line->local_line == ntohl (msg->remote_line)) &&
572          (LS_CALLEE_LISTEN == line->status) )
573       break;
574   if (NULL == line) 
575   {
576     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
577                 _("No available phone for incoming call on line %u, sending BUSY signal\n"),
578                 ntohl (msg->remote_line));
579     e = GNUNET_MQ_msg (busy, GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_BUSY);
580     GNUNET_MQ_notify_sent (e,
581                            &mq_done_destroy_tunnel,
582                            tunnel);
583     GNUNET_MQ_send (line->reliable_mq, e);
584     GNUNET_MESH_receive_done (tunnel); /* needed? */
585     return GNUNET_OK;
586   }
587   line->status = LS_CALLEE_RINGING;
588   line->remote_line = ntohl (msg->source_line);
589   line->tunnel_reliable = tunnel;
590   line->reliable_mq = GNUNET_MESH_mq_create (line->tunnel_reliable);
591   *tunnel_ctx = line;
592   cring.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RING);
593   cring.header.size = htons (sizeof (cring));
594   cring.reserved = htonl (0);
595   cring.caller_id = msg->caller_id;
596   GNUNET_SERVER_notification_context_unicast (nc,
597                                               line->client,
598                                               &cring.header,
599                                               GNUNET_NO);
600   GNUNET_MESH_receive_done (tunnel);
601   return GNUNET_OK;
602 }
603
604
605 /**
606  * Function to handle a hangup message incoming over mesh
607  *
608  * @param cls closure, NULL
609  * @param tunnel the tunnel over which the message arrived
610  * @param tunnel_ctx the tunnel context, can be NULL
611  * @param message the incoming message
612  * @return #GNUNET_OK
613  */
614 static int
615 handle_mesh_hangup_message (void *cls,
616                             struct GNUNET_MESH_Tunnel *tunnel,
617                             void **tunnel_ctx,
618                             const struct GNUNET_MessageHeader *message)
619 {
620   struct Line *line = *tunnel_ctx;
621   const struct MeshPhoneHangupMessage *msg;
622   const char *reason;
623   size_t len = ntohs (message->size) - sizeof (struct MeshPhoneHangupMessage);
624   char buf[len + sizeof (struct ClientPhoneHangupMessage)];
625   struct ClientPhoneHangupMessage *hup;
626   
627   msg = (const struct MeshPhoneHangupMessage *) message;
628   len = ntohs (msg->header.size) - sizeof (struct MeshPhoneHangupMessage);
629   reason = (const char *) &msg[1];
630   if ( (0 == len) ||
631        ('\0' != reason[len - 1]) )
632   {
633     reason = NULL;
634     len = 0;
635   }
636   if (NULL == line)
637   {
638     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
639                 "HANGUP message received for non-existing line, dropping tunnel.\n");
640     return GNUNET_SYSERR;
641   }
642   hup = (struct ClientPhoneHangupMessage *) buf;
643   hup->header.size = sizeof (buf);
644   hup->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP);
645   memcpy (&hup[1], reason, len);
646   GNUNET_SERVER_notification_context_unicast (nc,
647                                               line->client,
648                                               &hup->header,
649                                               GNUNET_NO);
650   GNUNET_MESH_receive_done (tunnel);
651   *tunnel_ctx = NULL;
652   switch (line->status)
653   {
654   case LS_CALLEE_LISTEN:
655     GNUNET_break (0);
656     return GNUNET_SYSERR;
657   case LS_CALLEE_RINGING:
658     line->status = LS_CALLEE_LISTEN;
659     destroy_line_mesh_tunnels (line);
660     break;
661   case LS_CALLEE_CONNECTED:
662     line->status = LS_CALLEE_LISTEN;
663     destroy_line_mesh_tunnels (line);
664     break;
665   case LS_CALLEE_SHUTDOWN:
666     line->status = LS_CALLEE_LISTEN;
667     destroy_line_mesh_tunnels (line);
668     break;
669   case LS_CALLER_CALLING:
670     line->status = LS_CALLER_SHUTDOWN;
671     mq_done_finish_caller_shutdown (line);
672     break;
673   case LS_CALLER_CONNECTED:
674     line->status = LS_CALLER_SHUTDOWN;
675     mq_done_finish_caller_shutdown (line);
676     break;
677   case LS_CALLER_SHUTDOWN:
678     mq_done_finish_caller_shutdown (line);
679     break;
680   }
681   return GNUNET_OK;
682 }
683
684
685 /**
686  * Function to handle a pickup message incoming over mesh
687  *
688  * @param cls closure, NULL
689  * @param tunnel the tunnel over which the message arrived
690  * @param tunnel_ctx the tunnel context, can be NULL
691  * @param message the incoming message
692  * @return #GNUNET_OK
693  */
694 static int
695 handle_mesh_pickup_message (void *cls,
696                             struct GNUNET_MESH_Tunnel *tunnel,
697                             void **tunnel_ctx,
698                             const struct GNUNET_MessageHeader *message)
699 {
700   const struct MeshPhonePickupMessage *msg;
701   struct Line *line = *tunnel_ctx;
702   
703   msg = (const struct MeshPhonePickupMessage *) message;
704   GNUNET_break (0); // FIXME
705
706
707   line->tunnel_unreliable = GNUNET_MESH_tunnel_create (mesh,
708                                                        line,
709                                                        &line->target,
710                                                        GNUNET_APPLICATION_TYPE_CONVERSATION_AUDIO,
711                                                        GNUNET_YES,
712                                                        GNUNET_NO);
713   
714
715   GNUNET_MESH_receive_done (tunnel);
716   return GNUNET_OK;
717 }
718
719
720 /**
721  * Function to handle a busy message incoming over mesh
722  *
723  * @param cls closure, NULL
724  * @param tunnel the tunnel over which the message arrived
725  * @param tunnel_ctx the tunnel context, can be NULL
726  * @param message the incoming message
727  * @return #GNUNET_OK
728  */
729 static int
730 handle_mesh_busy_message (void *cls,
731                           struct GNUNET_MESH_Tunnel *tunnel,
732                           void **tunnel_ctx,
733                           const struct GNUNET_MessageHeader *message)
734 {
735   struct Line *line = *tunnel_ctx;
736   const struct MeshPhoneBusyMessage *msg;
737   struct ClientPhoneBusyMessage busy;
738   
739   msg = (const struct MeshPhoneBusyMessage *) message;
740   if (NULL == line)
741   {
742     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
743                 "HANGUP message received for non-existing line, dropping tunnel.\n");
744     return GNUNET_SYSERR;
745   }
746   busy.header.size = sizeof (busy);
747   busy.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_BUSY);
748   GNUNET_SERVER_notification_context_unicast (nc,
749                                               line->client,
750                                               &busy.header,
751                                               GNUNET_NO);
752   GNUNET_MESH_receive_done (tunnel);
753   *tunnel_ctx = NULL;
754   switch (line->status)
755   {
756   case LS_CALLEE_LISTEN:
757     GNUNET_break (0);
758     return GNUNET_SYSERR;
759   case LS_CALLEE_RINGING:
760     GNUNET_break_op (0);
761     break;
762   case LS_CALLEE_CONNECTED:
763     GNUNET_break_op (0);
764     break;
765   case LS_CALLEE_SHUTDOWN:
766     GNUNET_break_op (0);
767     break;
768   case LS_CALLER_CALLING:
769     line->status = LS_CALLER_SHUTDOWN;
770     mq_done_finish_caller_shutdown (line);
771     break;
772   case LS_CALLER_CONNECTED:
773     line->status = LS_CALLER_SHUTDOWN;
774     mq_done_finish_caller_shutdown (line);
775     break;
776   case LS_CALLER_SHUTDOWN:
777     mq_done_finish_caller_shutdown (line);
778     break;
779   }
780   return GNUNET_OK;
781 }
782
783
784 /**
785  * Function to handle an audio message incoming over mesh
786  *
787  * @param cls closure, NULL
788  * @param tunnel the tunnel over which the message arrived
789  * @param tunnel_ctx the tunnel context, can be NULL
790  * @param message the incoming message
791  * @return #GNUNET_OK
792  */
793 static int
794 handle_mesh_audio_message (void *cls,
795                            struct GNUNET_MESH_Tunnel *tunnel,
796                            void **tunnel_ctx,
797                            const struct GNUNET_MessageHeader *message)
798 {
799   const struct MeshAudioMessage *msg;
800   
801   msg = (const struct MeshAudioMessage *) message;
802   GNUNET_break (0); // FIXME
803   GNUNET_MESH_receive_done (tunnel);
804   return GNUNET_OK;
805 }
806
807
808 /**
809  * Method called whenever another peer has added us to a tunnel
810  * the other peer initiated.
811  *
812  * @param cls closure
813  * @param tunnel new handle to the tunnel
814  * @param initiator peer that started the tunnel
815  * @param port port
816  * @return initial tunnel context for the tunnel (can be NULL -- that's not an error)
817  */
818 static void *
819 inbound_tunnel (void *cls,
820                 struct GNUNET_MESH_Tunnel *tunnel,
821                 const struct GNUNET_PeerIdentity *initiator, 
822                 uint32_t port)
823 {
824   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
825               _("Received incoming tunnel on port %d\n"), 
826               port);
827   return NULL;
828 }
829
830
831 /**
832  * Function called whenever an inbound tunnel is destroyed.  Should clean up
833  * any associated state.
834  *
835  * @param cls closure (set from #GNUNET_MESH_connect)
836  * @param tunnel connection to the other end (henceforth invalid)
837  * @param tunnel_ctx place where local state associated
838  *                   with the tunnel is stored
839  */
840 static void
841 inbound_end (void *cls,
842              const struct GNUNET_MESH_Tunnel *tunnel,
843              void *tunnel_ctx)
844 {
845   struct Line *line = tunnel_ctx;
846   struct ClientPhoneHangupMessage hup;
847
848   if (NULL == line)
849     return;
850   if (line->tunnel_unreliable == tunnel)
851   {
852     line->tunnel_unreliable = NULL;
853     return;
854   }
855   hup.header.size = sizeof (hup);
856   hup.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP);
857   switch (line->status)
858   {
859   case LS_CALLEE_LISTEN:
860     GNUNET_break (0);
861     return;
862   case LS_CALLEE_RINGING:
863   case LS_CALLEE_CONNECTED:
864     GNUNET_SERVER_notification_context_unicast (nc,
865                                                 line->client,
866                                                 &hup.header,
867                                                 GNUNET_NO);
868     line->status = LS_CALLEE_LISTEN;
869     break;
870   case LS_CALLEE_SHUTDOWN:
871     line->status = LS_CALLEE_LISTEN;
872     destroy_line_mesh_tunnels (line);
873     break;
874   case LS_CALLER_CALLING:
875   case LS_CALLER_CONNECTED:
876     GNUNET_SERVER_notification_context_unicast (nc,
877                                                 line->client,
878                                                 &hup.header,
879                                                 GNUNET_NO);
880     destroy_line_mesh_tunnels (line);
881     GNUNET_CONTAINER_DLL_remove (lines_head,
882                                  lines_tail,
883                                  line);
884     GNUNET_free (line);
885     break;
886   case LS_CALLER_SHUTDOWN:
887     destroy_line_mesh_tunnels (line);
888     GNUNET_CONTAINER_DLL_remove (lines_head,
889                                  lines_tail,
890                                  line);
891     GNUNET_free (line);
892     break;
893   }
894 }
895
896
897 /**
898  * A client disconnected.  Remove all of its data structure entries.
899  *
900  * @param cls closure, NULL
901  * @param client identification of the client
902  */
903 static void
904 handle_client_disconnect (void *cls, 
905                           struct GNUNET_SERVER_Client *client)
906 {
907   struct Line *line;
908
909   line = GNUNET_SERVER_client_get_user_context (client, struct Line);
910   if (NULL == line)
911     return;
912   GNUNET_CONTAINER_DLL_remove (lines_head,
913                                lines_tail,
914                                line);
915   GNUNET_free (line);
916   GNUNET_SERVER_client_set_user_context (client, NULL);
917 }
918
919
920 /**
921  * Shutdown nicely
922  * 
923  * @param cls closure, NULL
924  * @param tc the task context
925  */
926 static void
927 do_shutdown (void *cls,
928              const struct GNUNET_SCHEDULER_TaskContext *tc)
929 {
930   if (NULL != mesh)
931   {
932     GNUNET_MESH_disconnect (mesh);
933     mesh = NULL;
934   }
935   if (NULL != nc)
936   {
937     GNUNET_SERVER_notification_context_destroy (nc);
938     nc = NULL;
939   }
940 }
941
942
943 /**
944  * Main function that will be run by the scheduler.
945  *
946  * @param cls closure
947  * @param server server handle
948  * @param c configuration
949  */
950 static void
951 run (void *cls, 
952      struct GNUNET_SERVER_Handle *server,
953      const struct GNUNET_CONFIGURATION_Handle *c)
954 {
955   static const struct GNUNET_SERVER_MessageHandler server_handlers[] = {
956     {&handle_client_register_message, NULL,
957      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_REGISTER,
958      sizeof (struct ClientPhoneRegisterMessage)},
959     {&handle_client_pickup_message, NULL,
960      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICK_UP,
961      0},
962     {&handle_client_hangup_message, NULL,
963      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP,
964      0},
965     {&handle_client_call_message, NULL,
966      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_CALL,
967      0},
968     {&handle_client_audio_message, NULL,
969      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO,
970      0},
971     {NULL, NULL, 0, 0}
972   };
973   static struct GNUNET_MESH_MessageHandler mesh_handlers[] = {
974     {&handle_mesh_ring_message,
975      GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_RING,
976      sizeof (struct MeshPhoneRingMessage)},
977     {&handle_mesh_hangup_message, 
978      GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_HANG_UP,
979      0},
980     {&handle_mesh_pickup_message, 
981      GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_PICK_UP,
982      0},
983     {&handle_mesh_busy_message, 
984      GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_BUSY,
985      sizeof (struct MeshPhoneBusyMessage)},
986     {&handle_mesh_audio_message, GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_AUDIO,
987      0},
988     {NULL, 0, 0}
989   };
990   static uint32_t ports[] = { 
991     GNUNET_APPLICATION_TYPE_CONVERSATION_CONTROL,
992     GNUNET_APPLICATION_TYPE_CONVERSATION_AUDIO,
993     0 
994   };
995
996   cfg = c;
997   GNUNET_assert (GNUNET_OK ==
998                  GNUNET_CRYPTO_get_host_identity (cfg,
999                                                   &my_identity));
1000   mesh = GNUNET_MESH_connect (cfg,
1001                               NULL,
1002                               &inbound_tunnel,
1003                               &inbound_end, 
1004                               mesh_handlers, 
1005                               ports);
1006
1007   if (NULL == mesh)
1008   {
1009     GNUNET_break (0);
1010     GNUNET_SCHEDULER_shutdown ();
1011     return;
1012   }
1013   nc = GNUNET_SERVER_notification_context_create (server, 16);
1014   GNUNET_SERVER_add_handlers (server, server_handlers);
1015   GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL);
1016   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, 
1017                                 &do_shutdown,
1018                                 NULL);
1019 }
1020
1021
1022 /**
1023  * The main function for the conversation service.
1024  *
1025  * @param argc number of arguments from the command line
1026  * @param argv command line arguments
1027  * @return 0 ok, 1 on error
1028  */
1029 int
1030 main (int argc, 
1031       char *const *argv)
1032 {
1033   return (GNUNET_OK ==
1034           GNUNET_SERVICE_run (argc, argv,
1035                               "conversation", 
1036                               GNUNET_SERVICE_OPTION_NONE,
1037                               &run, NULL)) ? 0 : 1;
1038 }
1039
1040 /* end of gnunet-service-conversation.c */