first batch of license fixes (boring)
[oweals/gnunet.git] / src / conversation / test_conversation_api.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2013, 2014, 2018 GNUnet e.V.
4
5      GNUnet is free software: you can redistribute it and/or modify it
6      under the terms of the GNU 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.c
17  * @brief testcase for conversation_api.c
18  *
19  * This test performs the operations of a call to a phone
20  * where the phone user picks up and then the call is
21  * terminated by the party that initiated the call.
22  */
23 #include "platform.h"
24 #include "gnunet_util_lib.h"
25 #include "gnunet_testing_lib.h"
26 #include "gnunet_gnsrecord_lib.h"
27 #include "gnunet_conversation_service.h"
28 #include "gnunet_identity_service.h"
29 #include "gnunet_namestore_service.h"
30
31 #define FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 250)
32
33 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 25)
34
35 static int ok = 1;
36
37 static const struct GNUNET_CONFIGURATION_Handle *cfg;
38
39 static struct GNUNET_IDENTITY_Handle *id;
40
41 static struct GNUNET_IDENTITY_Operation *op;
42
43 static struct GNUNET_CONVERSATION_Phone *phone;
44
45 static struct GNUNET_NAMESTORE_Handle *ns;
46
47 static struct GNUNET_CONVERSATION_Call *call;
48
49 static struct GNUNET_NAMESTORE_QueueEntry *qe;
50
51 static struct GNUNET_CONVERSATION_Caller *active_caller;
52
53 static char *gns_name;
54
55 static char *gns_caller_id;
56
57 static GNUNET_MICROPHONE_RecordedDataCallback phone_rdc;
58
59 static void *phone_rdc_cls;
60
61 static GNUNET_MICROPHONE_RecordedDataCallback call_rdc;
62
63 static void *call_rdc_cls;
64
65 static struct GNUNET_SCHEDULER_Task *phone_task;
66
67 static struct GNUNET_SCHEDULER_Task *call_task;
68
69
70 static void
71 phone_send (void *cls)
72 {
73   static unsigned int i;
74   char buf[32];
75
76   (void) cls;
77   GNUNET_assert (NULL != phone_rdc);
78   GNUNET_snprintf (buf, sizeof (buf), "phone-%u", i++);
79   phone_rdc (phone_rdc_cls, strlen (buf) + 1, buf);
80   phone_task = GNUNET_SCHEDULER_add_delayed (FREQ,
81                                              &phone_send, NULL);
82 }
83
84
85 static void
86 call_send (void *cls)
87 {
88   static unsigned int i;
89   char buf[32];
90
91   (void) cls;
92   GNUNET_assert (NULL != call_rdc);
93   GNUNET_snprintf (buf, sizeof (buf), "call-%u", i++);
94   call_rdc (call_rdc_cls, strlen (buf) + 1, buf);
95   call_task = GNUNET_SCHEDULER_add_delayed (FREQ,
96                                             &call_send, NULL);
97 }
98
99
100 static int
101 enable_speaker (void *cls)
102 {
103   const char *origin = cls;
104
105   fprintf (stderr,
106            "Speaker %s enabled\n",
107            origin);
108   return GNUNET_OK;
109 }
110
111
112 static void
113 disable_speaker (void *cls)
114 {
115   const char *origin = cls;
116
117   fprintf (stderr,
118            "Speaker %s disabled\n",
119            origin);
120 }
121
122
123 static void
124 play (void *cls,
125       size_t data_size,
126       const void *data)
127 {
128   const char *origin = cls;
129   static unsigned int phone_i = 1;
130   static unsigned int call_i;
131   char buf[32];
132
133   if (0 == strcmp (origin, "phone"))
134     GNUNET_snprintf (buf,
135                      sizeof (buf),
136                      "call-%u",
137                      call_i++);
138   else
139     GNUNET_snprintf (buf,
140                      sizeof (buf),
141                      "phone-%u",
142                      phone_i++);
143   if ( (data_size != strlen (buf) + 1) ||
144        (0 != strncmp (buf, data, data_size)) )
145   {
146     fprintf (stderr,
147              "Expected %s, received %.*s\n",
148              buf,
149              (int) data_size,
150              (const char *) data);
151   }
152   else
153   {
154     fprintf (stderr, ".");
155   }
156   if ( (20 < call_i) &&
157        (20 < phone_i) &&
158        (NULL != call) )
159   {
160     /* time to hang up ... */
161     GNUNET_CONVERSATION_call_stop (call);
162     call = NULL;
163   }
164 }
165
166
167 static void
168 destroy_speaker (void *cls)
169 {
170   const char *origin = cls;
171
172   fprintf (stderr, "Speaker %s destroyed\n", origin);
173 }
174
175
176 static struct GNUNET_SPEAKER_Handle call_speaker = {
177   &enable_speaker,
178   &play,
179   &disable_speaker,
180   &destroy_speaker,
181   "caller"
182 };
183
184
185 static struct GNUNET_SPEAKER_Handle phone_speaker = {
186   &enable_speaker,
187   &play,
188   &disable_speaker,
189   &destroy_speaker,
190   "phone"
191 };
192
193
194 static int
195 enable_mic (void *cls,
196             GNUNET_MICROPHONE_RecordedDataCallback rdc,
197             void *rdc_cls)
198 {
199   const char *origin = cls;
200
201   fprintf (stderr,
202            "Mic %s enabled\n",
203            origin);
204   if (0 == strcmp (origin, "phone"))
205   {
206     phone_rdc = rdc;
207     phone_rdc_cls = rdc_cls;
208     phone_task = GNUNET_SCHEDULER_add_now (&phone_send, NULL);
209   }
210   else
211   {
212     call_rdc = rdc;
213     call_rdc_cls = rdc_cls;
214     call_task = GNUNET_SCHEDULER_add_now (&call_send, NULL);
215   }
216   return GNUNET_OK;
217 }
218
219
220 static void
221 disable_mic (void *cls)
222 {
223   const char *origin = cls;
224
225   fprintf (stderr,
226            "Mic %s disabled\n",
227            origin);
228   if (0 == strcmp (origin, "phone"))
229   {
230     phone_rdc = NULL;
231     phone_rdc_cls = NULL;
232     GNUNET_SCHEDULER_cancel (phone_task);
233     phone_task = NULL;
234   }
235   else
236   {
237     call_rdc = NULL;
238     call_rdc_cls = NULL;
239     GNUNET_SCHEDULER_cancel (call_task);
240     call_task = NULL;
241   }
242 }
243
244
245 static void
246 destroy_mic (void *cls)
247 {
248   const char *origin = cls;
249
250   fprintf (stderr,
251            "Mic %s destroyed\n",
252            origin);
253 }
254
255
256 static struct GNUNET_MICROPHONE_Handle call_mic = {
257   &enable_mic,
258   &disable_mic,
259   &destroy_mic,
260   "caller"
261 };
262
263
264 static struct GNUNET_MICROPHONE_Handle phone_mic = {
265   &enable_mic,
266   &disable_mic,
267   &destroy_mic,
268   "phone"
269 };
270
271
272 /**
273  * Signature of the main function of a task.
274  *
275  * @param cls closure
276  */
277 static void
278 end_test (void *cls)
279 {
280   (void) cls;
281   GNUNET_SCHEDULER_shutdown ();
282   if (NULL != op)
283   {
284     GNUNET_IDENTITY_cancel (op);
285     op = NULL;
286   }
287   if (NULL != call)
288   {
289     GNUNET_CONVERSATION_call_stop (call);
290     call = NULL;
291   }
292   if (NULL != phone)
293   {
294     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from PHONE service.\n");
295     GNUNET_CONVERSATION_phone_destroy (phone);
296     phone = NULL;
297   }
298   if (NULL != id)
299   {
300     GNUNET_IDENTITY_disconnect (id);
301     id = NULL;
302   }
303   if (NULL != qe)
304   {
305     GNUNET_NAMESTORE_cancel (qe);
306     qe = NULL;
307   }
308   if (NULL != ns)
309   {
310     GNUNET_NAMESTORE_disconnect (ns);
311     ns = NULL;
312   }
313 }
314
315
316 static void
317 caller_event_handler (void *cls,
318                       enum GNUNET_CONVERSATION_CallerEventCode code)
319 {
320   (void) cls;
321   switch (code)
322   {
323   case GNUNET_CONVERSATION_EC_CALLER_SUSPEND:
324   case GNUNET_CONVERSATION_EC_CALLER_RESUME:
325     fprintf (stderr,
326              "Unexpected caller code: %d\n",
327              code);
328     break;
329   }
330 }
331
332
333 static void
334 phone_event_handler (void *cls,
335                      enum GNUNET_CONVERSATION_PhoneEventCode code,
336                      struct GNUNET_CONVERSATION_Caller *caller,
337                      const struct GNUNET_CRYPTO_EcdsaPublicKey *caller_id)
338 {
339   static enum GNUNET_CONVERSATION_PhoneEventCode expect
340     = GNUNET_CONVERSATION_EC_PHONE_RING;
341
342   (void) cls;
343   (void) caller_id;
344   GNUNET_break (code == expect);
345   switch (code)
346   {
347   case GNUNET_CONVERSATION_EC_PHONE_RING:
348     active_caller = caller;
349     GNUNET_CONVERSATION_caller_pick_up (caller,
350                                         &caller_event_handler,
351                                         NULL,
352                                         &phone_speaker,
353                                         &phone_mic);
354     expect = GNUNET_CONVERSATION_EC_PHONE_HUNG_UP;
355     break;
356   case GNUNET_CONVERSATION_EC_PHONE_HUNG_UP:
357     GNUNET_break (caller == active_caller);
358     active_caller = NULL;
359     if (1 == ok)
360       ok = 0;
361     GNUNET_SCHEDULER_shutdown ();
362     break;
363   default:
364     fprintf (stderr,
365              "Unexpected phone code: %d\n",
366              code);
367     break;
368   }
369 }
370
371
372 static void
373 call_event_handler (void *cls,
374                     enum GNUNET_CONVERSATION_CallEventCode code)
375 {
376   static enum GNUNET_CONVERSATION_CallEventCode expect
377     = GNUNET_CONVERSATION_EC_CALL_RINGING;
378
379   (void) cls;
380   GNUNET_break (code == expect);
381   switch (code)
382   {
383   case GNUNET_CONVERSATION_EC_CALL_RINGING:
384     expect = GNUNET_CONVERSATION_EC_CALL_PICKED_UP;
385     break;
386   case GNUNET_CONVERSATION_EC_CALL_PICKED_UP:
387     expect = -1;
388     break;
389   case GNUNET_CONVERSATION_EC_CALL_GNS_FAIL:
390   case GNUNET_CONVERSATION_EC_CALL_HUNG_UP:
391     call = NULL;
392     ok = 2;
393     GNUNET_break (0);
394     fprintf (stderr, "Unexpected call code: %d\n", code);
395     break;
396   case GNUNET_CONVERSATION_EC_CALL_SUSPENDED:
397   case GNUNET_CONVERSATION_EC_CALL_RESUMED:
398     GNUNET_break (0);
399     fprintf (stderr, "Unexpected call code: %d\n", code);
400     ok = 2;
401     break;
402   case GNUNET_CONVERSATION_EC_CALL_ERROR:
403     GNUNET_break (0);
404     fprintf (stderr, "Unexpected call code: %d\n", code);
405     call = NULL;
406     ok = 2;
407     break;
408   }
409 }
410
411
412 static void
413 caller_ego_create_cont (void *cls,
414                         const char *emsg)
415 {
416   (void) cls;
417   op = NULL;
418   GNUNET_assert (NULL == emsg);
419 }
420
421
422 static void
423 namestore_put_cont (void *cls,
424                     int32_t success,
425                     const char *emsg)
426 {
427   (void) cls;
428   qe = NULL;
429   GNUNET_assert (GNUNET_YES == success);
430   GNUNET_assert (NULL == emsg);
431   GNUNET_assert (NULL == op);
432   op = GNUNET_IDENTITY_create (id,
433                                "caller-ego",
434                                &caller_ego_create_cont,
435                                NULL);
436 }
437
438
439 static void
440 identity_cb (void *cls,
441              struct GNUNET_IDENTITY_Ego *ego,
442              void **ctx,
443              const char *name)
444 {
445   struct GNUNET_GNSRECORD_Data rd;
446   struct GNUNET_CRYPTO_EcdsaPublicKey pub;
447
448   (void) cls;
449   (void) ctx;
450   if (NULL == name)
451     return;
452   if (NULL == ego)
453     return;
454   if (0 == strcmp (name, "phone-ego"))
455   {
456     GNUNET_IDENTITY_ego_get_public_key (ego, &pub);
457     GNUNET_asprintf (&gns_name,
458                      "phone.%s",
459                      GNUNET_GNSRECORD_pkey_to_zkey (&pub));
460     phone = GNUNET_CONVERSATION_phone_create (cfg,
461                                               ego,
462                                               &phone_event_handler,
463                                               NULL);
464     GNUNET_assert (NULL != phone);
465     memset (&rd, 0, sizeof (rd));
466     GNUNET_CONVERSATION_phone_get_record (phone,
467                                           &rd);
468     GNUNET_assert (rd.record_type == GNUNET_GNSRECORD_TYPE_PHONE);
469     rd.expiration_time = UINT64_MAX;
470     qe = GNUNET_NAMESTORE_records_store (ns,
471                                          GNUNET_IDENTITY_ego_get_private_key (ego),
472                                          "phone" /* GNS label */,
473                                          1,
474                                          &rd,
475                                          &namestore_put_cont,
476                                          NULL);
477     return;
478   }
479   if (0 == strcmp (name, "caller-ego"))
480   {
481     GNUNET_IDENTITY_ego_get_public_key (ego, &pub);
482     GNUNET_asprintf (&gns_caller_id,
483                      "%s",
484                      GNUNET_GNSRECORD_pkey_to_zkey (&pub));
485     call = GNUNET_CONVERSATION_call_start (cfg,
486                                            ego,
487                                            gns_name,
488                                            &call_speaker,
489                                            &call_mic,
490                                            &call_event_handler,
491                                            NULL);
492     return;
493   }
494 }
495
496
497 static void
498 phone_ego_create_cont (void *cls,
499                        const char *emsg)
500 {
501   (void) cls;
502   op = NULL;
503   GNUNET_assert (NULL == emsg);
504 }
505
506
507 static void
508 run (void *cls,
509      const struct GNUNET_CONFIGURATION_Handle *c,
510      struct GNUNET_TESTING_Peer *peer)
511 {
512   (void) cls;
513   (void) peer;
514   cfg = c;
515   GNUNET_SCHEDULER_add_delayed (TIMEOUT,
516                                 &end_test,
517                                 NULL);
518   id = GNUNET_IDENTITY_connect (cfg,
519                                 &identity_cb,
520                                 NULL);
521   op = GNUNET_IDENTITY_create (id,
522                                "phone-ego",
523                                &phone_ego_create_cont,
524                                NULL);
525   ns = GNUNET_NAMESTORE_connect (cfg);
526 }
527
528
529 int
530 main (int argc,
531       char *argv[])
532 {
533   (void) argc;
534   (void) argv;
535   if (0 != GNUNET_TESTING_peer_run ("test_conversation_api",
536                                     "test_conversation.conf",
537                                     &run,
538                                     NULL))
539     return 1;
540   return ok;
541 }
542
543 /* end of test_conversation_api.c */