From 7effc1a7a43dd4962c5777538e26a09a67914ecd Mon Sep 17 00:00:00 2001 From: Sree Harsha Totakura Date: Wed, 25 Jul 2012 15:02:53 +0000 Subject: [PATCH] -helper service shutdown fixes; overlay connect message --- src/testbed/Makefile.am | 1 + src/testbed/gnunet-service-testbed.c | 145 ++++++++++++++++++++------- src/testbed/gnunet-testbed-helper.c | 84 ++++++++-------- src/testbed/testbed_api.c | 6 ++ src/testbed/testbed_api.h | 1 + src/testbed/testbed_api_peers.c | 29 +++++- src/testbed/testbed_api_peers.h | 58 ++++++++++- 7 files changed, 239 insertions(+), 85 deletions(-) diff --git a/src/testbed/Makefile.am b/src/testbed/Makefile.am index fd667b8d1..d3ca76c17 100644 --- a/src/testbed/Makefile.am +++ b/src/testbed/Makefile.am @@ -22,6 +22,7 @@ gnunet_service_testbed_SOURCES = \ gnunet-service-testbed.c gnunet_service_testbed_LDADD = $(XLIB) \ $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/testbed/libgnunettestbed.la \ $(LTLIBINTL) -lz diff --git a/src/testbed/gnunet-service-testbed.c b/src/testbed/gnunet-service-testbed.c index f2bb16488..0b19d6e5c 100644 --- a/src/testbed/gnunet-service-testbed.c +++ b/src/testbed/gnunet-service-testbed.c @@ -27,6 +27,7 @@ #include "platform.h" #include "gnunet_service_lib.h" #include "gnunet_server_lib.h" +#include "gnunet_transport_service.h" #include #include "gnunet_testbed_service.h" @@ -302,6 +303,53 @@ struct Peer }; +/** + * Context information for connecting 2 peers in overlay + */ +struct OverlayConnectContext +{ + /** + * peer 1 + */ + struct Peer *peer1; + + /** + * peer 2 + */ + struct Peer *peer2; + + /** + * Transport handle of peer1 + */ + struct GNUNET_TRANSPORT_Handle *peer1_transport; + + /** + * Transport handle of peer2 + */ + struct GNUNET_TRANSPORT_Handle *peer2_transport; + + /** + * HELLO of peer1 + */ + struct GNUNET_MessageHeader *peer1_hello; + + /** + * HELLO of peer2 + */ + struct GNUNET_MessageHeader *peer2_hello; + + /** + * Get hello handle for peer1 + */ + struct GNUNET_TRANSPORT_GetHelloHandle *peer1_ghh; + + /** + * Get hello handle for peer2 + */ + struct GNUNET_TRANSPORT_GetHelloHandle *peer2_ghh; +}; + + /** * The master context; generated with the first INIT message */ @@ -311,11 +359,6 @@ static struct Context *master_context; /* Handles */ /***********/ -/** - * Wrapped stdin. - */ -static struct GNUNET_DISK_FileHandle *fh; - /** * Current Transmit Handle; NULL if no notify transmit exists currently */ @@ -1436,6 +1479,58 @@ handle_peer_get_config (void *cls, } + +/** + * Function called whenever there is an update to the + * HELLO of this peer. + * + * @param cls closure + * @param hello our updated HELLO + */ +static void +hello_update_cb (void *cls, + const struct GNUNET_MessageHeader *hello) +{ + GNUNET_break(0); +} + + +/** + * Handler for GNUNET_MESSAGE_TYPE_TESTBED_OLCONNECT messages + * + * @param cls NULL + * @param client identification of the client + * @param message the actual message + */ +static void +handle_overlay_connect (void *cls, + struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + const struct GNUNET_TESTBED_OverlayConnectMessage *msg; + struct OverlayConnectContext *occ; + uint32_t p1; + uint32_t p2; + + msg = (const struct GNUNET_TESTBED_OverlayConnectMessage *) message; + p1 = ntohl (msg->peer1); + p2 = ntohl (msg->peer2); + GNUNET_assert (p1 < peer_list_size); + GNUNET_assert (NULL != peer_list[p1]); + GNUNET_assert (p2 < peer_list_size); + GNUNET_assert (NULL != peer_list[p2]); + occ = GNUNET_malloc (sizeof (struct OverlayConnectContext)); + occ->peer1 = peer_list[p1]; + occ->peer2 = peer_list[p2]; + occ->peer1_transport = GNUNET_TRANSPORT_connect (occ->peer1->cfg, NULL, occ, + NULL, NULL, NULL); + occ->peer2_transport = GNUNET_TRANSPORT_connect (occ->peer2->cfg, NULL, occ, + NULL, NULL, NULL); + occ->peer1_ghh = GNUNET_TRANSPORT_get_hello (occ->peer1_transport, &hello_update_cb, occ); + occ->peer2_ghh = GNUNET_TRANSPORT_get_hello (occ->peer2_transport, &hello_update_cb, occ); +} + + /** * Iterator over hash map entries. * @@ -1478,11 +1573,6 @@ shutdown_task (void *cls, (void) GNUNET_CONTAINER_multihashmap_iterate (ss_map, &ss_map_free_iterator, NULL); GNUNET_CONTAINER_multihashmap_destroy (ss_map); - if (NULL != fh) - { - GNUNET_DISK_file_close (fh); - fh = NULL; - } if (NULL != lcfq_head) { if (GNUNET_SCHEDULER_NO_TASK != lcf_proc_task_id) @@ -1540,21 +1630,6 @@ shutdown_task (void *cls, } -/** - * Debug shutdown task in case of stdin getting closed - * - * @param cls NULL - * @param tc the TaskContext from scheduler - */ -static void -shutdown_task_ (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - LOG (GNUNET_ERROR_TYPE_DEBUG, "STDIN closed ...\n"); - shutdown_task (cls, tc); -} - - /** * Callback for client disconnect * @@ -1575,7 +1650,7 @@ client_disconnect_cb (void *cls, struct GNUNET_SERVER_Client *client) hurt for now --- might need to revise this later if we ever decide that master connections might be temporarily down for some reason */ - GNUNET_SCHEDULER_shutdown (); + //GNUNET_SCHEDULER_shutdown (); } } @@ -1610,6 +1685,8 @@ testbed_run (void *cls, sizeof (struct GNUNET_TESTBED_PeerStopMessage)}, {&handle_peer_get_config, NULL, GNUNET_MESSAGE_TYPE_TESTBED_GETPEERCONFIG, sizeof (struct GNUNET_TESTBED_PeerGetConfigurationMessage)}, + {&handle_overlay_connect, NULL, GNUNET_MESSAGE_TYPE_TESTBED_OLCONNECT, + sizeof (struct GNUNET_TESTBED_OverlayConnectMessage)}, {NULL} }; @@ -1619,18 +1696,10 @@ testbed_run (void *cls, &client_disconnect_cb, NULL); ss_map = GNUNET_CONTAINER_multihashmap_create (5); - fh = GNUNET_DISK_get_handle_from_native (stdin); - if (NULL == fh) - shutdown_task_id = - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, - &shutdown_task, - NULL); - else - shutdown_task_id = - GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, - fh, - &shutdown_task_, - NULL); + shutdown_task_id = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, + &shutdown_task, + NULL); LOG_DEBUG ("Testbed startup complete\n"); } diff --git a/src/testbed/gnunet-testbed-helper.c b/src/testbed/gnunet-testbed-helper.c index 36eb3e931..942a9e549 100644 --- a/src/testbed/gnunet-testbed-helper.c +++ b/src/testbed/gnunet-testbed-helper.c @@ -98,16 +98,6 @@ static struct GNUNET_DISK_FileHandle *stdout_fd; */ static struct GNUNET_OS_Process *testbed; -/** - * Pipe handle to child's stdin - */ -static struct GNUNET_DISK_PipeHandle *pipe_in; - -/** - * Pipe handle to child's stdout - */ -static struct GNUNET_DISK_PipeHandle *pipe_out; - /** * Task identifier for the read task */ @@ -126,7 +116,13 @@ static int done_reading; /** * Result to return in case we fail */ -static int ret; +static int status; + + +/** + * Are we shutting down + */ +static int in_shutdown; /** @@ -139,6 +135,7 @@ static void shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { LOG_DEBUG ("Shutting down\n"); + in_shutdown = GNUNET_YES; if (GNUNET_SCHEDULER_NO_TASK != read_task_id) { GNUNET_SCHEDULER_cancel (read_task_id); @@ -157,21 +154,11 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) tokenizer = NULL; if (NULL != testbed) { - (void) GNUNET_OS_process_kill (testbed, SIGTERM); + GNUNET_break (0 == GNUNET_OS_process_kill (testbed, SIGTERM)); GNUNET_assert (GNUNET_OK == GNUNET_OS_process_wait (testbed)); GNUNET_OS_process_destroy (testbed); testbed = NULL; } - if (NULL != pipe_in) - { - (void) GNUNET_DISK_pipe_close (pipe_in); - pipe_in = NULL; - } - if (NULL != pipe_out) - { - (void) GNUNET_DISK_pipe_close (pipe_out); - pipe_out = NULL; - } if (NULL != test_system) { GNUNET_TESTING_system_destroy (test_system, GNUNET_YES); @@ -288,14 +275,6 @@ tokenizer_cb (void *cls, void *client, (test_system, cfg)); GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS", "DEFAULTCONFIG", &config)); - pipe_in = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_YES, GNUNET_NO); - pipe_out = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO, GNUNET_YES); - if ((NULL == pipe_in) || (NULL == pipe_out)) - { - GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "pipe"); - GNUNET_free (config); - goto error; - } if (GNUNET_OK != GNUNET_CONFIGURATION_write (cfg, config)) { LOG (GNUNET_ERROR_TYPE_WARNING, @@ -306,7 +285,7 @@ tokenizer_cb (void *cls, void *client, } LOG_DEBUG ("Staring testbed with config: %s\n", config); testbed = GNUNET_OS_start_process - (GNUNET_YES, GNUNET_OS_INHERIT_STD_ERR /*verbose? */, pipe_in, pipe_out, + (GNUNET_YES, GNUNET_OS_INHERIT_STD_ERR /*verbose? */, NULL, NULL, "gnunet-service-testbed", "gnunet-service-testbed", "-c", config, NULL); GNUNET_free (config); if (NULL == testbed) @@ -316,8 +295,6 @@ tokenizer_cb (void *cls, void *client, GNUNET_CONFIGURATION_destroy (cfg); goto error; } - GNUNET_DISK_pipe_close_end (pipe_out, GNUNET_DISK_PIPE_END_WRITE); - GNUNET_DISK_pipe_close_end (pipe_in, GNUNET_DISK_PIPE_END_READ); done_reading = GNUNET_YES; config = GNUNET_CONFIGURATION_serialize (cfg, &config_size); GNUNET_CONFIGURATION_destroy (cfg); @@ -338,7 +315,7 @@ tokenizer_cb (void *cls, void *client, return GNUNET_OK; error: - ret = GNUNET_SYSERR; + status = GNUNET_SYSERR; GNUNET_SCHEDULER_shutdown (); return GNUNET_SYSERR; } @@ -362,14 +339,12 @@ read_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) sread = GNUNET_DISK_file_read (stdin_fd, buf, sizeof (buf)); if (GNUNET_SYSERR == sread) { - GNUNET_break (0); /* FIXME: stdin closed - kill child */ GNUNET_SCHEDULER_shutdown (); return; } if (GNUNET_YES == done_reading) { /* didn't expect any more data! */ - GNUNET_break (0); GNUNET_SCHEDULER_shutdown (); return; } @@ -412,6 +387,24 @@ run (void *cls, char *const *args, const char *cfgfile, } +/** + * Signal handler called for SIGCHLD. Triggers the + * respective handler by writing to the trigger pipe. + */ +static void +sighandler_child_death () +{ + if ((NULL != testbed) && (GNUNET_NO == in_shutdown)) + { + LOG_DEBUG ("Child died\n"); + GNUNET_assert (GNUNET_OK == GNUNET_OS_process_wait (testbed)); + GNUNET_OS_process_destroy (testbed); + testbed = NULL; + GNUNET_SCHEDULER_shutdown (); /* We are done too! */ + } +} + + /** * Main function * @@ -421,18 +414,25 @@ run (void *cls, char *const *args, const char *cfgfile, */ int main (int argc, char **argv) { + struct GNUNET_SIGNAL_Context *shc_chld; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; + int ret; - ret = GNUNET_OK; + status = GNUNET_OK; + in_shutdown = GNUNET_NO; //sleep (60); - if (GNUNET_OK != - GNUNET_PROGRAM_run (argc, argv, "gnunet-testbed-helper", - "Helper for starting gnunet-service-testbed", - options, &run, NULL)) + shc_chld = + GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD, &sighandler_child_death); + ret = GNUNET_PROGRAM_run (argc, argv, "gnunet-testbed-helper", + "Helper for starting gnunet-service-testbed", + options, &run, NULL); + GNUNET_SIGNAL_handler_uninstall (shc_chld); + shc_chld = NULL; + if (GNUNET_OK != ret) return 1; - return (GNUNET_OK == ret) ? 0 : 1; + return (GNUNET_OK == status) ? 0 : 1; } /* end of gnunet-testbed-helper.c */ diff --git a/src/testbed/testbed_api.c b/src/testbed/testbed_api.c index 708fc1d04..365a8cdee 100644 --- a/src/testbed/testbed_api.c +++ b/src/testbed/testbed_api.c @@ -325,6 +325,7 @@ handle_peer_create_success (struct GNUNET_TESTBED_Controller *c, GNUNET_assert (NULL != data->peer); peer = data->peer; GNUNET_assert (peer->unique_id == ntohl (msg->peer_id)); + peer->state = PS_CREATED; cb = data->cb; cls = data->cls; GNUNET_free (data); @@ -374,10 +375,12 @@ handle_peer_event (struct GNUNET_TESTBED_Controller *c, switch (event.type) { case GNUNET_TESTBED_ET_PEER_START: + peer->state = PS_STARTED; event.details.peer_start.host = peer->host; event.details.peer_start.peer = peer; break; case GNUNET_TESTBED_ET_PEER_STOP: + peer->state = PS_STOPPED; event.details.peer_stop.peer = peer; break; default: @@ -1363,6 +1366,9 @@ GNUNET_TESTBED_operation_done (struct GNUNET_TESTBED_Operation *operation) } GNUNET_free_non_null (operation->data); break; + case OP_OVERLAY_CONNECT: + GNUNET_free_non_null (operation->data); + break; } GNUNET_free (operation); } diff --git a/src/testbed/testbed_api.h b/src/testbed/testbed_api.h index 4a5adfa17..642fc4ccb 100644 --- a/src/testbed/testbed_api.h +++ b/src/testbed/testbed_api.h @@ -62,6 +62,7 @@ enum OperationType * Overlay connection operation */ OP_OVERLAY_CONNECT, + }; diff --git a/src/testbed/testbed_api_peers.c b/src/testbed/testbed_api_peers.c index 4711aba7d..4571b78df 100644 --- a/src/testbed/testbed_api_peers.c +++ b/src/testbed/testbed_api_peers.c @@ -98,6 +98,7 @@ GNUNET_TESTBED_peer_create_with_id_ (uint32_t unique_id, peer->controller = controller; peer->host = host; peer->unique_id = unique_id; + peer->state = PS_INVALID; data = GNUNET_malloc (sizeof (struct PeerCreateData)); data->cb = cb; data->cls = cls; @@ -184,6 +185,7 @@ GNUNET_TESTBED_peer_start (struct GNUNET_TESTBED_Peer *peer) struct GNUNET_TESTBED_Operation *op; struct GNUNET_TESTBED_PeerStartMessage *msg; + GNUNET_assert ((PS_CREATED == peer->state) || (PS_STOPPED == peer->state)); op = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Operation)); op->operation_id = peer->controller->operation_counter++; op->controller = peer->controller; @@ -215,6 +217,7 @@ GNUNET_TESTBED_peer_stop (struct GNUNET_TESTBED_Peer *peer) struct GNUNET_TESTBED_Operation *op; struct GNUNET_TESTBED_PeerStopMessage *msg; + GNUNET_assert (PS_STARTED == peer->state); op = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Operation)); op->operation_id = peer->controller->operation_counter++; op->controller = peer->controller; @@ -365,7 +368,31 @@ GNUNET_TESTBED_overlay_connect (void *op_cls, struct GNUNET_TESTBED_Peer *p1, struct GNUNET_TESTBED_Peer *p2) { - GNUNET_break (0); + struct GNUNET_TESTBED_Operation *op; + struct OverlayConnectData *data; + struct GNUNET_TESTBED_OverlayConnectMessage *msg; + + GNUNET_assert ((PS_STARTED == p1->state) && (PS_STARTED == p2->state)); + GNUNET_assert (p1->controller == p2->controller); + data = GNUNET_malloc (sizeof (struct OverlayConnectData)); + data->p1 = p1; + data->p2 = p2; + op = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Operation)); + op->controller = p1->controller; + op->operation_id = op->controller->operation_counter++; + op->type = OP_OVERLAY_CONNECT; + op->data = data; + msg = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_OverlayConnectMessage)); + msg->header.size = htons (sizeof (struct + GNUNET_TESTBED_OverlayConnectMessage)); + msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_OLCONNECT); + msg->peer1 = htonl (p1->unique_id); + msg->peer2 = htonl (p2->unique_id); + msg->operation_id = GNUNET_htonll (op->operation_id); + GNUNET_CONTAINER_DLL_insert_tail (op->controller->op_head, + op->controller->op_tail, op); + GNUNET_TESTBED_queue_message_ (op->controller, + (struct GNUNET_MessageHeader *) msg); return NULL; } diff --git a/src/testbed/testbed_api_peers.h b/src/testbed/testbed_api_peers.h index b3a74eef7..9c1305c79 100644 --- a/src/testbed/testbed_api_peers.h +++ b/src/testbed/testbed_api_peers.h @@ -47,6 +47,33 @@ struct PeerDetails }; +/** + * Enumeration of possible states a peer could be in + */ +enum PeerState + { + /** + * State to signify that this peer is invalid + */ + PS_INVALID, + + /** + * The peer has been created + */ + PS_CREATED, + + /** + * The peer is running + */ + PS_STARTED, + + /** + * The peer is stopped + */ + PS_STOPPED, + }; + + /** * A peer controlled by the testing framework. A peer runs * at a particular host. @@ -64,17 +91,21 @@ struct GNUNET_TESTBED_Peer */ struct GNUNET_TESTBED_Host *host; + /** + * Internals of the peer for the controlling process; NULL if + * this process is not controlling this peer. + */ + struct PeerDetails *details; + /** * Globally unique ID of the peer. */ uint32_t unique_id; /** - * Internals of the peer for the controlling process; NULL if - * this process is not controlling this peer. + * Peer's state */ - struct PeerDetails *details; - + enum PeerState state; }; @@ -160,6 +191,25 @@ struct PeerInfoData2 }; +/** + * Data structure for OperationType OP_OVERLAY_CONNECT + */ +struct OverlayConnectData +{ + /** + * Peer A to connect to peer B + */ + struct GNUNET_TESTBED_Peer *p1; + + /** + * Peer B + */ + struct GNUNET_TESTBED_Peer *p2; + +}; + + + /** * Create the given peer at the specified host using the given * controller. If the given controller is not running on the target -- 2.25.1