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_regression.c
23 * @brief VectorProduct API regression test
24 * @author Gaurav Kukreja
25 * @author Christian Fuchs
29 * AIM of the regression test
31 * This test tries to check whether the service can handle abrupt client disconnect.
33 * 1. We create a responder peer, and ask the service to prepare_response. After this,
34 * we disconnect responder peer from service.
36 * 2. Then we create a requester peer, and ask service to request another peer. We
37 * should check that the service on responder peer is still active and receives
38 * request from the requester. We then disconnect requester peer from service. Both
39 * the requester and responder service should handle this cleanly.
46 #include "gnunet_util_lib.h"
47 #include "gnunet_testbed_service.h"
48 #include "gnunet_common.h"
49 #include "gnunet_scalarproduct_service.h"
50 #include "gnunet_protocols.h"
52 #define LOG(kind,...) GNUNET_log_from (kind, "test-scalarproduct-api-regression",__VA_ARGS__)
56 * Structure for holding peer's sockets and IO Handles
61 * Handle to testbed peer
63 struct GNUNET_TESTBED_Peer *peer;
66 * The service connect operation to stream
68 struct GNUNET_TESTBED_Operation *op;
73 struct GNUNET_PeerIdentity our_id;
76 * Pointer to Vector Product Handle
78 struct GNUNET_SCALARPRODUCT_Handle *vh;
82 * Different states in test setup
87 * Get the identity of peer 1
92 * Get the identity of peer 2
97 * Connect to stream service of peer 1
99 PEER1_SCALARPRODUCT_CONNECT,
102 * Connect to stream service of peer 2
104 PEER2_SCALARPRODUCT_CONNECT
108 /******************************************************************************
109 *** Global Variables *****************************
110 ******************************************************************************/
113 * Maximum allowed message-ids we can check in one go (with one GNUNET_message)
115 static unsigned int max_mids;
118 * Session Key used by both the test peers
120 char input_key[103] = "helloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhe";
123 * Input elements for peer1
125 //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";
126 char input_elements_peer1[] = "11,11,11";
129 * Input Mask for peer 1
131 //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";
132 char input_mask_peer1[] = "1,1,1";
135 * the array of converted message IDs to send to our service
137 static int32_t * elements_peer1 = NULL;
140 * Input elements for peer2
142 //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";
143 char input_elements_peer2[] = "11,11,11";
145 * Input Mask for peer 2
147 //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";
148 char input_mask_peer2[] = "1,1,1";
150 * the array of converted message IDs to send to our service
152 static int32_t * elements_peer2 = NULL;
155 * the array of converted message IDs to send to our service
157 static unsigned char * mask_peer2 = NULL;
160 * Data context for peer 1
162 static struct PeerData peer1;
165 * Data context for peer 2
167 static struct PeerData peer2;
170 * Various states during test setup
172 static enum SetupState setup_state;
175 * Testbed operation handle
177 static struct GNUNET_TESTBED_Operation *op;
180 * Return value of the test.
185 * Abort Task for timeout
187 static GNUNET_SCHEDULER_TaskIdentifier abort_task;
188 /******************************************************************************
189 *** Static Functions *****************************
190 ******************************************************************************/
193 * Helper function to shutdown a test peer
195 * @param cls void* to struct PeerData of the peer to be disconnected
196 * @param tc Task Context
199 do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
203 * Helper function to connect a test peer
205 * @param cls void* to struct PeerData of the peer to be connected
206 * @param tc Task Context
209 connect_peer (void *cls,
210 const struct GNUNET_SCHEDULER_TaskContext * tc);
214 * Close sockets and stop testing deamons nicely
217 do_close (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
220 if (peer1.op != NULL)
221 do_shutdown (&peer1, NULL);
223 if (peer2.op != NULL)
224 do_shutdown (&peer2, NULL);
226 if (GNUNET_SCHEDULER_NO_TASK != abort_task)
227 GNUNET_SCHEDULER_cancel (abort_task);
229 GNUNET_SCHEDULER_shutdown (); /* For shutting down testbed */
234 * Helper function to shutdown a test peer
236 * @param cls void* to struct PeerData of the peer to be disconnected
237 * @param tc Task Context
240 do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
244 struct PeerData* peer = (struct PeerData*) cls;
247 LOG (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting Peer1\n\n");
248 else if (peer == &peer2)
249 LOG (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting Peer2\n\n");
251 // peer->op contains handle to the TESTBED_connect_service operation
252 // calling operation done, leads to call to scalarproduct_da
253 if (peer->op != NULL)
255 GNUNET_TESTBED_operation_done (peer->op);
260 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 10), &do_close, NULL);
265 * Something went wrong and timed out. Kill everything and set error flag
268 do_abort (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
270 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "test: ABORT due to Timeout\n");
278 * Controller event callback
281 * @param event the controller event
284 controller_event_cb (void *cls,
285 const struct GNUNET_TESTBED_EventInformation *event)
289 case GNUNET_TESTBED_ET_OPERATION_FINISHED:
292 case PEER1_SCALARPRODUCT_CONNECT:
293 case PEER2_SCALARPRODUCT_CONNECT:
294 GNUNET_assert (NULL == event->details.operation_finished.emsg);
307 * Callback function called for the responder peer i.e. peer1
310 * @param key Session key
311 * @param status Status of the message
314 responder_callback (void *cls,
315 const struct GNUNET_HashCode * key,
316 enum GNUNET_SCALARPRODUCT_ResponseStatus status)
318 if (status == GNUNET_SCALARPRODUCT_Status_Failure)
320 LOG (GNUNET_ERROR_TYPE_WARNING, "Responder Client received status failure\n");
323 else if (status == GNUNET_SCALARPRODUCT_Status_InvalidResponse)
325 LOG (GNUNET_ERROR_TYPE_WARNING, "Responder Client received status invalid response\n");
328 else if (GNUNET_SCALARPRODUCT_Status_Timeout == status)
330 LOG (GNUNET_ERROR_TYPE_WARNING, "Responder Client received timeout occured\n");
333 else if (GNUNET_SCALARPRODUCT_Status_ServiceDisconnected == status)
335 LOG (GNUNET_ERROR_TYPE_WARNING, "Responder Client received service disconnected!!\n");
338 else if (GNUNET_SCALARPRODUCT_Status_Success == status)
340 LOG (GNUNET_ERROR_TYPE_DEBUG, "Responder Client expected response received!\n");
345 LOG (GNUNET_ERROR_TYPE_WARNING, "Responder Client status = %d!\n", (int) status);
349 // Not shutting down this time, only for this regression test. We have shutdown explicitly earlier.
350 // Shutting down again is causing problems.
352 // if(peer1.vh != NULL)
354 // GNUNET_SCHEDULER_add_now(&do_shutdown, &peer1);
361 * Callback function called for the requester peer i.e. peer2
364 * @param key Session key
365 * @param status Status of the message
368 requester_callback (void *cls,
369 const struct GNUNET_HashCode * key,
370 const struct GNUNET_PeerIdentity * peer,
371 enum GNUNET_SCALARPRODUCT_ResponseStatus status,
372 const struct GNUNET_SCALARPRODUCT_client_response *msg)
374 uint32_t product_len;
376 if (status == GNUNET_SCALARPRODUCT_Status_Failure)
378 LOG (GNUNET_ERROR_TYPE_WARNING, "Requester Client received status failure\n");
381 else if (status == GNUNET_SCALARPRODUCT_Status_InvalidResponse)
383 LOG (GNUNET_ERROR_TYPE_WARNING, "Requester Client received status invalid response\n");
386 else if (GNUNET_SCALARPRODUCT_Status_Timeout == status)
388 LOG (GNUNET_ERROR_TYPE_WARNING, "Requester Client timeout occured\n");
391 else if (GNUNET_SCALARPRODUCT_Status_ServiceDisconnected == status)
393 LOG (GNUNET_ERROR_TYPE_WARNING, "Requester Client service disconnected!!\n");
396 else if (GNUNET_SCALARPRODUCT_Status_Success != status)
398 LOG (GNUNET_ERROR_TYPE_DEBUG, "Requester Client Status = %d\n", (int) status);
401 else if (GNUNET_SCALARPRODUCT_Status_Success == status)
403 product_len = ntohl (msg->product_length);
408 gcry_error_t ret = 0;
411 ret = gcry_mpi_scan (&result, GCRYMPI_FMT_USG, (void *) &msg[1], product_len, &read);
415 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Could not convert to mpi to value!\n");
419 gcry_mpi_dump (result);
420 gcry_mpi_release (result);
425 { //currently not used, but if we get more info due to MESH we will need this
426 LOG (GNUNET_ERROR_TYPE_WARNING, "Error during computation of vector product, return code: %d\n", product_len);
431 // Not shutting down this time, only for this regression test. We have shutdown explicitly earlier.
432 // Shutting down again is causing problems.
434 // if(peer2.vh != NULL)
436 // GNUNET_SCHEDULER_add_now(&do_shutdown, &peer2);
443 requester_request (void *cls,
444 const struct GNUNET_SCHEDULER_TaskContext * tc)
446 GNUNET_assert (peer2.vh != NULL);
449 uint16_t element_count = 0;
450 uint16_t mask_length = 0;
451 char * begin = input_elements_peer2;
454 struct GNUNET_SCALARPRODUCT_QueueEntry *qe;
455 struct GNUNET_HashCode key;
458 GNUNET_CRYPTO_hash (input_key, strlen (input_key), &key);
460 /* Read input_elements_peer2, and put in elements_peer2 array */
464 unsigned int mcount = element_count;
465 //ignore empty rows of ,,,,,,
466 while (*begin == ',')
468 // get the length of the current element and replace , with null
469 for (end = begin; *end && *end != ','; end++);
474 if (1 != sscanf (begin, "%" SCNd32, &element))
476 FPRINTF (stderr, _ ("Could not convert `%s' to int32_t.\n"), begin);
481 GNUNET_array_append (elements_peer2, mcount, element);
486 while (!exit_loop && element_count < max_mids);
487 GNUNET_assert (elements_peer2 != NULL);
488 GNUNET_assert (element_count >= 1);
490 /* Read input_mask_peer2 and read in mask_peer2 array */
491 mask_length = element_count / 8 + (element_count % 8 ? 1 : 0);
492 mask_peer2 = GNUNET_malloc ((element_count / 8) + 2);
493 GNUNET_assert (NULL != mask_peer2);
494 if (NULL != input_mask_peer2)
496 begin = input_mask_peer2;
497 unsigned short mask_count = 0;
502 //ignore empty rows of ,,,,,,
503 while (* begin == ',')
505 // get the length of the current element and replace , with null
506 // gnunet_ascii-armor uses base32, thus we can use , as separator!
507 for (end = begin; *end && *end != ','; end++);
512 if (1 != sscanf (begin, "%" SCNd32, &element))
514 FPRINTF (stderr, _ ("Could not convert `%s' to int32_t.\n"), begin);
519 GNUNET_assert (mask_count <= element_count);
522 mask_peer2[mask_count / 8] = mask_peer2[mask_count / 8] | 1 << (mask_count % 8);
528 // +1 to see if we would have more data, which would indicate malformed/superficial input
529 GNUNET_assert (mask_count == element_count);
533 for (i = 0; i <= mask_length; i++)
534 mask_peer2[i] = UCHAR_MAX; // all 1's
537 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Responder peer key %s\n", &peer1.our_id);
539 qe = GNUNET_SCALARPRODUCT_request (peer2.vh,
544 elements_peer2, mask_peer2,
545 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
551 FPRINTF (stderr, "%s", _ ("Could not send request to scalarproduct service! Exitting!"));
557 * For regression, we shutdown the initiator peer, peer2, one second after
558 * issuing a request. Hopefully, peer1 notices that the tunnel has been
559 * been destroyed, and will shutdown cleanly.
561 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &do_shutdown, &peer2);
568 * Function prepares the message to be sent by peer1 to its scalarproduct service
569 * to prepare response, and wait for a request session to be initiated by peer1
572 responder_prepare_response (void *cls,
573 const struct GNUNET_SCHEDULER_TaskContext * tc)
575 GNUNET_assert (peer1.vh != NULL);
577 uint16_t element_count = 0;
578 char * begin = input_elements_peer1;
582 struct GNUNET_SCALARPRODUCT_QueueEntry *qe;
584 struct GNUNET_HashCode key;
585 GNUNET_CRYPTO_hash (input_key, strlen (input_key), &key);
588 /* Read input_elements_peer1, and put in elements_peer1 array */
591 unsigned int mcount = element_count;
592 //ignore empty rows of ,,,,,,
593 while (*begin == ',')
595 // get the length of the current element and replace , with null
596 for (end = begin; *end && *end != ','; end++);
601 if (1 != sscanf (begin, "%" SCNd32, &element))
603 FPRINTF (stderr, _ ("Could not convert `%s' to int32_t.\n"), begin);
608 GNUNET_array_append (elements_peer1, mcount, element);
613 while (!exit_loop && element_count < max_mids);
615 GNUNET_assert (elements_peer1 != NULL);
616 GNUNET_assert (element_count >= 1);
618 qe = GNUNET_SCALARPRODUCT_prepare_response (peer1.vh,
622 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
628 FPRINTF (stderr, "%s", _ ("Could not send request to scalarproduct service! Exitting!"));
633 // connect the second peer
634 setup_state = PEER2_SCALARPRODUCT_CONNECT;
635 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1), &connect_peer, &peer2);
637 // while the service is waiting for a matching request, disconnect the test client
638 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &do_shutdown, &peer1);
645 * Adapter function called to destroy a connection to
646 * a service. This function is called when GNUNET_TESTBED_operation_done is
647 * called for peer->op, which holds the handle for GNUNET_TESTBED_service_connect
651 * @param op_result service handle returned from the connect adapter
654 scalarproduct_da (void *cls, void *op_result)
656 struct PeerData* peer = (struct PeerData*) cls;
658 GNUNET_SCALARPRODUCT_cancel (peer->vh);
665 * Adapter function called to establish a connection to
666 * a service. This function is called to by GNUNET_TESTBED_service_connect.
669 * @param cfg configuration of the peer to connect to; will be available until
670 * GNUNET_TESTBED_operation_done() is called on the operation returned
671 * from GNUNET_TESTBED_service_connect()
672 * @return service handle to return in 'op_result', NULL on error
675 scalarproduct_ca (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg)
677 struct PeerData *p = cls;
679 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') started\n", (&peer1 == p) ? 1 : 2,
680 GNUNET_i2s (&p->our_id));
684 case PEER1_SCALARPRODUCT_CONNECT:
685 peer1.vh = GNUNET_SCALARPRODUCT_connect (cfg);
687 if (peer1.vh != NULL)
689 /* prepare_response from peer1 */
690 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS, &responder_prepare_response, NULL);
700 case PEER2_SCALARPRODUCT_CONNECT:
701 /* Actually connect peer 2 to scalarproduct service */
702 peer2.vh = GNUNET_SCALARPRODUCT_connect (cfg);
704 if (peer2.vh != NULL)
706 /* initiate request from peer2 */
707 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS, &requester_request, NULL);
723 * Helper function to connect a test peer
725 * @param cls void* to struct PeerData of the peer to be connected
726 * @param tc Task Context
729 connect_peer (void *cls,
730 const struct GNUNET_SCHEDULER_TaskContext * tc)
732 struct PeerData *peer = cls;
734 peer->op = GNUNET_TESTBED_service_connect (peer, peer->peer, "scalarproduct",
735 NULL, NULL, scalarproduct_ca,
736 scalarproduct_da, peer);
742 * Callback to be called when the requested peer information is available
744 * @param cb_cls the closure from GNUNET_TETSBED_peer_get_information()
745 * @param op the operation this callback corresponds to
746 * @param pinfo the result; will be NULL if the operation has failed
747 * @param emsg error message if the operation has failed; will be NULL if the
748 * operation is successfull
751 peerinfo_cb (void *cb_cls, struct GNUNET_TESTBED_Operation *op_,
752 const struct GNUNET_TESTBED_PeerInformation *pinfo,
755 GNUNET_assert (NULL == emsg);
756 GNUNET_assert (op == op_);
760 case PEER1_GET_IDENTITY:
762 memcpy (&peer1.our_id, pinfo->result.id,
763 sizeof (struct GNUNET_PeerIdentity));
764 GNUNET_TESTBED_operation_done (op);
766 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer 1 id: %s\n", GNUNET_i2s_full
769 /* Request for peer id of peer 2*/
770 setup_state = PEER2_GET_IDENTITY;
771 op = GNUNET_TESTBED_peer_get_information (peer2.peer,
772 GNUNET_TESTBED_PIT_IDENTITY,
776 case PEER2_GET_IDENTITY:
778 memcpy (&peer2.our_id, pinfo->result.id,
779 sizeof (struct GNUNET_PeerIdentity));
780 GNUNET_TESTBED_operation_done (op);
782 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer 2 id: %s\n", GNUNET_i2s_full
785 /* Connect peer 1 to scalarproduct service */
786 setup_state = PEER1_SCALARPRODUCT_CONNECT;
787 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS, &connect_peer, &peer1);
797 * Signature of a main function for a testcase.
800 * @param num_peers number of peers in 'peers'
801 * @param peers handle to peers run in the testbed
804 test_master (void *cls, unsigned int num_peers,
805 struct GNUNET_TESTBED_Peer **peers)
807 GNUNET_assert (NULL != peers);
808 GNUNET_assert (NULL != peers[0]);
809 GNUNET_assert (NULL != peers[1]);
810 peer1.peer = peers[0];
811 peer2.peer = peers[1];
813 /* Get the peer identity and configuration of peer 1 */
814 setup_state = PEER1_GET_IDENTITY;
815 op = GNUNET_TESTBED_peer_get_information (peer1.peer,
816 GNUNET_TESTBED_PIT_IDENTITY,
820 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
821 (GNUNET_TIME_UNIT_SECONDS, 20), &do_abort,
830 main (int argc, char **argv)
836 event_mask |= (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED);
837 max_mids = (GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct GNUNET_MessageHeader))
838 / sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1;
840 (void) GNUNET_TESTBED_test_run ("test_scalarproduct_api_regression",
841 "test_scalarproduct_api_data.conf",
842 NUM_PEERS, event_mask, &controller_event_cb,
846 if (GNUNET_SYSERR == ok)