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