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