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