- reset counters to continue the resumed call
[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     call_i = 0;
205     phone_i = 0;
206   }
207 }
208
209
210 static void
211 destroy_speaker (void *cls)
212 {
213   const char *origin = CLS_STR (cls);
214
215   fprintf (stderr, "Speaker %s destroyed\n", origin);
216 }
217
218
219 static struct GNUNET_SPEAKER_Handle call1_speaker = {
220   &enable_speaker,
221   &play,
222   &disable_speaker,
223   &destroy_speaker,
224   CALLER1
225 };
226
227
228 static struct GNUNET_SPEAKER_Handle call2_speaker = {
229   &enable_speaker,
230   &play,
231   &disable_speaker,
232   &destroy_speaker,
233   CALLER2
234 };
235
236
237 static struct GNUNET_SPEAKER_Handle phone_speaker = {
238   &enable_speaker,
239   &play,
240   &disable_speaker,
241   &destroy_speaker,
242   PHONE0
243 };
244
245
246 static int
247 enable_mic (void *cls,
248             GNUNET_MICROPHONE_RecordedDataCallback rdc,
249             void *rdc_cls)
250 {
251   const char *origin = CLS_STR (cls);
252   struct MicContext *mc;
253
254   fprintf (stderr,
255            "Mic %s enabled\n",
256            origin);
257   if (PHONE0 == cls)
258   {
259     phone_rdc = rdc;
260     phone_rdc_cls = rdc_cls;
261     GNUNET_break (GNUNET_SCHEDULER_NO_TASK == phone_task);
262     phone_task = GNUNET_SCHEDULER_add_now (&phone_send, NULL);
263     return GNUNET_OK;
264   }
265   mc = (CALLER1 == cls) ? &call1_mic_ctx : &call2_mic_ctx;
266   mc->sym = (CALLER1 == cls) ? '1': '2';
267   mc->rdc = rdc;
268   mc->rdc_cls = rdc_cls;
269   GNUNET_break (GNUNET_SCHEDULER_NO_TASK == mc->call_task);
270   mc->call_task = GNUNET_SCHEDULER_add_now (&call_send, mc);
271   return GNUNET_OK;
272 }
273
274
275 static void
276 disable_mic (void *cls)
277 {
278   const char *origin = CLS_STR (cls);
279   struct MicContext *mc;
280
281   fprintf (stderr,
282            "Mic %s disabled\n",
283            origin);
284   if (PHONE0 == cls)
285   {
286     phone_rdc = NULL;
287     phone_rdc_cls = NULL;
288     GNUNET_SCHEDULER_cancel (phone_task);
289     phone_task = GNUNET_SCHEDULER_NO_TASK;
290     return;
291   }
292   mc = (CALLER1 == cls) ? &call1_mic_ctx : &call2_mic_ctx;
293   mc->rdc = NULL;
294   mc->rdc_cls = NULL;
295   GNUNET_SCHEDULER_cancel (mc->call_task);
296   mc->call_task = GNUNET_SCHEDULER_NO_TASK;
297 }
298
299
300 static void
301 destroy_mic (void *cls)
302 {
303   const char *origin = CLS_STR (cls);
304
305   fprintf (stderr,
306            "Mic %s destroyed\n",
307            origin);
308 }
309
310
311 static struct GNUNET_MICROPHONE_Handle call1_mic = {
312   &enable_mic,
313   &disable_mic,
314   &destroy_mic,
315   CALLER1
316 };
317
318
319 static struct GNUNET_MICROPHONE_Handle call2_mic = {
320   &enable_mic,
321   &disable_mic,
322   &destroy_mic,
323   CALLER2
324 };
325
326
327 static struct GNUNET_MICROPHONE_Handle phone_mic = {
328   &enable_mic,
329   &disable_mic,
330   &destroy_mic,
331   PHONE0
332 };
333
334
335 /**
336  * Signature of the main function of a task.
337  *
338  * @param cls closure
339  * @param tc context information (why was this task triggered now)
340  */
341 static void
342 end_test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
343 {
344   GNUNET_SCHEDULER_shutdown ();
345   if (NULL != op)
346   {
347     GNUNET_IDENTITY_cancel (op);
348     op = NULL;
349   }
350   if (NULL != call1)
351   {
352     GNUNET_CONVERSATION_call_stop (call1);
353     call1 = NULL;
354   }
355   if (NULL != call2)
356   {
357     GNUNET_CONVERSATION_call_stop (call2);
358     call2 = NULL;
359   }
360   if (NULL != phone)
361   {
362     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from PHONE service.\n");
363     GNUNET_CONVERSATION_phone_destroy (phone);
364     phone = NULL;
365   }
366   if (NULL != id)
367   {
368     GNUNET_IDENTITY_disconnect (id);
369     id = NULL;
370   }
371   if (NULL != qe)
372   {
373     GNUNET_NAMESTORE_cancel (qe);
374     qe = NULL;
375   }
376   if (NULL != ns)
377   {
378     GNUNET_NAMESTORE_disconnect (ns);
379     ns = NULL;
380   }
381 }
382
383
384 static void
385 caller_event_handler (void *cls,
386                       enum GNUNET_CONVERSATION_CallerEventCode code)
387 {
388   switch (code)
389   {
390   case GNUNET_CONVERSATION_EC_CALLER_SUSPEND:
391   case GNUNET_CONVERSATION_EC_CALLER_RESUME:
392     fprintf (stderr, "Unexpected caller code: %d\n", code);
393     break;
394   }
395 }
396
397
398 static void
399 phone_event_handler (void *cls,
400                      enum GNUNET_CONVERSATION_PhoneEventCode code,
401                      struct GNUNET_CONVERSATION_Caller *caller,
402                      const char *caller_id)
403 {
404   const char *cid;
405
406   GNUNET_break (0 == strcmp (caller_id,
407                              gns_caller_id));
408   switch (code)
409   {
410   case GNUNET_CONVERSATION_EC_PHONE_RING:
411     if (NULL == active_caller1)
412     {
413       active_caller1 = caller;
414       cid = "caller1";
415       GNUNET_CONVERSATION_caller_pick_up (caller,
416                                           &caller_event_handler,
417                                           (void *) cid,
418                                           &phone_speaker,
419                                           &phone_mic);
420     }
421     else
422     {
423       GNUNET_CONVERSATION_caller_suspend (active_caller1);
424       active_caller2 = caller;
425       cid = "caller2";
426       GNUNET_CONVERSATION_caller_pick_up (caller,
427                                           &caller_event_handler,
428                                           (void *) cid,
429                                           &phone_speaker,
430                                           &phone_mic);
431     }
432     break;
433   case GNUNET_CONVERSATION_EC_PHONE_HUNG_UP:
434     if (caller == active_caller2)
435     {
436       active_caller2 = NULL;
437       GNUNET_CONVERSATION_caller_resume (active_caller1,
438                                          &phone_speaker,
439                                          &phone_mic);
440     }
441     else if (caller == active_caller1)
442     {
443       active_caller1 = NULL;
444       GNUNET_break (NULL == active_caller2);
445       ok = 0;
446       GNUNET_SCHEDULER_shutdown ();
447     }
448     break;
449   default:
450     fprintf (stderr, "Unexpected phone code: %d\n", code);
451     break;
452   }
453 }
454
455
456 static void
457 call_event_handler (void *cls,
458                     enum GNUNET_CONVERSATION_CallEventCode code)
459 {
460   const char *cid = cls;
461
462   switch (code)
463   {
464   case GNUNET_CONVERSATION_EC_CALL_RINGING:
465     break;
466   case GNUNET_CONVERSATION_EC_CALL_PICKED_UP:
467     fprintf (stderr, "\t Call %s picked\n", cid);
468     break;
469   case GNUNET_CONVERSATION_EC_CALL_GNS_FAIL:
470     fprintf (stderr, "\t Call %s GNS lookup failed \n", cid);
471   case GNUNET_CONVERSATION_EC_CALL_HUNG_UP:
472     fprintf (stderr, "\t Call %s hungup\n", cid);
473     if (0 == strcmp (cid, "call1"))
474       call1 = NULL;
475     else
476       call2 = NULL;
477     break;
478   case GNUNET_CONVERSATION_EC_CALL_SUSPENDED:
479     fprintf (stderr, "\t Call %s suspended\n", cid);
480     break;
481   case GNUNET_CONVERSATION_EC_CALL_RESUMED:
482     fprintf (stderr, "\t Call %s resumed\n", cid);
483     break;
484   }
485 }
486
487
488 static void
489 caller_ego_create_cont (void *cls,
490                         const char *emsg)
491 {
492   op = NULL;
493   GNUNET_assert (NULL == emsg);
494 }
495
496
497 static void
498 namestore_put_cont (void *cls,
499                     int32_t success,
500                     const char *emsg)
501 {
502   qe = NULL;
503   GNUNET_assert (GNUNET_YES == success);
504   GNUNET_assert (NULL == emsg);
505   GNUNET_assert (NULL == op);
506   op = GNUNET_IDENTITY_create (id, "caller-ego", &caller_ego_create_cont, NULL);
507 }
508
509
510 static void
511 identity_cb (void *cls,
512              struct GNUNET_IDENTITY_Ego *ego,
513              void **ctx,
514              const char *name)
515 {
516   struct GNUNET_GNSRECORD_Data rd;
517   struct GNUNET_CRYPTO_EcdsaPublicKey pub;
518
519   if (NULL == name)
520     return;
521   if (NULL == ego)
522     return;
523   if (0 == strcmp (name, "phone-ego"))
524   {
525     GNUNET_IDENTITY_ego_get_public_key (ego, &pub);
526     GNUNET_asprintf (&gns_name,
527                      "phone.%s",
528                      GNUNET_GNSRECORD_pkey_to_zkey (&pub));
529     phone = GNUNET_CONVERSATION_phone_create (cfg,
530                                               ego,
531                                               &phone_event_handler,
532                                               NULL);
533     GNUNET_assert (NULL != phone);
534     memset (&rd, 0, sizeof (rd));
535     GNUNET_CONVERSATION_phone_get_record (phone,
536                                           &rd);
537     GNUNET_assert (rd.record_type == GNUNET_GNSRECORD_TYPE_PHONE);
538     rd.expiration_time = UINT64_MAX;
539     qe = GNUNET_NAMESTORE_records_store (ns,
540                                          GNUNET_IDENTITY_ego_get_private_key (ego),
541                                          "phone" /* GNS label */,
542                                          1,
543                                          &rd,
544                                          &namestore_put_cont,
545                                          NULL);
546     return;
547   }
548   if (0 == strcmp (name, "caller-ego"))
549   {
550     GNUNET_IDENTITY_ego_get_public_key (ego, &pub);
551     GNUNET_asprintf (&gns_caller_id,
552                      "%s",
553                      GNUNET_GNSRECORD_pkey_to_zkey (&pub));
554     call1 = GNUNET_CONVERSATION_call_start (cfg,
555                                             ego,
556                                             gns_name,
557                                             &call1_speaker,
558                                             &call1_mic,
559                                             &call_event_handler,
560                                             (void *) "call1");
561     call2 = GNUNET_CONVERSATION_call_start (cfg,
562                                             ego,
563                                             gns_name,
564                                             &call2_speaker,
565                                             &call2_mic,
566                                             &call_event_handler,
567                                             (void *) "call2");
568     return;
569   }
570 }
571
572
573 static void
574 phone_ego_create_cont (void *cls,
575                        const char *emsg)
576 {
577   op = NULL;
578   GNUNET_assert (NULL == emsg);
579 }
580
581
582 static void
583 run (void *cls,
584      const struct GNUNET_CONFIGURATION_Handle *c,
585      struct GNUNET_TESTING_Peer *peer)
586 {
587   cfg = c;
588   GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_test,
589                                 NULL);
590   id = GNUNET_IDENTITY_connect (cfg,
591                                 &identity_cb,
592                                 NULL);
593   op = GNUNET_IDENTITY_create (id, "phone-ego", &phone_ego_create_cont, NULL);
594   ns = GNUNET_NAMESTORE_connect (cfg);
595 }
596
597
598 int
599 main (int argc, char *argv[])
600 {
601   if (0 != GNUNET_TESTING_peer_run ("test_conversation_api_twocalls",
602                                     "test_conversation.conf",
603                                     &run, NULL))
604     return 1;
605   return ok;
606 }
607
608 /* end of test_conversation_api_twocalls.c */