log: add \n
[oweals/gnunet.git] / src / conversation / test_conversation_api_twocalls.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2013 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/test_conversation_api_twocalls.c
22  * @brief testcase for conversation_api.c
23  *
24  * This test performs the operations of TWO calls made to a phone
25  * where the phone user picks up one, suspends it, picks up the
26  * second one; eventually, the initiator hangs up, the callee
27  * resumes the first call, and then the initiator hangs up the
28  * second call.
29  */
30 #include "platform.h"
31 #include "gnunet_util_lib.h"
32 #include "gnunet_testing_lib.h"
33 #include "gnunet_gnsrecord_lib.h"
34 #include "gnunet_conversation_service.h"
35 #include "gnunet_identity_service.h"
36 #include "gnunet_namestore_service.h"
37
38 #define FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 250)
39
40 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 25)
41
42 #define LOG(kind,...)                           \
43   GNUNET_log (kind, __VA_ARGS__)
44
45 #define LOG_DEBUG(...)                          \
46   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
47
48 static const struct GNUNET_CONFIGURATION_Handle *cfg;
49
50 static struct GNUNET_IDENTITY_Handle *id;
51
52 static struct GNUNET_IDENTITY_Operation *op;
53
54 static struct GNUNET_CONVERSATION_Phone *phone;
55
56 static struct GNUNET_NAMESTORE_Handle *ns;
57
58 static struct GNUNET_CONVERSATION_Call *call1;
59
60 static struct GNUNET_CONVERSATION_Call *call2;
61
62 static struct GNUNET_NAMESTORE_QueueEntry *qe;
63
64 static struct GNUNET_CONVERSATION_Caller *active_caller1;
65
66 static struct GNUNET_CONVERSATION_Caller *active_caller2;
67
68 static char *gns_name;
69
70 static char *gns_caller_id;
71
72 static GNUNET_MICROPHONE_RecordedDataCallback phone_rdc;
73
74 static void *phone_rdc_cls;
75
76 static struct GNUNET_SCHEDULER_Task *phone_task;
77
78 static struct GNUNET_SCHEDULER_Task *timeout_task;
79
80 /**
81  * Variable for recognizing caller1
82  */
83 static const char *caller1 = "caller1";
84
85 /**
86  * Variable for recognizing caller2
87  */
88 static const char *caller2 = "caller2";
89
90 /**
91  * Variable for recognizing callee
92  */
93 static const char *phone0 = "phone";
94
95
96 #define CALLER1 &caller1
97 #define CALLER2 &caller2
98 #define PHONE0 &phone0
99
100 #define CLS_STR(caller) (*((char **)caller))
101
102
103 /**
104  * Did caller1 call finish successfully
105  */
106 static int call1_finished;
107
108 /**
109  * Did caller2 call finish successfully
110  */
111 static int call2_finished;
112
113 struct MicContext
114 {
115   GNUNET_MICROPHONE_RecordedDataCallback rdc;
116
117   void *rdc_cls;
118
119   struct GNUNET_SCHEDULER_Task * call_task;
120
121 };
122
123 static struct MicContext call1_mic_ctx;
124 static struct MicContext call2_mic_ctx;
125 //static struct MicContext phone_mic_ctx;
126
127
128 static void
129 phone_send (void *cls)
130 {
131   char buf[32];
132
133   GNUNET_assert (NULL != phone_rdc);
134   GNUNET_snprintf (buf, sizeof (buf), "phone");
135   phone_rdc (phone_rdc_cls, strlen (buf) + 1, buf);
136   phone_task = GNUNET_SCHEDULER_add_delayed (FREQ,
137                                              &phone_send, NULL);
138 }
139
140
141 static void
142 call_send (void *cls)
143 {
144   struct MicContext *mc = cls;
145   char buf[32];
146
147   GNUNET_assert (NULL != mc->rdc);
148   GNUNET_snprintf (buf, sizeof (buf), "call");
149   mc->rdc (mc->rdc_cls, strlen (buf) + 1, buf);
150   mc->call_task = GNUNET_SCHEDULER_add_delayed (FREQ,
151                                                 &call_send, mc);
152 }
153
154
155 static int
156 enable_speaker (void *cls)
157 {
158   const char *origin = CLS_STR (cls);
159
160   LOG_DEBUG ("Speaker %s enabled\n",
161              origin);
162   return GNUNET_OK;
163 }
164
165
166 static void
167 disable_speaker (void *cls)
168 {
169   const char *origin = CLS_STR (cls);
170
171   LOG_DEBUG ("Speaker %s disabled\n",
172              origin);
173 }
174
175
176 static void
177 play (void *cls,
178       size_t data_size,
179       const void *data)
180 {
181   static unsigned int phone_i;
182   static unsigned int call_i;
183
184   if (0 == strncmp ("call", data, data_size))
185     call_i++;
186   else if (0 == strncmp ("phone", data, data_size))
187     phone_i++;
188   else
189   {
190     LOG_DEBUG ("Received unexpected data %.*s\n",
191                (int) data_size,
192                (const char *) data);
193   }
194
195   if ( (20 < call_i) &&
196        (20 < phone_i) &&
197        (CALLER2 == cls) )
198   {
199     /* time to hang up ... */
200     GNUNET_CONVERSATION_call_stop (call2);
201     call2 = NULL;
202     /* reset counters */
203     call_i = 0;
204     phone_i = 0;
205     call2_finished = GNUNET_YES;
206   }
207   if ( (20 < call_i) &&
208        (20 < phone_i) &&
209        (CALLER1 == cls) )
210   {
211     /* time to hang up ... */
212     GNUNET_CONVERSATION_call_stop (call1);
213     call1 = NULL;
214     call_i = 0;
215     phone_i = 0;
216     call1_finished = GNUNET_YES;
217   }
218 }
219
220
221 static void
222 destroy_speaker (void *cls)
223 {
224   const char *origin = CLS_STR (cls);
225
226   LOG_DEBUG ("Speaker %s destroyed\n", origin);
227 }
228
229
230 static struct GNUNET_SPEAKER_Handle call1_speaker = {
231   &enable_speaker,
232   &play,
233   &disable_speaker,
234   &destroy_speaker,
235   CALLER1
236 };
237
238
239 static struct GNUNET_SPEAKER_Handle call2_speaker = {
240   &enable_speaker,
241   &play,
242   &disable_speaker,
243   &destroy_speaker,
244   CALLER2
245 };
246
247
248 static struct GNUNET_SPEAKER_Handle phone_speaker = {
249   &enable_speaker,
250   &play,
251   &disable_speaker,
252   &destroy_speaker,
253   PHONE0
254 };
255
256
257 static int
258 enable_mic (void *cls,
259             GNUNET_MICROPHONE_RecordedDataCallback rdc,
260             void *rdc_cls)
261 {
262   const char *origin = CLS_STR (cls);
263   struct MicContext *mc;
264
265   LOG_DEBUG ("Mic %s enabled\n",
266              origin);
267   if (PHONE0 == cls)
268   {
269     phone_rdc = rdc;
270     phone_rdc_cls = rdc_cls;
271     GNUNET_break (NULL == phone_task);
272     phone_task = GNUNET_SCHEDULER_add_now (&phone_send, NULL);
273     return GNUNET_OK;
274   }
275   mc = (CALLER1 == cls) ? &call1_mic_ctx : &call2_mic_ctx;
276   mc->rdc = rdc;
277   mc->rdc_cls = rdc_cls;
278   GNUNET_break (NULL == mc->call_task);
279   mc->call_task = GNUNET_SCHEDULER_add_now (&call_send, mc);
280   return GNUNET_OK;
281 }
282
283
284 static void
285 disable_mic (void *cls)
286 {
287   const char *origin = CLS_STR (cls);
288   struct MicContext *mc;
289
290   LOG_DEBUG ("Mic %s disabled\n",
291              origin);
292   if (PHONE0 == cls)
293   {
294     phone_rdc = NULL;
295     phone_rdc_cls = NULL;
296     GNUNET_SCHEDULER_cancel (phone_task);
297     phone_task = NULL;
298     return;
299   }
300   mc = (CALLER1 == cls) ? &call1_mic_ctx : &call2_mic_ctx;
301   mc->rdc = NULL;
302   mc->rdc_cls = NULL;
303   GNUNET_SCHEDULER_cancel (mc->call_task);
304   mc->call_task = NULL;
305 }
306
307
308 static void
309 destroy_mic (void *cls)
310 {
311   const char *origin = CLS_STR (cls);
312
313   LOG_DEBUG ("Mic %s destroyed\n",
314              origin);
315 }
316
317
318 static struct GNUNET_MICROPHONE_Handle call1_mic = {
319   &enable_mic,
320   &disable_mic,
321   &destroy_mic,
322   CALLER1
323 };
324
325
326 static struct GNUNET_MICROPHONE_Handle call2_mic = {
327   &enable_mic,
328   &disable_mic,
329   &destroy_mic,
330   CALLER2
331 };
332
333
334 static struct GNUNET_MICROPHONE_Handle phone_mic = {
335   &enable_mic,
336   &disable_mic,
337   &destroy_mic,
338   PHONE0
339 };
340
341
342 /**
343  * Function run on timeout.
344  *
345  * @param cls closure
346  */
347 static void
348 end_test (void *cls)
349 {
350   timeout_task = NULL;
351   fprintf (stderr,
352            "Timeout!\n");
353   GNUNET_SCHEDULER_shutdown ();
354 }
355
356
357 /**
358  * Function run on shutdown.
359  *
360  * @param cls closure
361  */
362 static void
363 do_shutdown (void *cls)
364 {
365   if (NULL != timeout_task)
366   {
367     GNUNET_SCHEDULER_cancel (timeout_task);
368     timeout_task = NULL;
369   }
370   if (NULL != op)
371   {
372     GNUNET_IDENTITY_cancel (op);
373     op = NULL;
374   }
375   if (NULL != call1)
376   {
377     GNUNET_CONVERSATION_call_stop (call1);
378     call1 = NULL;
379   }
380   if (NULL != call2)
381   {
382     GNUNET_CONVERSATION_call_stop (call2);
383     call2 = NULL;
384   }
385   if (NULL != phone)
386   {
387     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from PHONE service.\n");
388     GNUNET_CONVERSATION_phone_destroy (phone);
389     phone = NULL;
390   }
391   if (NULL != id)
392   {
393     GNUNET_IDENTITY_disconnect (id);
394     id = NULL;
395   }
396   if (NULL != qe)
397   {
398     GNUNET_NAMESTORE_cancel (qe);
399     qe = NULL;
400   }
401   if (NULL != ns)
402   {
403     GNUNET_NAMESTORE_disconnect (ns);
404     ns = NULL;
405   }
406 }
407
408
409 static void
410 caller_event_handler (void *cls,
411                       enum GNUNET_CONVERSATION_CallerEventCode code)
412 {
413   switch (code)
414   {
415   case GNUNET_CONVERSATION_EC_CALLER_SUSPEND:
416   case GNUNET_CONVERSATION_EC_CALLER_RESUME:
417     LOG (GNUNET_ERROR_TYPE_WARNING, "Unexpected caller code: %d\n", code);
418     break;
419   }
420 }
421
422
423 static void
424 phone_event_handler (void *cls,
425                      enum GNUNET_CONVERSATION_PhoneEventCode code,
426                      struct GNUNET_CONVERSATION_Caller *caller,
427                      const struct GNUNET_CRYPTO_EcdsaPublicKey *caller_id)
428 {
429   const char *cid;
430
431   switch (code)
432   {
433   case GNUNET_CONVERSATION_EC_PHONE_RING:
434     if (NULL == active_caller1)
435     {
436       active_caller1 = caller;
437       cid = "caller1";
438       GNUNET_CONVERSATION_caller_pick_up (caller,
439                                           &caller_event_handler,
440                                           (void *) cid,
441                                           &phone_speaker,
442                                           &phone_mic);
443     }
444     else
445     {
446       GNUNET_CONVERSATION_caller_suspend (active_caller1);
447       active_caller2 = caller;
448       cid = "caller2";
449       GNUNET_CONVERSATION_caller_pick_up (caller,
450                                           &caller_event_handler,
451                                           (void *) cid,
452                                           &phone_speaker,
453                                           &phone_mic);
454     }
455     break;
456   case GNUNET_CONVERSATION_EC_PHONE_HUNG_UP:
457     if (caller == active_caller2)
458     {
459       active_caller2 = NULL;
460       GNUNET_CONVERSATION_caller_resume (active_caller1,
461                                          &phone_speaker,
462                                          &phone_mic);
463     }
464     else if (caller == active_caller1)
465     {
466       active_caller1 = NULL;
467       GNUNET_break (NULL == active_caller2);
468       GNUNET_SCHEDULER_shutdown ();
469     }
470     break;
471   default:
472     LOG (GNUNET_ERROR_TYPE_WARNING, "Unexpected phone code: %d\n", code);
473     break;
474   }
475 }
476
477
478 static void
479 call_event_handler (void *cls,
480                     enum GNUNET_CONVERSATION_CallEventCode code)
481 {
482   const char *cid = cls;
483
484   switch (code)
485   {
486   case GNUNET_CONVERSATION_EC_CALL_RINGING:
487     break;
488   case GNUNET_CONVERSATION_EC_CALL_PICKED_UP:
489     LOG_DEBUG ("Call %s picked\n", cid);
490     break;
491   case GNUNET_CONVERSATION_EC_CALL_GNS_FAIL:
492     LOG_DEBUG ("Call %s GNS lookup failed \n", cid);
493     break;
494   case GNUNET_CONVERSATION_EC_CALL_HUNG_UP:
495     LOG_DEBUG ("Call %s hungup\n", cid);
496     if (0 == strcmp (cid, "call1"))
497       call1 = NULL;
498     else
499       call2 = NULL;
500     break;
501   case GNUNET_CONVERSATION_EC_CALL_SUSPENDED:
502     LOG_DEBUG ("Call %s suspended\n", cid);
503     break;
504   case GNUNET_CONVERSATION_EC_CALL_RESUMED:
505     LOG_DEBUG ("Call %s resumed\n", cid);
506     break;
507   case GNUNET_CONVERSATION_EC_CALL_ERROR:
508     GNUNET_break (0);
509     if (0 == strcmp (cid, "call1"))
510       call1 = NULL;
511     else
512       call2 = NULL;
513     GNUNET_SCHEDULER_shutdown ();
514     break;
515   }
516 }
517
518
519 static void
520 caller_ego_create_cont (void *cls,
521                         const char *emsg)
522 {
523   op = NULL;
524   GNUNET_assert (NULL == emsg);
525 }
526
527
528 static void
529 namestore_put_cont (void *cls,
530                     int32_t success,
531                     const char *emsg)
532 {
533   qe = NULL;
534   GNUNET_assert (GNUNET_YES == success);
535   GNUNET_assert (NULL == emsg);
536   GNUNET_assert (NULL == op);
537   op = GNUNET_IDENTITY_create (id, "caller-ego", &caller_ego_create_cont, NULL);
538 }
539
540
541 static void
542 identity_cb (void *cls,
543              struct GNUNET_IDENTITY_Ego *ego,
544              void **ctx,
545              const char *name)
546 {
547   struct GNUNET_GNSRECORD_Data rd;
548   struct GNUNET_CRYPTO_EcdsaPublicKey pub;
549
550   if (NULL == name)
551     return;
552   if (NULL == ego)
553     return;
554   if (0 == strcmp (name, "phone-ego"))
555   {
556     GNUNET_IDENTITY_ego_get_public_key (ego, &pub);
557     GNUNET_asprintf (&gns_name,
558                      "phone.%s",
559                      GNUNET_GNSRECORD_pkey_to_zkey (&pub));
560     phone = GNUNET_CONVERSATION_phone_create (cfg,
561                                               ego,
562                                               &phone_event_handler,
563                                               NULL);
564     GNUNET_assert (NULL != phone);
565     memset (&rd, 0, sizeof (rd));
566     GNUNET_CONVERSATION_phone_get_record (phone,
567                                           &rd);
568     GNUNET_assert (rd.record_type == GNUNET_GNSRECORD_TYPE_PHONE);
569     rd.expiration_time = UINT64_MAX;
570     qe = GNUNET_NAMESTORE_records_store (ns,
571                                          GNUNET_IDENTITY_ego_get_private_key (ego),
572                                          "phone" /* GNS label */,
573                                          1,
574                                          &rd,
575                                          &namestore_put_cont,
576                                          NULL);
577     return;
578   }
579   if (0 == strcmp (name, "caller-ego"))
580   {
581     GNUNET_IDENTITY_ego_get_public_key (ego, &pub);
582     GNUNET_asprintf (&gns_caller_id,
583                      "%s",
584                      GNUNET_GNSRECORD_pkey_to_zkey (&pub));
585     call1 = GNUNET_CONVERSATION_call_start (cfg,
586                                             ego,
587                                             ego,
588                                             gns_name,
589                                             &call1_speaker,
590                                             &call1_mic,
591                                             &call_event_handler,
592                                             (void *) "call1");
593     call2 = GNUNET_CONVERSATION_call_start (cfg,
594                                             ego,
595                                             ego,
596                                             gns_name,
597                                             &call2_speaker,
598                                             &call2_mic,
599                                             &call_event_handler,
600                                             (void *) "call2");
601     return;
602   }
603 }
604
605
606 static void
607 phone_ego_create_cont (void *cls,
608                        const char *emsg)
609 {
610   op = NULL;
611   GNUNET_assert (NULL == emsg);
612 }
613
614
615 static void
616 run (void *cls,
617      const struct GNUNET_CONFIGURATION_Handle *c,
618      struct GNUNET_TESTING_Peer *peer)
619 {
620   cfg = c;
621   timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
622                                                &end_test,
623                                                NULL);
624   GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
625                                  NULL);
626   id = GNUNET_IDENTITY_connect (cfg,
627                                 &identity_cb,
628                                 NULL);
629   op = GNUNET_IDENTITY_create (id, "phone-ego", &phone_ego_create_cont, NULL);
630   ns = GNUNET_NAMESTORE_connect (cfg);
631 }
632
633
634 int
635 main (int argc, char *argv[])
636 {
637
638   if (0 != GNUNET_TESTING_peer_run ("test_conversation_api_twocalls",
639                                     "test_conversation.conf",
640                                     &run, NULL))
641     return 1;
642   if (call1_finished && call2_finished)
643     return 0;
644   return 1;
645 }
646
647 /* end of test_conversation_api_twocalls.c */