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