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