2 This file is part of GNUnet.
3 (C) 2013 Christian Grothoff (and other contributing authors)
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.
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.
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.
22 * @file scalarproduct/test_scalarproduct_api_regression2.c
23 * @brief Regression test, destroys requester service before receiving response
25 * @author Gaurav Kukreja
26 * @author Christian Fuchs
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"
39 #define LOG(kind,...) GNUNET_log_from (kind, "test-scalarproduct-api-regression2",__VA_ARGS__)
43 * Structure for holding peer's sockets and IO Handles
48 * Handle to testbed peer
50 struct GNUNET_TESTBED_Peer *peer;
53 * The service connect operation to stream
55 struct GNUNET_TESTBED_Operation *op;
60 struct GNUNET_PeerIdentity our_id;
63 * Pointer to Vector Product Handle
65 struct GNUNET_SCALARPRODUCT_Handle *vh;
69 * Different states in test setup
74 * Get the identity of peer 1
79 * Get the identity of peer 2
84 * Connect to stream service of peer 1
86 PEER1_SCALARPRODUCT_CONNECT,
89 * Connect to stream service of peer 2
91 PEER2_SCALARPRODUCT_CONNECT
95 /******************************************************************************
96 *** Global Variables *****************************
97 ******************************************************************************/
100 * Maximum allowed message-ids we can check in one go (with one GNUNET_message)
102 static unsigned int max_mids;
105 * Session Key used by both the test peers
107 char input_key[103] = "helloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhe";
110 * Input elements for peer1
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";
116 * Input Mask for peer 1
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";
122 * the array of converted message IDs to send to our service
124 static int32_t * elements_peer1 = NULL;
127 * the array of converted message IDs to send to our service
129 static unsigned char * mask_peer1 = NULL;
134 uint16_t element_count_peer1 = 0;
137 * Input elements for peer2
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";
143 * Input Mask for peer 2
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";
149 * the array of converted message IDs to send to our service
151 static int32_t * elements_peer2 = NULL;
154 * the array of converted message IDs to send to our service
156 static unsigned char * mask_peer2 = NULL;
161 uint16_t element_count_peer2 = 0;
164 * Data context for peer 1
166 static struct PeerData peer1;
169 * Data context for peer 2
171 static struct PeerData peer2;
174 * Various states during test setup
176 static enum SetupState setup_state;
179 * Testbed operation handle
181 static struct GNUNET_TESTBED_Operation *op;
185 static int responder_ok;
187 static int requester_ok;
189 static GNUNET_SCHEDULER_TaskIdentifier abort_task;
190 /******************************************************************************
191 *** Static Functions *****************************
192 ******************************************************************************/
195 do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
199 * Close sockets and stop testing deamons nicely
202 do_close (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
206 if (peer1.op != NULL)
208 do_shutdown (&peer1, NULL);
211 if (peer2.op != NULL)
213 do_shutdown (&peer2, NULL);
216 if (GNUNET_SCHEDULER_NO_TASK != abort_task)
218 GNUNET_SCHEDULER_cancel (abort_task);
219 abort_task = GNUNET_SCHEDULER_NO_TASK;
220 GNUNET_SCHEDULER_shutdown (); /* For shutting down testbed */
226 GNUNET_SCHEDULER_shutdown (); /* For shutting down testbed */
233 * @param cls closure is a pointer to the struct PeerData of the peer to be disconnected
234 * @param tc Task Context
237 do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
241 struct PeerData* peer = (struct PeerData*) cls;
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)
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");
252 GNUNET_TESTBED_operation_done (peer->op);
256 if (peer1.op == NULL && peer2.op == NULL)
257 GNUNET_SCHEDULER_add_now (&do_close, NULL);
262 * Something went wrong and timed out. Kill everything and set error flag
265 do_abort (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
267 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "test: ABORT due to Timeout\n");
269 abort_task = GNUNET_SCHEDULER_NO_TASK;
270 GNUNET_SCHEDULER_add_now (&do_shutdown, &peer1);
271 GNUNET_SCHEDULER_add_now (&do_shutdown, &peer2);
276 * Controller event callback
279 * @param event the controller event
282 controller_event_cb (void *cls,
283 const struct GNUNET_TESTBED_EventInformation *event)
287 case GNUNET_TESTBED_ET_OPERATION_FINISHED:
290 case PEER1_SCALARPRODUCT_CONNECT:
291 case PEER2_SCALARPRODUCT_CONNECT:
292 GNUNET_assert (NULL == event->details.operation_finished.emsg);
305 responder_callback (void *cls,
306 const struct GNUNET_HashCode * key,
307 enum GNUNET_SCALARPRODUCT_ResponseStatus status)
309 if (status == GNUNET_SCALARPRODUCT_Status_Failure)
311 LOG (GNUNET_ERROR_TYPE_WARNING, "Responder Client received status failure\n");
314 else if (status == GNUNET_SCALARPRODUCT_Status_InvalidResponse)
316 LOG (GNUNET_ERROR_TYPE_WARNING, "Responder Client received status invalid response\n");
319 else if (GNUNET_SCALARPRODUCT_Status_Timeout == status)
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
326 else if (GNUNET_SCALARPRODUCT_Status_ServiceDisconnected == status)
328 LOG (GNUNET_ERROR_TYPE_WARNING, "Responder Client received service disconnected!!\n");
331 else if (GNUNET_SCALARPRODUCT_Status_Success == status)
333 LOG (GNUNET_ERROR_TYPE_DEBUG, "Responder Client expected response received!\n");
338 LOG (GNUNET_ERROR_TYPE_WARNING, "Responder Client status = %d!\n", (int) status);
341 // TODO : Responder Session Complete. Shutdown Test Cleanly!!!
342 //do_shutdown(&peer1, NULL);
343 GNUNET_SCHEDULER_add_now (&do_shutdown, &peer1);
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,
356 uint32_t product_len;
358 if (status == GNUNET_SCALARPRODUCT_Status_Failure)
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
365 else if (status == GNUNET_SCALARPRODUCT_Status_InvalidResponse)
367 LOG (GNUNET_ERROR_TYPE_WARNING, "Requester Client received status invalid response\n");
370 else if (GNUNET_SCALARPRODUCT_Status_Timeout == status)
372 LOG (GNUNET_ERROR_TYPE_WARNING, "Requester Client timeout occured\n");
375 else if (GNUNET_SCALARPRODUCT_Status_ServiceDisconnected == status)
377 LOG (GNUNET_ERROR_TYPE_WARNING, "Requester Client service disconnected!!\n");
380 else if (GNUNET_SCALARPRODUCT_Status_Success != status)
382 LOG (GNUNET_ERROR_TYPE_WARNING, "Requester Client Status = %d\n", (int) status);
385 else if (GNUNET_SCALARPRODUCT_Status_Success == status)
387 LOG (GNUNET_ERROR_TYPE_DEBUG, "Requester Client expected response received!\n");
389 product_len = ntohl (msg->product_length);
394 gcry_error_t ret = 0;
397 ret = gcry_mpi_scan (&result, GCRYMPI_FMT_USG, (void *) &msg[1], product_len, &read);
401 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not convert to mpi to value!\n");
408 // calculate expected product
409 gcry_mpi_t expected_result;
412 gcry_mpi_t v1_v2_prod;
414 expected_result = gcry_mpi_new (0);
416 for (i = 0; i < element_count_peer1; i++)
419 v1_v2_prod = gcry_mpi_new (0);
421 // long to gcry_mpi_t
422 value = elements_peer1[i] >= 0 ? elements_peer1[i] : -elements_peer1[i];
423 if (elements_peer1[i] < 0)
425 v1 = gcry_mpi_new (0);
426 gcry_mpi_sub_ui (v1, v1, value);
429 v1 = gcry_mpi_set_ui (NULL, value);
431 // long to gcry_mpi_t
432 value = elements_peer2[i] >= 0 ? elements_peer2[i] : -elements_peer2[i];
433 if (elements_peer2[i] < 0)
435 v2 = gcry_mpi_new (0);
436 gcry_mpi_sub_ui (v2, v2, value);
439 v2 = gcry_mpi_set_ui (NULL, value);
441 gcry_mpi_mul (v1_v2_prod, v1, v2);
442 gcry_mpi_add (expected_result, expected_result, v1_v2_prod);
444 gcry_mpi_release (v1);
445 gcry_mpi_release (v2);
446 gcry_mpi_release (v1_v2_prod);
450 // compare the result
451 if (!gcry_mpi_cmp (expected_result, result))
453 LOG (GNUNET_ERROR_TYPE_DEBUG, "Scalar Product matches expected Result!!\n");
458 LOG (GNUNET_ERROR_TYPE_WARNING, "Scalar Product DOES NOT match expected Result!!\n");
461 gcry_mpi_release (result);
462 gcry_mpi_release (expected_result);
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);
472 //do_shutdown(&peer2, NULL);
473 GNUNET_SCHEDULER_add_now (&do_shutdown, &peer2);
478 static struct GNUNET_SCALARPRODUCT_QueueEntry *
481 GNUNET_assert (peer2.vh != NULL);
484 //uint16_t element_count_peer2 = 0;
485 uint16_t mask_length = 0;
486 char * begin = input_elements_peer2;
490 struct GNUNET_SCALARPRODUCT_QueueEntry *qe;
492 struct GNUNET_HashCode key;
493 GNUNET_CRYPTO_hash (input_key, strlen (input_key), &key);
496 /* Read input_elements_peer2, and put in elements_peer2 array */
499 unsigned int mcount = element_count_peer2;
500 //ignore empty rows of ,,,,,,
501 while (*begin == ',')
503 // get the length of the current element and replace , with null
504 for (end = begin; *end && *end != ','; end++);
509 if (1 != sscanf (begin, "%" SCNd32, &element))
511 FPRINTF (stderr, _ ("Could not convert `%s' to int32_t.\n"), begin);
516 GNUNET_array_append (elements_peer2, mcount, element);
517 element_count_peer2++;
521 while (!exit_loop && element_count_peer2 < max_mids);
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);
529 /* Read input_mask_peer2 and read in mask_peer2 array */
530 if (NULL != input_mask_peer2)
532 begin = input_mask_peer2;
533 unsigned short mask_count = 0;
538 //ignore empty rows of ,,,,,,
539 while (* 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++);
548 if (1 != sscanf (begin, "%" SCNd32, &element))
550 FPRINTF (stderr, _ ("Could not convert `%s' to int32_t.\n"), begin);
555 GNUNET_assert (mask_count <= element_count_peer2);
558 mask_peer2[mask_count / 8] = mask_peer2[mask_count / 8] | 1 << (mask_count % 8);
564 // +1 to see if we would have more data, which would indicate malformed/superficial input
565 GNUNET_assert (mask_count == element_count_peer2);
569 for (i = 0; i <= mask_length; i++)
570 mask_peer2[i] = UCHAR_MAX; // all 1's
573 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Responder peer key %s\n", &peer1.our_id);
575 // TODO : Create the mask array
576 qe = GNUNET_SCALARPRODUCT_request (peer2.vh,
581 elements_peer2, mask_peer2,
582 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
588 FPRINTF (stderr, "%s", _ ("Could not send request to scalarproduct service! Exitting!"));
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
601 static struct GNUNET_SCALARPRODUCT_QueueEntry *
602 responder_prepare_response ()
604 GNUNET_assert (peer1.vh != NULL);
607 //uint16_t element_count_peer1 = 0;
608 char * begin = input_elements_peer1;
612 struct GNUNET_SCALARPRODUCT_QueueEntry *qe;
614 struct GNUNET_HashCode key;
615 GNUNET_CRYPTO_hash (input_key, strlen (input_key), &key);
618 /* Read input_elements_peer1, and put in elements_peer1 array */
621 unsigned int mcount = element_count_peer1;
622 //ignore empty rows of ,,,,,,
623 while (*begin == ',')
625 // get the length of the current element and replace , with null
626 for (end = begin; *end && *end != ','; end++);
634 if (1 != sscanf (begin, "%" SCNd32, &element))
636 FPRINTF (stderr, _ ("Could not convert `%s' to int32_t.\n"), begin);
641 GNUNET_array_append (elements_peer1, mcount, element);
642 element_count_peer1++;
646 while (!exit_loop && element_count_peer1 < max_mids);
648 GNUNET_assert (elements_peer1 != NULL);
649 GNUNET_assert (element_count_peer1 >= 1);
651 qe = GNUNET_SCALARPRODUCT_prepare_response (peer1.vh,
655 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
661 FPRINTF (stderr, "%s", _ ("Could not send request to scalarproduct service! Exitting!"));
670 * Scheduler task to initiate requester client
672 * @param cls void* to struct PeerData
673 * @param tc Task Context
676 request_task (void *cls,
677 const struct GNUNET_SCHEDULER_TaskContext
680 struct PeerData * peer = cls;
682 requester_request ();
688 * Scheduler task to initiate responder client
690 * @param cls void* to struct PeerData
691 * @param tc Task Context
694 prepare_response_task (void *cls,
695 const struct GNUNET_SCHEDULER_TaskContext
698 struct PeerData * peer = cls;
700 responder_prepare_response ();
706 peer_stop_callback (void *cls,
709 GNUNET_TESTBED_peer_destroy (peer2.peer);
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.
717 * @param cls Not used
718 * @param tc Task Context - Not used
721 destroy_server (void *cls,
722 const struct GNUNET_SCHEDULER_TaskContext *tc)
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);
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
737 * @param op_result service handle returned from the connect adapter
740 scalarproduct_da (void *cls, void *op_result)
742 struct PeerData* peer = (struct PeerData*) cls;
744 GNUNET_SCALARPRODUCT_disconnect (peer->vh);
750 * Adapter function called to establish a connection to
751 * a service. This function is called to by GNUNET_TESTBED_service_connect.
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
760 scalarproduct_ca (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg)
762 struct PeerData *p = cls;
764 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') started\n", (&peer1 == p) ? 1 : 2,
765 GNUNET_i2s (&p->our_id));
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 */
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;
779 /* Actually connect peer 1 to scalarproduct service */
780 peer1.vh = GNUNET_SCALARPRODUCT_connect (cfg);
783 case PEER2_SCALARPRODUCT_CONNECT:
784 /* Actually connect peer 2 to scalarproduct service */
785 peer2.vh = GNUNET_SCALARPRODUCT_connect (cfg);
788 if (peer1.vh != NULL && peer2.vh != NULL)
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);
797 // TODO : Handle error. One of the peers is not connected. Cleanly shutdown
809 * Callback to be called when the requested peer information is available
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
818 peerinfo_cb (void *cb_cls, struct GNUNET_TESTBED_Operation *op_,
819 const struct GNUNET_TESTBED_PeerInformation *pinfo,
822 GNUNET_assert (NULL == emsg);
823 GNUNET_assert (op == op_);
826 case PEER1_GET_IDENTITY:
828 memcpy (&peer1.our_id, pinfo->result.id,
829 sizeof (struct GNUNET_PeerIdentity));
830 GNUNET_TESTBED_operation_done (op);
832 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer 1 id: %s\n", GNUNET_i2s_full
835 /* Request for peer id of peer 2*/
836 op = GNUNET_TESTBED_peer_get_information (peer2.peer,
837 GNUNET_TESTBED_PIT_IDENTITY,
839 setup_state = PEER2_GET_IDENTITY;
842 case PEER2_GET_IDENTITY:
844 memcpy (&peer2.our_id, pinfo->result.id,
845 sizeof (struct GNUNET_PeerIdentity));
846 GNUNET_TESTBED_operation_done (op);
848 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer 2 id: %s\n", GNUNET_i2s_full
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;
866 * Signature of a main function for a testcase.
869 * @param num_peers number of peers in 'peers'
870 * @param peers handle to peers run in the testbed
873 test_master (void *cls, unsigned int num_peers,
874 struct GNUNET_TESTBED_Peer **peers)
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,
885 setup_state = PEER1_GET_IDENTITY;
887 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
888 (GNUNET_TIME_UNIT_SECONDS, 20), &do_abort,
897 main (int argc, char **argv)
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;
907 (void) GNUNET_TESTBED_test_run ("test_scalarproduct_api_regression2",
908 "test_scalarproduct_api_data.conf",
909 NUM_PEERS, event_mask, &controller_event_cb,
912 if (GNUNET_SYSERR == ok)
914 LOG (GNUNET_ERROR_TYPE_ERROR, "Test failing due to some error before calling API for request or prepare_response\n");
917 else if (GNUNET_SYSERR == responder_ok)
919 LOG (GNUNET_ERROR_TYPE_ERROR, "Test failing due to some error in response for responding_client\n");
922 else if (GNUNET_SYSERR == requester_ok)
924 LOG (GNUNET_ERROR_TYPE_ERROR, "Test failing due to some error in response for requesting client\n");