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