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