Merge branch 'master' of gnunet.org:gnunet
[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
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   (void) cls;
134   GNUNET_assert (NULL != phone_rdc);
135   GNUNET_snprintf (buf, sizeof (buf), "phone");
136   phone_rdc (phone_rdc_cls,
137              strlen (buf) + 1,
138              buf);
139   phone_task = GNUNET_SCHEDULER_add_delayed (FREQ,
140                                              &phone_send,
141                                              NULL);
142 }
143
144
145 static void
146 call_send (void *cls)
147 {
148   struct MicContext *mc = cls;
149   char buf[32];
150
151   (void) cls;
152   GNUNET_assert (NULL != mc->rdc);
153   GNUNET_snprintf (buf,
154                    sizeof (buf),
155                    "call");
156   mc->rdc (mc->rdc_cls,
157            strlen (buf) + 1,
158            buf);
159   mc->call_task = GNUNET_SCHEDULER_add_delayed (FREQ,
160                                                 &call_send,
161                                                 mc);
162 }
163
164
165 static int
166 enable_speaker (void *cls)
167 {
168   const char *origin = CLS_STR (cls);
169
170   (void) cls;
171   LOG_DEBUG ("Speaker %s enabled\n",
172              origin);
173   return GNUNET_OK;
174 }
175
176
177 static void
178 disable_speaker (void *cls)
179 {
180   const char *origin = CLS_STR (cls);
181
182   (void) cls;
183   LOG_DEBUG ("Speaker %s disabled\n",
184              origin);
185 }
186
187
188 static void
189 play (void *cls,
190       size_t data_size,
191       const void *data)
192 {
193   static unsigned int phone_i;
194   static unsigned int call_i;
195
196   (void) cls;
197   if (0 == strncmp ("call", data, data_size))
198     call_i++;
199   else if (0 == strncmp ("phone", data, data_size))
200     phone_i++;
201   else
202   {
203     LOG_DEBUG ("Received %u bytes of unexpected data `%.*s'\n",
204                (unsigned int) data_size,
205                (int) data_size,
206                (const char *) data);
207   }
208
209   if ( (20 < call_i) &&
210        (20 < phone_i) &&
211        (CALLER2 == cls) )
212   {
213     /* time to hang up ... */
214     GNUNET_CONVERSATION_call_stop (call2);
215     call2 = NULL;
216     /* reset counters */
217     call_i = 0;
218     phone_i = 0;
219     call2_finished = GNUNET_YES;
220   }
221   if ( (20 < call_i) &&
222        (20 < phone_i) &&
223        (CALLER1 == cls) )
224   {
225     /* time to hang up ... */
226     GNUNET_CONVERSATION_call_stop (call1);
227     call1 = NULL;
228     call_i = 0;
229     phone_i = 0;
230     call1_finished = GNUNET_YES;
231   }
232 }
233
234
235 static void
236 destroy_speaker (void *cls)
237 {
238   const char *origin = CLS_STR (cls);
239
240   LOG_DEBUG ("Speaker %s destroyed\n", origin);
241 }
242
243
244 static struct GNUNET_SPEAKER_Handle call1_speaker = {
245   &enable_speaker,
246   &play,
247   &disable_speaker,
248   &destroy_speaker,
249   CALLER1
250 };
251
252
253 static struct GNUNET_SPEAKER_Handle call2_speaker = {
254   &enable_speaker,
255   &play,
256   &disable_speaker,
257   &destroy_speaker,
258   CALLER2
259 };
260
261
262 static struct GNUNET_SPEAKER_Handle phone_speaker = {
263   &enable_speaker,
264   &play,
265   &disable_speaker,
266   &destroy_speaker,
267   PHONE0
268 };
269
270
271 static int
272 enable_mic (void *cls,
273             GNUNET_MICROPHONE_RecordedDataCallback rdc,
274             void *rdc_cls)
275 {
276   const char *origin = CLS_STR (cls);
277   struct MicContext *mc;
278
279   LOG_DEBUG ("Mic %s enabled\n",
280              origin);
281   if (PHONE0 == cls)
282   {
283     phone_rdc = rdc;
284     phone_rdc_cls = rdc_cls;
285     GNUNET_break (NULL == phone_task);
286     phone_task = GNUNET_SCHEDULER_add_now (&phone_send, NULL);
287     return GNUNET_OK;
288   }
289   mc = (CALLER1 == cls) ? &call1_mic_ctx : &call2_mic_ctx;
290   mc->rdc = rdc;
291   mc->rdc_cls = rdc_cls;
292   GNUNET_break (NULL == mc->call_task);
293   mc->call_task = GNUNET_SCHEDULER_add_now (&call_send, mc);
294   return GNUNET_OK;
295 }
296
297
298 static void
299 disable_mic (void *cls)
300 {
301   const char *origin = CLS_STR (cls);
302   struct MicContext *mc;
303
304   LOG_DEBUG ("Mic %s disabled\n",
305              origin);
306   if (PHONE0 == cls)
307   {
308     phone_rdc = NULL;
309     phone_rdc_cls = NULL;
310     GNUNET_SCHEDULER_cancel (phone_task);
311     phone_task = NULL;
312     return;
313   }
314   mc = (CALLER1 == cls) ? &call1_mic_ctx : &call2_mic_ctx;
315   mc->rdc = NULL;
316   mc->rdc_cls = NULL;
317   GNUNET_SCHEDULER_cancel (mc->call_task);
318   mc->call_task = NULL;
319 }
320
321
322 static void
323 destroy_mic (void *cls)
324 {
325   const char *origin = CLS_STR (cls);
326
327   LOG_DEBUG ("Mic %s destroyed\n",
328              origin);
329 }
330
331
332 static struct GNUNET_MICROPHONE_Handle call1_mic = {
333   &enable_mic,
334   &disable_mic,
335   &destroy_mic,
336   CALLER1
337 };
338
339
340 static struct GNUNET_MICROPHONE_Handle call2_mic = {
341   &enable_mic,
342   &disable_mic,
343   &destroy_mic,
344   CALLER2
345 };
346
347
348 static struct GNUNET_MICROPHONE_Handle phone_mic = {
349   &enable_mic,
350   &disable_mic,
351   &destroy_mic,
352   PHONE0
353 };
354
355
356 /**
357  * Function run on timeout.
358  *
359  * @param cls closure
360  */
361 static void
362 end_test (void *cls)
363 {
364   (void) cls;
365   timeout_task = NULL;
366   fprintf (stderr,
367            "Timeout!\n");
368   GNUNET_SCHEDULER_shutdown ();
369 }
370
371
372 /**
373  * Function run on shutdown.
374  *
375  * @param cls closure
376  */
377 static void
378 do_shutdown (void *cls)
379 {
380   (void) cls;
381   if (NULL != timeout_task)
382   {
383     GNUNET_SCHEDULER_cancel (timeout_task);
384     timeout_task = NULL;
385   }
386   if (NULL != op)
387   {
388     GNUNET_IDENTITY_cancel (op);
389     op = NULL;
390   }
391   if (NULL != call1)
392   {
393     GNUNET_CONVERSATION_call_stop (call1);
394     call1 = NULL;
395   }
396   if (NULL != call2)
397   {
398     GNUNET_CONVERSATION_call_stop (call2);
399     call2 = NULL;
400   }
401   if (NULL != phone)
402   {
403     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from PHONE service.\n");
404     GNUNET_CONVERSATION_phone_destroy (phone);
405     phone = NULL;
406   }
407   if (NULL != id)
408   {
409     GNUNET_IDENTITY_disconnect (id);
410     id = NULL;
411   }
412   if (NULL != qe)
413   {
414     GNUNET_NAMESTORE_cancel (qe);
415     qe = NULL;
416   }
417   if (NULL != ns)
418   {
419     GNUNET_NAMESTORE_disconnect (ns);
420     ns = NULL;
421   }
422 }
423
424
425 static void
426 caller_event_handler (void *cls,
427                       enum GNUNET_CONVERSATION_CallerEventCode code)
428 {
429   (void) cls;
430   switch (code)
431   {
432   case GNUNET_CONVERSATION_EC_CALLER_SUSPEND:
433   case GNUNET_CONVERSATION_EC_CALLER_RESUME:
434     LOG (GNUNET_ERROR_TYPE_WARNING,
435          "Unexpected caller code: %d\n",
436          code);
437     break;
438   }
439 }
440
441
442 static void
443 phone_event_handler (void *cls,
444                      enum GNUNET_CONVERSATION_PhoneEventCode code,
445                      struct GNUNET_CONVERSATION_Caller *caller,
446                      const struct GNUNET_CRYPTO_EcdsaPublicKey *caller_id)
447 {
448   const char *cid;
449   (void) cls;
450   (void) caller_id;
451
452   switch (code)
453   {
454   case GNUNET_CONVERSATION_EC_PHONE_RING:
455     if (NULL == active_caller1)
456     {
457       active_caller1 = caller;
458       cid = "caller1";
459       GNUNET_CONVERSATION_caller_pick_up (caller,
460                                           &caller_event_handler,
461                                           (void *) cid,
462                                           &phone_speaker,
463                                           &phone_mic);
464     }
465     else
466     {
467       GNUNET_CONVERSATION_caller_suspend (active_caller1);
468       active_caller2 = caller;
469       cid = "caller2";
470       GNUNET_CONVERSATION_caller_pick_up (caller,
471                                           &caller_event_handler,
472                                           (void *) cid,
473                                           &phone_speaker,
474                                           &phone_mic);
475     }
476     break;
477   case GNUNET_CONVERSATION_EC_PHONE_HUNG_UP:
478     if (caller == active_caller2)
479     {
480       active_caller2 = NULL;
481       GNUNET_CONVERSATION_caller_resume (active_caller1,
482                                          &phone_speaker,
483                                          &phone_mic);
484     }
485     else if (caller == active_caller1)
486     {
487       active_caller1 = NULL;
488       GNUNET_break (NULL == active_caller2);
489       GNUNET_SCHEDULER_shutdown ();
490     }
491     break;
492   default:
493     LOG (GNUNET_ERROR_TYPE_WARNING,
494          "Unexpected phone code: %d\n",
495          code);
496     break;
497   }
498 }
499
500
501 static void
502 call_event_handler (void *cls,
503                     enum GNUNET_CONVERSATION_CallEventCode code)
504 {
505   const char *cid = cls;
506
507   switch (code)
508   {
509   case GNUNET_CONVERSATION_EC_CALL_RINGING:
510     break;
511   case GNUNET_CONVERSATION_EC_CALL_PICKED_UP:
512     LOG_DEBUG ("Call %s picked\n", cid);
513     break;
514   case GNUNET_CONVERSATION_EC_CALL_GNS_FAIL:
515     LOG_DEBUG ("Call %s GNS lookup failed \n", cid);
516     break;
517   case GNUNET_CONVERSATION_EC_CALL_HUNG_UP:
518     LOG_DEBUG ("Call %s hungup\n", cid);
519     if (0 == strcmp (cid, "call1"))
520       call1 = NULL;
521     else
522       call2 = NULL;
523     break;
524   case GNUNET_CONVERSATION_EC_CALL_SUSPENDED:
525     LOG_DEBUG ("Call %s suspended\n", cid);
526     break;
527   case GNUNET_CONVERSATION_EC_CALL_RESUMED:
528     LOG_DEBUG ("Call %s resumed\n", cid);
529     break;
530   case GNUNET_CONVERSATION_EC_CALL_ERROR:
531     GNUNET_break (0);
532     if (0 == strcmp (cid, "call1"))
533       call1 = NULL;
534     else
535       call2 = NULL;
536     GNUNET_SCHEDULER_shutdown ();
537     break;
538   }
539 }
540
541
542 static void
543 caller_ego_create_cont (void *cls,
544                         const char *emsg)
545 {
546   (void) cls;
547   op = NULL;
548   GNUNET_assert (NULL == emsg);
549 }
550
551
552 static void
553 namestore_put_cont (void *cls,
554                     int32_t success,
555                     const char *emsg)
556 {
557   (void) cls;
558   qe = NULL;
559   GNUNET_assert (GNUNET_YES == success);
560   GNUNET_assert (NULL == emsg);
561   GNUNET_assert (NULL == op);
562   op = GNUNET_IDENTITY_create (id,
563                                "caller-ego",
564                                &caller_ego_create_cont,
565                                NULL);
566 }
567
568
569 static void
570 identity_cb (void *cls,
571              struct GNUNET_IDENTITY_Ego *ego,
572              void **ctx,
573              const char *name)
574 {
575   struct GNUNET_GNSRECORD_Data rd;
576   struct GNUNET_CRYPTO_EcdsaPublicKey pub;
577
578   (void) cls;
579   (void) ctx;
580   if (NULL == name)
581     return;
582   if (NULL == ego)
583     return;
584   if (0 == strcmp (name, "phone-ego"))
585   {
586     GNUNET_IDENTITY_ego_get_public_key (ego, &pub);
587     GNUNET_asprintf (&gns_name,
588                      "phone.%s",
589                      GNUNET_GNSRECORD_pkey_to_zkey (&pub));
590     phone = GNUNET_CONVERSATION_phone_create (cfg,
591                                               ego,
592                                               &phone_event_handler,
593                                               NULL);
594     GNUNET_assert (NULL != phone);
595     memset (&rd, 0, sizeof (rd));
596     GNUNET_CONVERSATION_phone_get_record (phone,
597                                           &rd);
598     GNUNET_assert (rd.record_type == GNUNET_GNSRECORD_TYPE_PHONE);
599     rd.expiration_time = UINT64_MAX;
600     qe = GNUNET_NAMESTORE_records_store (ns,
601                                          GNUNET_IDENTITY_ego_get_private_key (ego),
602                                          "phone" /* GNS label */,
603                                          1,
604                                          &rd,
605                                          &namestore_put_cont,
606                                          NULL);
607     return;
608   }
609   if (0 == strcmp (name, "caller-ego"))
610   {
611     GNUNET_IDENTITY_ego_get_public_key (ego, &pub);
612     GNUNET_asprintf (&gns_caller_id,
613                      "%s",
614                      GNUNET_GNSRECORD_pkey_to_zkey (&pub));
615     call1 = GNUNET_CONVERSATION_call_start (cfg,
616                                             ego,
617                                             gns_name,
618                                             &call1_speaker,
619                                             &call1_mic,
620                                             &call_event_handler,
621                                             (void *) "call1");
622     call2 = GNUNET_CONVERSATION_call_start (cfg,
623                                             ego,
624                                             gns_name,
625                                             &call2_speaker,
626                                             &call2_mic,
627                                             &call_event_handler,
628                                             (void *) "call2");
629     return;
630   }
631 }
632
633
634 static void
635 phone_ego_create_cont (void *cls,
636                        const char *emsg)
637 {
638   (void) cls;
639   op = NULL;
640   GNUNET_assert (NULL == emsg);
641 }
642
643
644 static void
645 run (void *cls,
646      const struct GNUNET_CONFIGURATION_Handle *c,
647      struct GNUNET_TESTING_Peer *peer)
648 {
649   (void) cls;
650   (void) peer;
651   cfg = c;
652   timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
653                                                &end_test,
654                                                NULL);
655   GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
656                                  NULL);
657   id = GNUNET_IDENTITY_connect (cfg,
658                                 &identity_cb,
659                                 NULL);
660   op = GNUNET_IDENTITY_create (id,
661                                "phone-ego",
662                                &phone_ego_create_cont,
663                                NULL);
664   ns = GNUNET_NAMESTORE_connect (cfg);
665 }
666
667
668 int
669 main (int argc,
670       char *argv[])
671 {
672   (void) argc;
673   (void) argv;
674   if (0 != GNUNET_TESTING_peer_run ("test_conversation_api_twocalls",
675                                     "test_conversation.conf",
676                                     &run,
677                                     NULL))
678     return 1;
679   if (call1_finished && call2_finished)
680     return 0;
681   return 1;
682 }
683
684 /* end of test_conversation_api_twocalls.c */