-cleanup, FIXMEs
[oweals/gnunet.git] / src / scalarproduct / test_scalarproduct_api_regression2.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 /**
22  * @file scalarproduct/test_scalarproduct_api_regression2.c
23  * @brief Regression test, destroys requester service before receiving response
24  *        responder service
25  * @author Gaurav Kukreja
26  * @author Christian Fuchs
27  */
28
29 #include <string.h>
30
31 #include <inttypes.h>
32 #include "platform.h"
33 #include "gnunet_util_lib.h"
34 #include "gnunet_testbed_service.h"
35 #include "gnunet_common.h"
36 #include "gnunet_scalarproduct_service.h"
37 #include "gnunet_protocols.h"
38
39 #define LOG(kind,...) GNUNET_log_from (kind, "test-scalarproduct-api-regression2",__VA_ARGS__)
40 #define NUM_PEERS 2
41
42 /**
43  * Structure for holding peer's sockets and IO Handles
44  */
45 struct PeerData
46 {
47   /**
48    * Handle to testbed peer
49    */
50   struct GNUNET_TESTBED_Peer *peer;
51
52   /**
53    * The service connect operation to stream
54    */
55   struct GNUNET_TESTBED_Operation *op;
56
57   /**
58    * Our Peer id
59    */
60   struct GNUNET_PeerIdentity our_id;
61
62   /**
63    * Pointer to Vector Product Handle
64    */
65   struct GNUNET_SCALARPRODUCT_Handle *vh;
66 };
67
68 /**
69  * Different states in test setup
70  */
71 enum SetupState
72 {
73   /**
74    * Get the identity of peer 1
75    */
76   PEER1_GET_IDENTITY,
77
78   /**
79    * Get the identity of peer 2
80    */
81   PEER2_GET_IDENTITY,
82
83   /**
84    * Connect to stream service of peer 1
85    */
86   PEER1_SCALARPRODUCT_CONNECT,
87
88   /**
89    * Connect to stream service of peer 2
90    */
91   PEER2_SCALARPRODUCT_CONNECT
92
93 };
94
95 /******************************************************************************
96  *** Global Variables                            *****************************
97  ******************************************************************************/
98
99 /**
100  * Maximum allowed message-ids we can check in one go (with one GNUNET_message)
101  */
102 static unsigned int max_mids;
103
104 /**
105  * Session Key used by both the test peers
106  */
107 char input_key[103] = "helloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhe";
108
109 /**
110  * Input elements for peer1
111  */
112 char input_elements_peer1[] = "11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11";
113 //char input_elements_peer1[] = "11,11,11";
114
115 /**
116  * Input Mask for peer 1
117  */
118 char input_mask_peer1[] = "1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1";
119 //char input_mask_peer1[] = "1,1,1";
120
121 /**
122  * the array of converted message IDs to send to our service
123  */
124 static int32_t * elements_peer1 = NULL;
125
126 /**
127  * the array of converted message IDs to send to our service
128  */
129 static unsigned char * mask_peer1 = NULL;
130
131 /**
132  * Number of elements
133  */
134 uint16_t element_count_peer1 = 0;
135
136 /**
137  * Input elements for peer2
138  */
139 char input_elements_peer2[] = "11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11";
140 //char input_elements_peer2[] = "11,11,11";
141
142 /**
143  * Input Mask for peer 2
144  */
145 char input_mask_peer2[] = "1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1";
146 //char input_mask_peer2[] = "1,1,1";
147
148 /**
149  * the array of converted message IDs to send to our service
150  */
151 static int32_t * elements_peer2 = NULL;
152
153 /**
154  * the array of converted message IDs to send to our service
155  */
156 static unsigned char * mask_peer2 = NULL;
157
158 /**
159  * Number of elements
160  */
161 uint16_t element_count_peer2 = 0;
162
163 /**
164  * Data context for peer 1
165  */
166 static struct PeerData peer1;
167
168 /**
169  * Data context for peer 2
170  */
171 static struct PeerData peer2;
172
173 /**
174  * Various states during test setup
175  */
176 static enum SetupState setup_state;
177
178 /**
179  * Testbed operation handle
180  */
181 static struct GNUNET_TESTBED_Operation *op;
182
183 static int ok;
184
185 static int responder_ok;
186
187 static int requester_ok;
188
189 static GNUNET_SCHEDULER_TaskIdentifier abort_task;
190 /******************************************************************************
191  *** Static Functions                             *****************************
192  ******************************************************************************/
193
194 static void
195 do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
196
197
198 /**
199  * Close sockets and stop testing deamons nicely
200  */
201 static void
202 do_close (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
203 {
204   static int closed;
205
206   if (peer1.op != NULL)
207     {
208       do_shutdown (&peer1, NULL);
209     }
210
211   if (peer2.op != NULL)
212     {
213       do_shutdown (&peer2, NULL);
214     }
215
216   if (GNUNET_SCHEDULER_NO_TASK != abort_task)
217     {
218       GNUNET_SCHEDULER_cancel (abort_task);
219       abort_task = GNUNET_SCHEDULER_NO_TASK;
220       GNUNET_SCHEDULER_shutdown (); /* For shutting down testbed */
221     }
222
223   if (!closed)
224     {
225       closed++;
226       GNUNET_SCHEDULER_shutdown (); /* For shutting down testbed */
227     }
228 }
229
230 /**
231  * Shutdown a peer
232  * 
233  * @param cls closure is a pointer to the struct PeerData of the peer to be disconnected
234  * @param tc Task Context
235  */
236 static void
237 do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
238 {
239   static int shutdown;
240   shutdown++;
241   struct PeerData* peer = (struct PeerData*) cls;
242
243   // peer->op contains handle to the TESTBED_connect_service operation
244   // calling operation done, leads to call to scalarproduct_da
245   if (peer->op != NULL)
246     {
247       if (peer == &peer1)
248         LOG (GNUNET_ERROR_TYPE_INFO, "Disconnecting Peer1\n\n");
249       else if (peer == &peer2)
250         LOG (GNUNET_ERROR_TYPE_INFO, "Disconnecting Peer2\n\n");
251
252       GNUNET_TESTBED_operation_done (peer->op);
253       peer->op = NULL;
254     }
255
256   if (peer1.op == NULL && peer2.op == NULL)
257     GNUNET_SCHEDULER_add_now (&do_close, NULL);
258 }
259
260
261 /**
262  * Something went wrong and timed out. Kill everything and set error flag
263  */
264 static void
265 do_abort (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
266 {
267   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "test: ABORT due to Timeout\n");
268   ok = GNUNET_SYSERR;
269   abort_task = GNUNET_SCHEDULER_NO_TASK;
270   GNUNET_SCHEDULER_add_now (&do_shutdown, &peer1);
271   GNUNET_SCHEDULER_add_now (&do_shutdown, &peer2);
272 }
273
274
275 /**
276  * Controller event callback
277  *
278  * @param cls NULL
279  * @param event the controller event
280  */
281 static void
282 controller_event_cb (void *cls,
283                      const struct GNUNET_TESTBED_EventInformation *event)
284 {
285   switch (event->type)
286     {
287     case GNUNET_TESTBED_ET_OPERATION_FINISHED:
288       switch (setup_state)
289         {
290         case PEER1_SCALARPRODUCT_CONNECT:
291         case PEER2_SCALARPRODUCT_CONNECT:
292           GNUNET_assert (NULL == event->details.operation_finished.emsg);
293           break;
294         default:
295           GNUNET_assert (0);
296         }
297       break;
298     default:
299       GNUNET_assert (0);
300     }
301 }
302
303
304 static void
305 responder_callback (void *cls,
306                     const struct GNUNET_HashCode * key,
307                     enum GNUNET_SCALARPRODUCT_ResponseStatus status)
308 {
309   if (status == GNUNET_SCALARPRODUCT_Status_Failure)
310     {
311       LOG (GNUNET_ERROR_TYPE_WARNING, "Responder Client received status failure\n");
312       responder_ok = -1;
313     }
314   else if (status == GNUNET_SCALARPRODUCT_Status_InvalidResponse)
315     {
316       LOG (GNUNET_ERROR_TYPE_WARNING, "Responder Client received status invalid response\n");
317       responder_ok = -1;
318     }
319   else if (GNUNET_SCALARPRODUCT_Status_Timeout == status)
320     {
321       LOG (GNUNET_ERROR_TYPE_WARNING, "Responder Client received timeout occured\n");
322       // In this regression test, requester is supposed to fail due to timeout
323       // therefore responder_ok is set to 1, to make regression test pass
324       responder_ok = 1;
325     }
326   else if (GNUNET_SCALARPRODUCT_Status_ServiceDisconnected == status)
327     {
328       LOG (GNUNET_ERROR_TYPE_WARNING, "Responder Client received service disconnected!!\n");
329       responder_ok = -1;
330     }
331   else if (GNUNET_SCALARPRODUCT_Status_Success == status)
332     {
333       LOG (GNUNET_ERROR_TYPE_DEBUG, "Responder Client expected response received!\n");
334       responder_ok = 1;
335     }
336   else
337     {
338       LOG (GNUNET_ERROR_TYPE_WARNING, "Responder Client status = %d!\n", (int) status);
339       responder_ok = -1;
340     }
341   // TODO : Responder Session Complete. Shutdown Test Cleanly!!!
342   //do_shutdown(&peer1, NULL);
343   GNUNET_SCHEDULER_add_now (&do_shutdown, &peer1);
344   return;
345 }
346
347
348 static void
349 requester_callback (void *cls,
350                     const struct GNUNET_HashCode * key,
351                     const struct GNUNET_PeerIdentity * peer,
352                     enum GNUNET_SCALARPRODUCT_ResponseStatus status,
353                     uint16_t size, struct GNUNET_SCALARPRODUCT_client_response *msg,
354                     uint16_t type)
355 {
356   uint32_t product_len;
357
358   if (status == GNUNET_SCALARPRODUCT_Status_Failure)
359     {
360       LOG (GNUNET_ERROR_TYPE_WARNING, "Requester Client received status failure\n");
361       // In this regression test, requester is supposed to receive status failure
362       // therefore requester_ok is set to 1, to make regression test pass
363       requester_ok = 1;
364     }
365   else if (status == GNUNET_SCALARPRODUCT_Status_InvalidResponse)
366     {
367       LOG (GNUNET_ERROR_TYPE_WARNING, "Requester Client received status invalid response\n");
368       requester_ok = -1;
369     }
370   else if (GNUNET_SCALARPRODUCT_Status_Timeout == status)
371     {
372       LOG (GNUNET_ERROR_TYPE_WARNING, "Requester Client timeout occured\n");
373       requester_ok = -1;
374     }
375   else if (GNUNET_SCALARPRODUCT_Status_ServiceDisconnected == status)
376     {
377       LOG (GNUNET_ERROR_TYPE_WARNING, "Requester Client service disconnected!!\n");
378       requester_ok = -1;
379     }
380   else if (GNUNET_SCALARPRODUCT_Status_Success != status)
381     {
382       LOG (GNUNET_ERROR_TYPE_WARNING, "Requester Client Status = %d\n", (int) status);
383       requester_ok = -1;
384     }
385   else if (GNUNET_SCALARPRODUCT_Status_Success == status)
386     {
387       LOG (GNUNET_ERROR_TYPE_DEBUG, "Requester Client expected response received!\n");
388
389       product_len = ntohl (msg->product_length);
390
391       if (0 < product_len)
392         {
393           gcry_mpi_t result;
394           gcry_error_t ret = 0;
395           size_t read = 0;
396
397           ret = gcry_mpi_scan (&result, GCRYMPI_FMT_USG, (void *) &msg[1], product_len, &read);
398
399           if (0 != ret)
400             {
401               GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not convert to mpi to value!\n");
402               ok = -1;
403             }
404           else
405             {
406               uint16_t i = 0;
407
408               // calculate expected product 
409               gcry_mpi_t expected_result;
410               gcry_mpi_t v1;
411               gcry_mpi_t v2;
412               gcry_mpi_t v1_v2_prod;
413
414               expected_result = gcry_mpi_new (0);
415
416               for (i = 0; i < element_count_peer1; i++)
417                 {
418                   uint32_t value;
419                   v1_v2_prod = gcry_mpi_new (0);
420
421                   // long to gcry_mpi_t
422                   value = elements_peer1[i] >= 0 ? elements_peer1[i] : -elements_peer1[i];
423                   if (elements_peer1[i] < 0)
424                     {
425                       v1 = gcry_mpi_new (0);
426                       gcry_mpi_sub_ui (v1, v1, value);
427                     }
428                   else
429                     v1 = gcry_mpi_set_ui (NULL, value);
430
431                   // long to gcry_mpi_t
432                   value = elements_peer2[i] >= 0 ? elements_peer2[i] : -elements_peer2[i];
433                   if (elements_peer2[i] < 0)
434                     {
435                       v2 = gcry_mpi_new (0);
436                       gcry_mpi_sub_ui (v2, v2, value);
437                     }
438                   else
439                     v2 = gcry_mpi_set_ui (NULL, value);
440
441                   gcry_mpi_mul (v1_v2_prod, v1, v2);
442                   gcry_mpi_add (expected_result, expected_result, v1_v2_prod);
443
444                   gcry_mpi_release (v1);
445                   gcry_mpi_release (v2);
446                   gcry_mpi_release (v1_v2_prod);
447
448                 }
449
450               // compare the result
451               if (!gcry_mpi_cmp (expected_result, result))
452                 {
453                   LOG (GNUNET_ERROR_TYPE_DEBUG, "Scalar Product matches expected Result!!\n");
454                   requester_ok = 1;
455                 }
456               else
457                 {
458                   LOG (GNUNET_ERROR_TYPE_WARNING, "Scalar Product DOES NOT match expected Result!!\n");
459                   requester_ok = -1;
460                 }
461               gcry_mpi_release (result);
462               gcry_mpi_release (expected_result);
463             }
464         }
465       else
466         { //currently not used, but if we get more info due to MESH we will need this
467           LOG (GNUNET_ERROR_TYPE_WARNING, "Error during computation of vector product, return code: %d\n", product_len);
468           requester_ok = -1;
469         }
470     }
471
472   //do_shutdown(&peer2, NULL);
473   GNUNET_SCHEDULER_add_now (&do_shutdown, &peer2);
474   return;
475 }
476
477
478 static struct GNUNET_SCALARPRODUCT_QueueEntry *
479 requester_request ()
480 {
481   GNUNET_assert (peer2.vh != NULL);
482
483   unsigned int i;
484   //uint16_t element_count_peer2 = 0;
485   uint16_t mask_length = 0;
486   char * begin = input_elements_peer2;
487   char * end;
488   int32_t element;
489
490   struct GNUNET_SCALARPRODUCT_QueueEntry *qe;
491
492   struct GNUNET_HashCode key;
493   GNUNET_CRYPTO_hash (input_key, strlen (input_key), &key);
494
495   int exit_loop = 0;
496   /* Read input_elements_peer2, and put in elements_peer2 array */
497   do
498     {
499       unsigned int mcount = element_count_peer2;
500       //ignore empty rows of ,,,,,,
501       while (*begin == ',')
502         begin++;
503       // get the length of the current element and replace , with null
504       for (end = begin; *end && *end != ','; end++);
505
506       if (*end == '\0')
507         exit_loop = 1;
508
509       if (1 != sscanf (begin, "%" SCNd32, &element))
510         {
511           FPRINTF (stderr, _ ("Could not convert `%s' to int32_t.\n"), begin);
512           ok = -1;
513           return NULL;
514         }
515
516       GNUNET_array_append (elements_peer2, mcount, element);
517       element_count_peer2++;
518
519       begin = ++end;
520     }
521   while (!exit_loop && element_count_peer2 < max_mids);
522
523   GNUNET_assert (elements_peer2 != NULL);
524   GNUNET_assert (element_count_peer2 >= 1);
525   mask_length = element_count_peer2 / 8 + (element_count_peer2 % 8 ? 1 : 0);
526   mask_peer2 = GNUNET_malloc ((element_count_peer2 / 8) + 2);
527   GNUNET_assert (NULL != mask_peer2);
528
529   /* Read input_mask_peer2 and read in mask_peer2 array */
530   if (NULL != input_mask_peer2)
531     {
532       begin = input_mask_peer2;
533       unsigned short mask_count = 0;
534       int exit_loop = 0;
535
536       do
537         {
538           //ignore empty rows of ,,,,,,
539           while (* begin == ',')
540             begin++;
541           // get the length of the current element and replace , with null
542           // gnunet_ascii-armor uses base32, thus we can use , as separator!
543           for (end = begin; *end && *end != ','; end++);
544
545           if (*end == '\0')
546             exit_loop = 1;
547
548           if (1 != sscanf (begin, "%" SCNd32, &element))
549             {
550               FPRINTF (stderr, _ ("Could not convert `%s' to int32_t.\n"), begin);
551               ok = -1;
552               return NULL;
553             }
554
555           GNUNET_assert (mask_count <= element_count_peer2);
556
557           if (element)
558             mask_peer2[mask_count / 8] = mask_peer2[mask_count / 8] | 1 << (mask_count % 8);
559
560           mask_count++;
561           begin = ++end;
562         }
563       while (!exit_loop);
564       // +1 to see if we would have more data, which would indicate malformed/superficial input
565       GNUNET_assert (mask_count == element_count_peer2);
566     }
567   else
568     {
569       for (i = 0; i <= mask_length; i++)
570         mask_peer2[i] = UCHAR_MAX; // all 1's
571     }
572
573   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Responder peer key %s\n", &peer1.our_id);
574
575   // TODO : Create the mask array
576   qe = GNUNET_SCALARPRODUCT_request (peer2.vh,
577                                      &key,
578                                      &peer1.our_id,
579                                      element_count_peer2,
580                                      mask_length,
581                                      elements_peer2, mask_peer2,
582                                      GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
583                                      &requester_callback,
584                                      NULL);
585
586   if (qe == NULL)
587     {
588       FPRINTF (stderr, "%s", _ ("Could not send request to scalarproduct service! Exitting!"));
589       ok = -1;
590       return NULL;
591     }
592
593   return qe;
594 }
595
596
597 /**
598  * Function prepares the message to be sent by peer1 to its scalarproduct service
599  * to prepare response, and wait for a request session to be initiated by peer1
600  */
601 static struct GNUNET_SCALARPRODUCT_QueueEntry *
602 responder_prepare_response ()
603 {
604   GNUNET_assert (peer1.vh != NULL);
605
606   unsigned int i;
607   //uint16_t element_count_peer1 = 0;
608   char * begin = input_elements_peer1;
609   char * end;
610   int32_t element;
611
612   struct GNUNET_SCALARPRODUCT_QueueEntry *qe;
613
614   struct GNUNET_HashCode key;
615   GNUNET_CRYPTO_hash (input_key, strlen (input_key), &key);
616
617   int exit_loop = 0;
618   /* Read input_elements_peer1, and put in elements_peer1 array */
619   do
620     {
621       unsigned int mcount = element_count_peer1;
622       //ignore empty rows of ,,,,,,
623       while (*begin == ',')
624         begin++;
625       // get the length of the current element and replace , with null
626       for (end = begin; *end && *end != ','; end++);
627
628       if (*end == '\0')
629         exit_loop = 1;
630
631       if (*end == ',')
632         *end = '\0';
633
634       if (1 != sscanf (begin, "%" SCNd32, &element))
635         {
636           FPRINTF (stderr, _ ("Could not convert `%s' to int32_t.\n"), begin);
637           ok = -1;
638           return NULL;
639         }
640
641       GNUNET_array_append (elements_peer1, mcount, element);
642       element_count_peer1++;
643
644       begin = ++end;
645     }
646   while (!exit_loop && element_count_peer1 < max_mids);
647
648   GNUNET_assert (elements_peer1 != NULL);
649   GNUNET_assert (element_count_peer1 >= 1);
650
651   qe = GNUNET_SCALARPRODUCT_prepare_response (peer1.vh,
652                                               &key,
653                                               element_count_peer1,
654                                               elements_peer1,
655                                               GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
656                                               &responder_callback,
657                                               NULL);
658
659   if (qe == NULL)
660     {
661       FPRINTF (stderr, "%s", _ ("Could not send request to scalarproduct service! Exitting!"));
662       ok = -1;
663       return NULL;
664     }
665   return qe;
666 }
667
668
669 /**
670  * Scheduler task to initiate requester client
671  * 
672  * @param cls void* to struct PeerData
673  * @param tc Task Context
674  */
675 static void
676 request_task (void *cls,
677               const struct GNUNET_SCHEDULER_TaskContext
678               * tc)
679 {
680   struct PeerData * peer = cls;
681
682   requester_request ();
683   return;
684 }
685
686
687 /**
688  * Scheduler task to initiate responder client
689  * 
690  * @param cls void* to struct PeerData
691  * @param tc Task Context
692  */
693 static void
694 prepare_response_task (void *cls,
695                        const struct GNUNET_SCHEDULER_TaskContext
696                        * tc)
697 {
698   struct PeerData * peer = cls;
699
700   responder_prepare_response ();
701   return;
702 }
703
704
705 static void
706 peer_stop_callback (void *cls,
707                     const char *emsg)
708 {
709   GNUNET_TESTBED_peer_destroy (peer2.peer);
710 }
711
712 /**
713  * Destroys Peer2 i.e. the initiator peer (Alice) This function is scheduled to
714  * run a few milliseconds after the request has been sent to the Responding Peer (Bob).
715  * This function tries to emulate a crash of Peer2.
716  * 
717  * @param cls Not used
718  * @param tc Task Context - Not used
719  */
720 static void
721 destroy_server (void *cls,
722                 const struct GNUNET_SCHEDULER_TaskContext *tc)
723 {
724   LOG (GNUNET_ERROR_TYPE_INFO, "\n***\nKilling the Requesting Client, hopefully before it receives response\n***\n");
725   do_shutdown (&peer2, NULL);
726   GNUNET_TESTBED_peer_stop (peer2.peer, &peer_stop_callback, NULL);
727 }
728
729
730 /**
731  * Adapter function called to destroy a connection to
732  * a service. This function is called when GNUNET_TESTBED_operation_done is
733  * called for peer->op, which holds the handle for GNUNET_TESTBED_service_connect
734  * operation.
735  * 
736  * @param cls closure
737  * @param op_result service handle returned from the connect adapter
738  */
739 static void
740 scalarproduct_da (void *cls, void *op_result)
741 {
742   struct PeerData* peer = (struct PeerData*) cls;
743
744   GNUNET_SCALARPRODUCT_disconnect (peer->vh);
745   return;
746 }
747
748
749 /**
750  * Adapter function called to establish a connection to
751  * a service. This function is called to by GNUNET_TESTBED_service_connect.
752  * 
753  * @param cls closure
754  * @param cfg configuration of the peer to connect to; will be available until
755  *          GNUNET_TESTBED_operation_done() is called on the operation returned
756  *          from GNUNET_TESTBED_service_connect()
757  * @return service handle to return in 'op_result', NULL on error
758  */
759 static void *
760 scalarproduct_ca (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg)
761 {
762   struct PeerData *p = cls;
763
764   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') started\n", (&peer1 == p) ? 1 : 2,
765               GNUNET_i2s (&p->our_id));
766
767   switch (setup_state)
768     {
769     case PEER1_SCALARPRODUCT_CONNECT:
770       /* Connect peer 2 to scalarproduct service */
771       /* The connect adapter scalarproduct_ca will be called to perform the actual connection */
772       {
773         peer2.op = GNUNET_TESTBED_service_connect (&peer2, peer2.peer, "scalarproduct",
774                                                    NULL, NULL, scalarproduct_ca,
775                                                    scalarproduct_da, &peer2);
776         setup_state = PEER2_SCALARPRODUCT_CONNECT;
777       }
778
779       /* Actually connect peer 1 to scalarproduct service */
780       peer1.vh = GNUNET_SCALARPRODUCT_connect (cfg);
781       return peer1.vh;
782
783     case PEER2_SCALARPRODUCT_CONNECT:
784       /* Actually connect peer 2 to scalarproduct service */
785       peer2.vh = GNUNET_SCALARPRODUCT_connect (cfg);
786
787
788       if (peer1.vh != NULL && peer2.vh != NULL)
789         {
790           GNUNET_SCHEDULER_add_now (&prepare_response_task, &peer1);
791           GNUNET_SCHEDULER_add_now (&request_task, &peer2);
792           GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 6),
793                                         &destroy_server, NULL);
794         }
795       else
796         {
797           // TODO : Handle error. One of the peers is not connected. Cleanly shutdown
798           ok = -1;
799           return NULL;
800         }
801       return peer2.vh;
802     default:
803       GNUNET_assert (0);
804     }
805 }
806
807
808 /**
809  * Callback to be called when the requested peer information is available
810  *
811  * @param cb_cls the closure from GNUNET_TETSBED_peer_get_information()
812  * @param op the operation this callback corresponds to
813  * @param pinfo the result; will be NULL if the operation has failed
814  * @param emsg error message if the operation has failed; will be NULL if the
815  *          operation is successfull
816  */
817 static void
818 peerinfo_cb (void *cb_cls, struct GNUNET_TESTBED_Operation *op_,
819              const struct GNUNET_TESTBED_PeerInformation *pinfo,
820              const char *emsg)
821 {
822   GNUNET_assert (NULL == emsg);
823   GNUNET_assert (op == op_);
824   switch (setup_state)
825     {
826     case PEER1_GET_IDENTITY:
827       {
828         memcpy (&peer1.our_id, pinfo->result.id,
829                 sizeof (struct GNUNET_PeerIdentity));
830         GNUNET_TESTBED_operation_done (op);
831
832         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer 1 id: %s\n", GNUNET_i2s_full
833                     (&peer1.our_id));
834
835         /* Request for peer id of peer 2*/
836         op = GNUNET_TESTBED_peer_get_information (peer2.peer,
837                                                   GNUNET_TESTBED_PIT_IDENTITY,
838                                                   &peerinfo_cb, NULL);
839         setup_state = PEER2_GET_IDENTITY;
840       }
841       break;
842     case PEER2_GET_IDENTITY:
843       {
844         memcpy (&peer2.our_id, pinfo->result.id,
845                 sizeof (struct GNUNET_PeerIdentity));
846         GNUNET_TESTBED_operation_done (op);
847
848         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer 2 id: %s\n", GNUNET_i2s_full
849                     (&peer2.our_id));
850
851         /* Connect peer 1 to scalarproduct service */
852         /* The connect adapter scalarproduct_ca will be called to perform the actual connection */
853         peer1.op = GNUNET_TESTBED_service_connect (&peer1, peer1.peer, "scalarproduct",
854                                                    NULL, NULL, scalarproduct_ca,
855                                                    scalarproduct_da, &peer1);
856         setup_state = PEER1_SCALARPRODUCT_CONNECT;
857       }
858       break;
859     default:
860       GNUNET_assert (0);
861     }
862 }
863
864
865 /**
866  * Signature of a main function for a testcase.
867  *
868  * @param cls closure
869  * @param num_peers number of peers in 'peers'
870  * @param peers handle to peers run in the testbed
871  */
872 static void
873 test_master (void *cls, unsigned int num_peers,
874              struct GNUNET_TESTBED_Peer **peers)
875 {
876   GNUNET_assert (NULL != peers);
877   GNUNET_assert (NULL != peers[0]);
878   GNUNET_assert (NULL != peers[1]);
879   peer1.peer = peers[0];
880   peer2.peer = peers[1];
881   /* Get the peer identity and configuration of peer 1 */
882   op = GNUNET_TESTBED_peer_get_information (peer1.peer,
883                                             GNUNET_TESTBED_PIT_IDENTITY,
884                                             &peerinfo_cb, NULL);
885   setup_state = PEER1_GET_IDENTITY;
886   abort_task =
887           GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
888                                         (GNUNET_TIME_UNIT_SECONDS, 20), &do_abort,
889                                         NULL);
890 }
891
892
893 /**
894  * Main function
895  */
896 int
897 main (int argc, char **argv)
898 {
899   uint64_t event_mask;
900
901   ok = GNUNET_NO;
902   event_mask = 0;
903   event_mask |= (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED);
904   max_mids = (GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct GNUNET_MessageHeader))
905           / sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1;
906
907   (void) GNUNET_TESTBED_test_run ("test_scalarproduct_api_regression2",
908                                   "test_scalarproduct_api_data.conf",
909                                   NUM_PEERS, event_mask, &controller_event_cb,
910                                   NULL,
911                                   &test_master, NULL);
912   if (GNUNET_SYSERR == ok)
913     {
914       LOG (GNUNET_ERROR_TYPE_ERROR, "Test failing due to some error before calling API for request or prepare_response\n");
915       return 1;
916     }
917   else if (GNUNET_SYSERR == responder_ok)
918     {
919       LOG (GNUNET_ERROR_TYPE_ERROR, "Test failing due to some error in response for responding_client\n");
920       return 1;
921     }
922   else if (GNUNET_SYSERR == requester_ok)
923     {
924       LOG (GNUNET_ERROR_TYPE_ERROR, "Test failing due to some error in response for requesting client\n");
925       return 1;
926     }
927   else
928     return 0;
929 }
930
931