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