X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Fregex%2Fgnunet-regex-profiler.c;h=638f1a1a43bd2cc1d78eb39d013df1e82fa756d9;hb=f119c5a88b06a05349f311c27f27be9a2760bf3f;hp=2dc36984113cae2eec63e17683b260bbebd06011;hpb=4ff43da8a5d8b41a6c12a4c761288554e8093c6e;p=oweals%2Fgnunet.git diff --git a/src/regex/gnunet-regex-profiler.c b/src/regex/gnunet-regex-profiler.c index 2dc369841..638f1a1a4 100644 --- a/src/regex/gnunet-regex-profiler.c +++ b/src/regex/gnunet-regex-profiler.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - (C) 2011, 2012 Christian Grothoff (and other contributing authors) + (C) 2011 - 2013 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published @@ -21,8 +21,9 @@ /** * @file regex/gnunet-regex-profiler.c * @brief Regex profiler for testing distributed regex use. - * @author Bart Polot - * @author Max Szengel + * @author Bartlomiej Polot + * @author Maximilian Szengel + * */ #include @@ -30,732 +31,1444 @@ #include "platform.h" #include "gnunet_applications.h" #include "gnunet_util_lib.h" -#include "gnunet_mesh_service.h" -#include "gnunet_stream_lib.h" +#include "regex_internal_lib.h" +#include "gnunet_arm_service.h" +#include "gnunet_dht_service.h" #include "gnunet_testbed_service.h" +#define FIND_TIMEOUT \ + GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 90) /** - * Total number of hosts. + * DLL of operations */ -#define NUM_HOSTS 2 +struct DLLOperation +{ + /** + * The testbed operation handle + */ + struct GNUNET_TESTBED_Operation *op; + + /** + * Closure + */ + void *cls; + + /** + * The next pointer for DLL + */ + struct DLLOperation *next; + + /** + * The prev pointer for DLL + */ + struct DLLOperation *prev; +}; -/** - * Number of peers per host. - */ -#define PEER_PER_HOST 1 /** - * Total number of peers. + * Available states during profiling */ -#define TOTAL_PEERS (NUM_HOSTS * PEER_PER_HOST) +enum State +{ + /** + * Initial state + */ + STATE_INIT = 0, + + /** + * Starting slaves + */ + STATE_SLAVES_STARTING, + + /** + * Creating peers + */ + STATE_PEERS_CREATING, + + /** + * Starting peers + */ + STATE_PEERS_STARTING, + + /** + * Linking peers + */ + STATE_PEERS_LINKING, + + /** + * Matching strings against announced regexes + */ + STATE_SEARCH_REGEX, + + /** + * Destroying peers; we can do this as the controller takes care of stopping a + * peer if it is running + */ + STATE_PEERS_DESTROYING +}; /** - * Different states in test setup + * Peer handles. */ -enum SetupState +struct RegexPeer { /** - * The initial state + * Peer id. + */ + unsigned int id; + + /** + * Peer configuration handle. + */ + struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * The actual testbed peer handle. + */ + struct GNUNET_TESTBED_Peer *peer_handle; + + /** + * Peer's search string. */ - INIT, + const char *search_str; /** - * Connecting to slave controller + * Set to GNUNET_YES if the peer successfully matched the above + * search string. GNUNET_NO if the string could not be matched + * during the profiler run. GNUNET_SYSERR if the string matching + * timed out. Undefined if search_str is NULL */ - LINKING, + int search_str_matched; - LINKING_SLAVES, + /** + * Peer's DHT handle. + */ + struct GNUNET_DHT_Handle *dht_handle; - LINKING_SLAVES_SUCCESS, + /** + * Handle to a running regex search. + */ + struct REGEX_INTERNAL_Search *search_handle; - CONNECTING_PEERS, + /** + * Testbed operation handle for DHT. + */ + struct GNUNET_TESTBED_Operation *op_handle; - CREATING_PEER, + /** + * Peers's statistics handle. + */ + struct GNUNET_STATISTICS_Handle *stats_handle; + + /** + * The starting time of a profiling step. + */ + struct GNUNET_TIME_Absolute prof_start_time; + + /** + * Operation timeout + */ + GNUNET_SCHEDULER_TaskIdentifier timeout; - STARTING_PEER + /** + * Deamon start + */ + struct GNUNET_TESTBED_Operation *daemon_op; }; +/** + * Set when shutting down to avoid making more queries. + */ +static int in_shutdown; + +/** + * The array of peers; we fill this as the peers are given to us by the testbed + */ +static struct RegexPeer *peers; + +/** + * Host registration handle + */ +static struct GNUNET_TESTBED_HostRegistrationHandle *reg_handle; /** - * Event Mask for operation callbacks + * Handle to the master controller process */ -uint64_t event_mask; +static struct GNUNET_TESTBED_ControllerProc *mc_proc; /** - * Testbed operation handle + * Handle to the master controller */ -static struct GNUNET_TESTBED_Operation *op[NUM_HOSTS]; +static struct GNUNET_TESTBED_Controller *mc; /** - * Setup state. + * Handle to global configuration */ -static enum SetupState state[NUM_HOSTS]; +static struct GNUNET_CONFIGURATION_Handle *cfg; /** - * Abort task. + * Abort task identifier */ static GNUNET_SCHEDULER_TaskIdentifier abort_task; /** - * Global test result + * Shutdown task identifier + */ +static GNUNET_SCHEDULER_TaskIdentifier shutdown_task; + +/** + * Host registration task identifier + */ +static GNUNET_SCHEDULER_TaskIdentifier register_hosts_task; + +/** + * Global event mask for all testbed events + */ +static uint64_t event_mask; + +/** + * The starting time of a profiling step + */ +static struct GNUNET_TIME_Absolute prof_start_time; + +/** + * Duration profiling step has taken + */ +static struct GNUNET_TIME_Relative prof_time; + +/** + * Number of peers to be started by the profiler + */ +static unsigned int num_peers; + +/** + * Global testing status */ static int result; /** - * Hosts successfully registered + * current state of profiling */ -static unsigned int host_registered; +enum State state; /** - * Peers successfully started + * Folder where policy files are stored. */ -static unsigned int peers_started; +static char * policy_dir; /** - * The master controller host + * File with hostnames where to execute the test. */ -struct GNUNET_TESTBED_Host *master_host; +static char *hosts_file; /** - * The master controller process + * File with the strings to look for. */ -static struct GNUNET_TESTBED_ControllerProc *master_proc; +static char *strings_file; /** - * Handle to master controller + * Search strings (num_peers of them). */ -static struct GNUNET_TESTBED_Controller *master_ctrl; +static char **search_strings; +/** + * How many searches are we going to start in parallel + */ +static long long unsigned int init_parallel_searches; /** - * Slave host registration handles + * How many searches are running in parallel */ -static struct GNUNET_TESTBED_HostRegistrationHandle *rh; +static unsigned int parallel_searches; +/** + * Number of strings found in the published regexes. + */ +static unsigned int strings_found; /** - * Handle to global configuration + * Index of peer to start next announce/search. */ -static struct GNUNET_CONFIGURATION_Handle *cfg; +static unsigned int next_search; /** - * Structure for storing host handles + * Search timeout task identifier. */ -struct Host -{ - /** - * IP address of this host. - */ - char *ip; +static GNUNET_SCHEDULER_TaskIdentifier search_timeout_task; - /** - * Host handle. - */ - struct GNUNET_TESTBED_Host *host; +/** + * Search timeout in seconds. + */ +static struct GNUNET_TIME_Relative search_timeout_time = { 60000 }; - /** - * Registration state of this host. - */ - int host_registered; +/** + * File to log statistics to. + */ +static struct GNUNET_DISK_FileHandle *data_file; - /** - * Operation handle. - */ - struct GNUNET_TESTBED_Operation *op; +/** + * Filename to log statistics to. + */ +static char *data_filename; - /** - * Host state. - */ - enum SetupState state; -}; +/** + * Prefix used for regex announcing. We need to prefix the search + * strings with it, in order to find something. + */ +static char * regex_prefix; /** - * List of slaves. + * What's the maximum regex reannounce period. */ -static struct Host slaves[NUM_HOSTS] = { {"192.168.1.33", NULL, 0, NULL, INIT}, -{"192.168.1.34", NULL, 0, NULL, INIT} -}; +static struct GNUNET_TIME_Relative reannounce_period_max; + + +/******************************************************************************/ +/****************************** DECLARATIONS ********************************/ +/******************************************************************************/ /** - * Structure for holding peer's handles. + * DHT connect callback. + * + * @param cls internal peer id. + * @param op operation handle. + * @param ca_result connect adapter result. + * @param emsg error message. */ -struct PeerData -{ - /** - * Handle to testbed peer. - */ - struct GNUNET_TESTBED_Peer *peer; +static void +dht_connect_cb (void *cls, struct GNUNET_TESTBED_Operation *op, + void *ca_result, const char *emsg); - /** - * Peer's mesh handle. - */ - struct GNUNET_MESH_Handle *mesh_handle; +/** + * DHT connect adapter. + * + * @param cls not used. + * @param cfg configuration handle. + * + * @return + */ +static void * +dht_ca (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg); - /** - * The service connect operation to stream - */ - struct GNUNET_TESTBED_Operation *op; - /** - * Peer setup state. - */ - enum SetupState state; +/** + * Adapter function called to destroy a connection to + * the DHT service + * + * @param cls closure + * @param op_result service handle returned from the connect adapter + */ +static void +dht_da (void *cls, void *op_result); - /** - * Our Peer id - */ - struct GNUNET_PeerIdentity our_id; -}; /** - * The peers + * Function called by testbed once we are connected to stats + * service. Get the statistics for the services of interest. + * + * @param cls the 'struct RegexPeer' for which we connected to stats + * @param op connect operation handle + * @param ca_result handle to stats service + * @param emsg error message on failure */ -struct PeerData peers[TOTAL_PEERS]; +static void +stats_connect_cb (void *cls, + struct GNUNET_TESTBED_Operation *op, + void *ca_result, + const char *emsg); +/** + * Start announcing the next regex in the DHT. + * + * @param cls Index of the next peer in the peers array. + * @param tc TaskContext. + */ +static void +announce_next_regex (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + + +/******************************************************************************/ +/******************************** SHUTDOWN **********************************/ +/******************************************************************************/ + /** - * Close sockets and stop testing deamons nicely + * Shutdown nicely + * + * @param cls NULL + * @param tc the task context */ -void -do_close (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +static void +do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { - unsigned int i; + struct RegexPeer *peer; + unsigned int peer_cnt; + unsigned int search_str_cnt; + char output_buffer[512]; + size_t size; + shutdown_task = GNUNET_SCHEDULER_NO_TASK; if (GNUNET_SCHEDULER_NO_TASK != abort_task) GNUNET_SCHEDULER_cancel (abort_task); + if (GNUNET_SCHEDULER_NO_TASK != register_hosts_task) + GNUNET_SCHEDULER_cancel (register_hosts_task); + + for (peer_cnt = 0; peer_cnt < num_peers; peer_cnt++) + { + peer = &peers[peer_cnt]; + + if (GNUNET_YES != peer->search_str_matched && NULL != data_file) + { + prof_time = GNUNET_TIME_absolute_get_duration (peer->prof_start_time); + size = + GNUNET_snprintf (output_buffer, + sizeof (output_buffer), + "%p Search string not found: %s (%d)\n" + "%p On peer: %u (%p)\n" + "%p After: %s\n", + peer, peer->search_str, peer->search_str_matched, + peer, peer->id, peer, + peer, + GNUNET_STRINGS_relative_time_to_string (prof_time, + GNUNET_NO)); + if (size != GNUNET_DISK_file_write (data_file, output_buffer, size)) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Unable to write to file!\n"); + } - for (i = 0; i < TOTAL_PEERS; i++) + if (NULL != peers[peer_cnt].op_handle) + GNUNET_TESTBED_operation_done (peers[peer_cnt].op_handle); + } + + if (NULL != data_file) + GNUNET_DISK_file_close (data_file); + + for (search_str_cnt = 0; + search_str_cnt < num_peers && NULL != search_strings; + search_str_cnt++) { - if (NULL != peers[i].mesh_handle) - GNUNET_MESH_disconnect (peers[i].mesh_handle); - if (NULL != peers[i].op) - GNUNET_TESTBED_operation_done (peers[i].op); + GNUNET_free_non_null (search_strings[search_str_cnt]); } + GNUNET_free_non_null (search_strings); + + if (NULL != reg_handle) + GNUNET_TESTBED_cancel_registration (reg_handle); - GNUNET_SCHEDULER_shutdown (); /* For shutting down testbed */ + if (NULL != mc) + GNUNET_TESTBED_controller_disconnect (mc); + if (NULL != mc_proc) + GNUNET_TESTBED_controller_stop (mc_proc); + if (NULL != cfg) + GNUNET_CONFIGURATION_destroy (cfg); + + GNUNET_SCHEDULER_shutdown (); /* Stop scheduler to shutdown testbed run */ } /** - * Something went wrong and timed out. Kill everything and set error flag. + * abort task to run on test timed out * - * @param cls close. - * @param tc task context. + * @param cls NULL + * @param tc the task context */ static void do_abort (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: ABORT\n"); + unsigned long i = (unsigned long) cls; + + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Aborting from line %lu...\n", i); + abort_task = GNUNET_SCHEDULER_NO_TASK; result = GNUNET_SYSERR; - abort_task = 0; + if (GNUNET_SCHEDULER_NO_TASK != shutdown_task) + GNUNET_SCHEDULER_cancel (shutdown_task); + shutdown_task = GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); } +/******************************************************************************/ +/********************* STATISTICS SERVICE CONNECTIONS ***********************/ +/******************************************************************************/ + /** - * Method called whenever another peer has added us to a tunnel - * the other peer initiated. - * Only called (once) upon reception of data with a message type which was - * subscribed to in GNUNET_MESH_connect. A call to GNUNET_MESH_tunnel_destroy - * causes te tunnel to be ignored and no further notifications are sent about - * the same tunnel. + * Adapter function called to establish a connection to + * statistics service. * * @param cls closure - * @param tunnel new handle to the tunnel - * @param initiator peer that started the tunnel - * @param atsi performance information for the tunnel - * @return initial tunnel context for the tunnel - * (can be NULL -- that's not an error) - */ -void * -mesh_inbound_tunnel_handler (void *cls, struct GNUNET_MESH_Tunnel *tunnel, - const struct GNUNET_PeerIdentity *initiator, - const struct GNUNET_ATS_Information *atsi) + * @param cfg configuration of the peer to connect to; will be available until + * GNUNET_TESTBED_operation_done() is called on the operation returned + * from GNUNET_TESTBED_service_connect() + * @return service handle to return in 'op_result', NULL on error + */ +static void * +stats_ca (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg) { - return NULL; + return GNUNET_STATISTICS_create ("", cfg); } /** - * Function called whenever an inbound tunnel is destroyed. Should clean up - * any associated state. This function is NOT called if the client has - * explicitly asked for the tunnel to be destroyed using - * GNUNET_MESH_tunnel_destroy. It must NOT call GNUNET_MESH_tunnel_destroy on - * the tunnel. + * Adapter function called to destroy a connection to + * statistics service. * - * @param cls closure (set from GNUNET_MESH_connect) - * @param tunnel connection to the other end (henceforth invalid) - * @param tunnel_ctx place where local state associated - * with the tunnel is stored + * @param cls closure + * @param op_result service handle returned from the connect adapter */ -void -mesh_tunnel_end_handler (void *cls, const struct GNUNET_MESH_Tunnel *tunnel, - void *tunnel_ctx) +static void +stats_da (void *cls, void *op_result) { + struct RegexPeer *peer = cls; + + GNUNET_assert (op_result == peer->stats_handle); + GNUNET_STATISTICS_destroy (peer->stats_handle, GNUNET_NO); + peer->stats_handle = NULL; } /** - * Mesh connect callback. + * Process statistic values. Write all values to global 'data_file', if present. * - * @param cls internal peer id. - * @param op operation handle. - * @param ca_result connect adapter result. - * @param emsg error message. + * @param cls closure + * @param subsystem name of subsystem that created the statistic + * @param name the name of the datum + * @param value the current value + * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not + * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration */ -void -mesh_connect_cb (void *cls, struct GNUNET_TESTBED_Operation *op, - void *ca_result, const char *emsg) +static int +stats_iterator (void *cls, const char *subsystem, const char *name, + uint64_t value, int is_persistent) { - long i = (long) cls; + struct RegexPeer *peer = cls; + char output_buffer[512]; + size_t size; - if (NULL != emsg) + if (NULL == data_file) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Mesh connect failed: %s\n", emsg); - GNUNET_assert (0); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "%p -> %s [%s]: %llu\n", + peer, subsystem, name, value); + return GNUNET_OK; } - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh connect callback for peer %i\n", - i); + size = + GNUNET_snprintf (output_buffer, + sizeof (output_buffer), + "%p [%s] %llu %s\n", + peer, + subsystem, value, name); + if (size != GNUNET_DISK_file_write (data_file, output_buffer, size)) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Unable to write to file!\n"); + + return GNUNET_OK; } /** - * Mesh connect adapter. - * - * @param cls not used. - * @param cfg configuration handle. + * Stats callback. Finish the stats testbed operation and when all stats have + * been iterated, shutdown the profiler. * - * @return + * @param cls closure + * @param success GNUNET_OK if statistics were + * successfully obtained, GNUNET_SYSERR if not. */ -void * -mesh_ca (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg) +static void +stats_cb (void *cls, + int success) { - struct PeerData *peer = (struct PeerData *) cls; + static unsigned int peer_cnt; + struct RegexPeer *peer = cls; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh connect adapter\n"); + if (GNUNET_OK != success) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Getting statistics for peer %u failed!\n", + peer->id); + return; + } - static struct GNUNET_MESH_MessageHandler handlers[] = { - {NULL, 0, 0} - }; + GNUNET_assert (NULL != peer->op_handle); - static GNUNET_MESH_ApplicationType apptypes[] = { - GNUNET_APPLICATION_TYPE_END - }; + GNUNET_TESTBED_operation_done (peer->op_handle); + peer->op_handle = NULL; - peer->mesh_handle = - GNUNET_MESH_connect (cfg, cls, &mesh_inbound_tunnel_handler, - &mesh_tunnel_end_handler, handlers, apptypes); + peer_cnt++; + peer = &peers[peer_cnt]; - return NULL; + if (peer_cnt == num_peers) + { + struct GNUNET_TIME_Relative delay = { 100 }; + shutdown_task = GNUNET_SCHEDULER_add_delayed (delay, &do_shutdown, NULL); + result = GNUNET_OK; + } + else + { + peer->op_handle = + GNUNET_TESTBED_service_connect (NULL, + peer->peer_handle, + "statistics", + &stats_connect_cb, + peer, + &stats_ca, + &stats_da, + peer); + } } /** - * Adapter function called to destroy a connection to - * the mesh service + * Function called by testbed once we are connected to stats + * service. Get the statistics for the services of interest. * - * @param cls closure - * @param op_result service handle returned from the connect adapter + * @param cls the 'struct RegexPeer' for which we connected to stats + * @param op connect operation handle + * @param ca_result handle to stats service + * @param emsg error message on failure */ -void -mesh_da (void *cls, void *op_result) +static void +stats_connect_cb (void *cls, + struct GNUNET_TESTBED_Operation *op, + void *ca_result, + const char *emsg) { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh disconnect adapter\n"); + struct RegexPeer *peer = cls; + + if (NULL == ca_result || NULL != emsg) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to connect to statistics service on peer %u: %s\n", + peer->id, emsg); + + peer->stats_handle = NULL; + return; + } + + peer->stats_handle = ca_result; + + if (NULL == GNUNET_STATISTICS_get (peer->stats_handle, NULL, NULL, + GNUNET_TIME_UNIT_FOREVER_REL, + &stats_cb, + &stats_iterator, peer)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Could not get statistics of peer %u!\n", peer->id); + } } /** - * Functions of this signature are called when a peer has been successfully - * started or stopped. + * Task to collect all statistics from all peers, will shutdown the + * profiler, when done. * - * @param cls the closure from GNUNET_TESTBED_peer_start/stop() - * @param emsg NULL on success; otherwise an error description + * @param cls NULL + * @param tc the task context */ static void -peer_start_cb (void *cls, const char *emsg) +do_collect_stats (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { - unsigned int cnt; - long i = (long) cls; - - GNUNET_TESTBED_operation_done (op[i]); - peers_started++; - // FIXME create and start rest of PEERS_PER_HOST - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " %u peer(s) started\n", peers_started); + struct RegexPeer *peer = &peers[0]; + + GNUNET_assert (NULL != peer->peer_handle); + + peer->op_handle = + GNUNET_TESTBED_service_connect (NULL, + peer->peer_handle, + "statistics", + &stats_connect_cb, + peer, + &stats_ca, + &stats_da, + peer); +} - if (TOTAL_PEERS == peers_started) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All peers started.\n"); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Linking slave controllers\n"); - for (cnt = 0; cnt < NUM_HOSTS - 1; cnt++) - { - state[cnt] = LINKING_SLAVES; - op[cnt] = - GNUNET_TESTBED_get_slave_config ((void *) (long) cnt, master_ctrl, - slaves[cnt + 1].host); - } - } -} +/******************************************************************************/ +/************************ REGEX FIND CONNECTIONS **************************/ +/******************************************************************************/ /** - * Functions of this signature are called when a peer has been successfully - * created + * Start searching for the next string in the DHT. * - * @param cls the closure from GNUNET_TESTBED_peer_create() - * @param peer the handle for the created peer; NULL on any error during - * creation - * @param emsg NULL if peer is not NULL; else MAY contain the error description + * @param cls Index of the next peer in the peers array. + * @param tc TaskContext. */ static void -peer_create_cb (void *cls, struct GNUNET_TESTBED_Peer *peer, const char *emsg) -{ - long i = (long) cls; - long peer_id; - -// GNUNET_TESTBED_operation_done(op[i]); - peer_id = i; // FIXME A * i + B - peers[peer_id].peer = peer; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Peer %i created\n", peer_id); - op[i] = GNUNET_TESTBED_peer_start (NULL, peer, peer_start_cb, (void *) i); -} +find_string (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); /** - * Signature of the event handler function called by the - * respective event controller. + * Method called when we've found a peer that announced a regex + * that matches our search string. Now get the statistics. * - * @param cls closure - * @param event information about the event + * @param cls Closure provided in REGEX_INTERNAL_search. + * @param id Peer providing a regex that matches the string. + * @param get_path Path of the get request. + * @param get_path_length Lenght of get_path. + * @param put_path Path of the put request. + * @param put_path_length Length of the put_path. */ static void -controller_cb (void *cls, const struct GNUNET_TESTBED_EventInformation *event) +regex_found_handler (void *cls, + const struct GNUNET_PeerIdentity *id, + const struct GNUNET_PeerIdentity *get_path, + unsigned int get_path_length, + const struct GNUNET_PeerIdentity *put_path, + unsigned int put_path_length) { - long i; + struct RegexPeer *peer = cls; + char output_buffer[512]; + size_t size; - switch (event->type) + if (GNUNET_YES == peer->search_str_matched) { - case GNUNET_TESTBED_ET_PEER_START: - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Peer started\n"); - /* event->details.peer_start.peer; */ - /* event->details.peer_start.host; */ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "String %s on peer %u already matched!\n", + peer->search_str, peer->id); + return; + } - break; - case GNUNET_TESTBED_ET_PEER_STOP: - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer stopped\n"); - break; - case GNUNET_TESTBED_ET_CONNECT: - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Overlay Connected\n"); - for (i = 0; i < TOTAL_PEERS; i++) - { - GNUNET_TESTBED_service_connect (NULL, peers[i].peer, "mesh", - &mesh_connect_cb, (void *) i, &mesh_ca, - &mesh_da, NULL); - } - break; - case GNUNET_TESTBED_ET_OPERATION_FINISHED: - if (NULL != event->details.operation_finished.emsg) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Testbed error: %s\n", - event->details.operation_finished.emsg); - GNUNET_assert (0); - } + strings_found++; + parallel_searches--; - i = (long) event->details.operation_finished.op_cls; - switch (state[i]) - { - case INIT: - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Init: %u\n", i); - GNUNET_TESTBED_operation_done (event->details. - operation_finished.operation); - op[i] = NULL; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Operation %u finished\n", i); - break; - } - case LINKING: - { - GNUNET_assert (NULL != slaves[i].op); + if (GNUNET_SCHEDULER_NO_TASK != peer->timeout) + { + GNUNET_SCHEDULER_cancel (peer->timeout); + peer->timeout = GNUNET_SCHEDULER_NO_TASK; + if (GNUNET_NO == in_shutdown) + GNUNET_SCHEDULER_add_now (&announce_next_regex, NULL); + } + + if (NULL == id) + { + // FIXME not possible right now + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "String matching timed out for string %s on peer %u (%i/%i)\n", + peer->search_str, peer->id, strings_found, num_peers); + peer->search_str_matched = GNUNET_SYSERR; + } + else + { + prof_time = GNUNET_TIME_absolute_get_duration (peer->prof_start_time); - GNUNET_TESTBED_operation_done (slaves[i].op); - slaves[i].op = NULL; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "String %s found on peer %u after %s (%i/%i) (%u||)\n", + peer->search_str, peer->id, + GNUNET_STRINGS_relative_time_to_string (prof_time, GNUNET_NO), + strings_found, num_peers, parallel_searches); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Operation %u finished\n", i); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Linked host %i\n", i); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Creating peer...\n"); + peer->search_str_matched = GNUNET_YES; - state[i] = CREATING_PEER; - op[i] = - GNUNET_TESTBED_peer_create (master_ctrl, slaves[i].host, cfg, - peer_create_cb, (void *) i); - break; - } - case CREATING_PEER: - { - GNUNET_TESTBED_operation_done (event->details. - operation_finished.operation); - op[i] = NULL; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Operation %u finished\n", i); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Peer create\n"); - break; - } - case LINKING_SLAVES: + if (NULL != data_file) { - struct GNUNET_CONFIGURATION_Handle *slave_cfg; - - GNUNET_assert (NULL != event->details.operation_finished.generic); - slave_cfg = - GNUNET_CONFIGURATION_dup ((struct GNUNET_CONFIGURATION_Handle *) - event->details.operation_finished.generic); - GNUNET_TESTBED_operation_done (event->details. - operation_finished.operation); - op[i] = NULL; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Operation %u finished\n", i); - state[i] = LINKING_SLAVES_SUCCESS; - op[i] = - GNUNET_TESTBED_controller_link ((void *) (long) i, master_ctrl, - slaves[i + 1].host, slaves[i].host, - slave_cfg, GNUNET_NO); - GNUNET_CONFIGURATION_destroy (slave_cfg); - break; + size = + GNUNET_snprintf (output_buffer, + sizeof (output_buffer), + "%p Peer: %u\n" + "%p Search string: %s\n" + "%p Search duration: %s\n\n", + peer, peer->id, + peer, peer->search_str, + peer, + GNUNET_STRINGS_relative_time_to_string (prof_time, + GNUNET_NO)); + + if (size != GNUNET_DISK_file_write (data_file, output_buffer, size)) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Unable to write to file!\n"); } - case LINKING_SLAVES_SUCCESS: + } + + GNUNET_TESTBED_operation_done (peer->op_handle); + peer->op_handle = NULL; + + if (strings_found == num_peers) + { + prof_time = GNUNET_TIME_absolute_get_duration (prof_start_time); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "All strings successfully matched in %s\n", + GNUNET_STRINGS_relative_time_to_string (prof_time, GNUNET_NO)); + + if (GNUNET_SCHEDULER_NO_TASK != search_timeout_task) { - unsigned int peer_cnt; - struct GNUNET_TESTBED_Peer *peer_handles[TOTAL_PEERS]; - - GNUNET_TESTBED_operation_done (event->details. - operation_finished.operation); - op[i] = NULL; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Operation %u finished\n", i); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Linking slave %i succeeded\n", i); - state[0] = CONNECTING_PEERS; - - for (peer_cnt = 0; peer_cnt < TOTAL_PEERS; peer_cnt++) - { - peer_handles[peer_cnt] = peers[peer_cnt].peer; - } - op[0] = - GNUNET_TESTBED_overlay_configure_topology (NULL, TOTAL_PEERS, - peer_handles, - GNUNET_TESTBED_TOPOLOGY_LINE); - GNUNET_assert (NULL != op[0]); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting peers...\n"); - break; + GNUNET_SCHEDULER_cancel (search_timeout_task); + search_timeout_task = GNUNET_SCHEDULER_NO_TASK; } - case CONNECTING_PEERS: + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Collecting stats and shutting down.\n"); + GNUNET_SCHEDULER_add_now (&do_collect_stats, NULL); + } +} + + +/** + * Connect by string timeout task. This will cancel the profiler after the + * specified timeout 'search_timeout'. + * + * @param cls NULL + * @param tc the task context + */ +static void +search_timed_out (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc) +{ + unsigned int i; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Finding matches to all strings did not succeed after %s.\n", + GNUNET_STRINGS_relative_time_to_string (search_timeout_time, + GNUNET_NO)); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Found %i of %i strings\n", strings_found, num_peers); + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Search timed out after %s." + "Collecting stats and shutting down.\n", + GNUNET_STRINGS_relative_time_to_string (search_timeout_time, + GNUNET_NO)); + + in_shutdown = GNUNET_YES; + for (i = 0; i < num_peers; i++) + { + if (NULL != peers[i].op_handle) { - GNUNET_TESTBED_operation_done (event->details. - operation_finished.operation); - op[i] = NULL; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Operation %u finished\n", i); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peers connected\n"); - break; + GNUNET_TESTBED_operation_done (peers[i].op_handle); + peers[i].op_handle = NULL; } - default: - GNUNET_break (0); - } - break; - default: - GNUNET_break (0); } + GNUNET_SCHEDULER_add_now (&do_collect_stats, NULL); } /** - * Callback which will be called to after a host registration succeeded or - * failed. Registration of all slave hosts is continued and linking of the hosts - * is started. + * Search timed out. It might still complete in the future, + * but we should start another one. * - * @param cls not used. - * @param emsg the error message; NULL if host registration is successful. + * @param cls Index of the next peer in the peers array. + * @param tc TaskContext. + */ +static void +find_timed_out (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct RegexPeer *p = cls; + + p->timeout = GNUNET_SCHEDULER_NO_TASK; + + if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) + return; + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Searching for string \"%s\" on peer %d timed out.\n", + p->search_str, + p->id); + if (GNUNET_NO == in_shutdown) + GNUNET_SCHEDULER_add_now (&announce_next_regex, NULL); +} + + +/** + * Start searching for a string in the DHT. + * + * @param cls Index of the next peer in the peers array. + * @param tc TaskContext. */ static void -registration_cont (void *cls, const char *emsg) +find_string (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { - struct Host *slave = (struct Host *) cls; + unsigned int search_peer = (unsigned int) (long) cls; + + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) || + search_peer >= num_peers || + GNUNET_YES == in_shutdown) + return; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Searching for string \"%s\" on peer %d (%u||)\n", + peers[search_peer].search_str, + search_peer, + parallel_searches); + + peers[search_peer].op_handle = + GNUNET_TESTBED_service_connect (NULL, + peers[search_peer].peer_handle, + "dht", + &dht_connect_cb, + &peers[search_peer], + &dht_ca, + &dht_da, + &peers[search_peer]); + GNUNET_assert (NULL != peers[search_peer].op_handle); + peers[search_peer].timeout = GNUNET_SCHEDULER_add_delayed (FIND_TIMEOUT, + &find_timed_out, + &peers[search_peer]); +} + + + + +/** + * Callback called when testbed has started the daemon we asked for. + * + * @param cls NULL + * @param op the operation handle + * @param emsg NULL on success; otherwise an error description + */ +static void +daemon_started (void *cls, struct GNUNET_TESTBED_Operation *op, + const char *emsg) +{ + struct RegexPeer *peer = (struct RegexPeer *) cls; + unsigned long search_peer; + unsigned int i; - if (NULL != emsg || NULL == slave) + GNUNET_TESTBED_operation_done (peer->daemon_op); + peer->daemon_op = NULL; + if (NULL != emsg) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", emsg); - GNUNET_assert (0); + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to start/stop daemon at peer %u: %s\n", peer->id, emsg); + GNUNET_abort (); } - state[host_registered] = LINKING; - slave->state = LINKING; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Linking host %u\n", host_registered); - slave->op = - GNUNET_TESTBED_controller_link ((void *) (long) host_registered, - master_ctrl, slave->host, NULL, cfg, - GNUNET_YES); - host_registered++; - if (NUM_HOSTS != host_registered) + /* Find a peer to look for a string matching the regex announced */ + search_peer = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, + num_peers); + for (i = 0; peers[search_peer].search_str != NULL; i++) { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Registering host %u with ip %s\n", - host_registered, slaves[host_registered].ip); - rh = GNUNET_TESTBED_register_host (master_ctrl, - slaves[host_registered].host, - ®istration_cont, - &slaves[host_registered]); - return; + search_peer = (search_peer + 1) % num_peers; + if (i > num_peers) + GNUNET_abort (); /* we ran out of peers, must be a bug */ } + peers[search_peer].search_str = search_strings[peer->id]; + peers[search_peer].search_str_matched = GNUNET_NO; + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply( + reannounce_period_max, + 2), + &find_string, + (void *) search_peer); } /** - * Callback to signal successfull startup of the controller process. If the - * startup was successfull the master controller and all slave hosts are - * created. Registering the slave hosts is started and continued in - * registration_cont. + * Task to start the daemons on each peer so that the regexes are announced + * into the DHT. * - * @param cls not used. - * @param config the configuration with which the controller has been started; - * NULL if status is not GNUNET_OK - * @param status GNUNET_OK if the startup is successfull; GNUNET_SYSERR if not, - * GNUNET_TESTBED_controller_stop() shouldn't be called in this case + * @param cls NULL + * @param tc the task context */ static void -status_cb (void *cls, const struct GNUNET_CONFIGURATION_Handle *config, - int status) +do_announce (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { unsigned int i; - if (NULL == config || GNUNET_OK != status) + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Starting announce.\n"); + + for (i = 0; i < init_parallel_searches; i++) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + " scheduling announce %u\n", + i); + (void) GNUNET_SCHEDULER_add_now (&announce_next_regex, NULL); + } +} + + +/** + * Start announcing the next regex in the DHT. + * + * @param cls Closure (unused). + * @param tc TaskContext. + */ +static void +announce_next_regex (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct RegexPeer *peer; + + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) return; + if (next_search >= num_peers) + { + if (strings_found != num_peers) + { + struct GNUNET_TIME_Relative new_delay; + if (GNUNET_SCHEDULER_NO_TASK != search_timeout_task) + GNUNET_SCHEDULER_cancel (search_timeout_task); + new_delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15); + search_timeout_task = GNUNET_SCHEDULER_add_delayed (new_delay, + &search_timed_out, + NULL); + } + return; + } - event_mask = 0; - event_mask |= (1L << GNUNET_TESTBED_ET_PEER_START); - event_mask |= (1L << GNUNET_TESTBED_ET_PEER_STOP); - event_mask |= (1L << GNUNET_TESTBED_ET_CONNECT); - event_mask |= (1L << GNUNET_TESTBED_ET_OPERATION_FINISHED); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting to master controller\n"); - master_ctrl = - GNUNET_TESTBED_controller_connect (config, master_host, event_mask, - &controller_cb, NULL); - GNUNET_assert (NULL != master_ctrl); - - for (i = 0; i < NUM_HOSTS; i++) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Creating host %u with ip %s\n", i, - slaves[i].ip); - slaves[i].host = GNUNET_TESTBED_host_create (slaves[i].ip, NULL, 0); - GNUNET_assert (NULL != slaves[i].host); - } - host_registered = 0; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Registering host %u with ip %s\n", - host_registered, slaves[0].ip); - rh = GNUNET_TESTBED_register_host (master_ctrl, slaves[0].host, - ®istration_cont, &slaves[0]); - GNUNET_assert (NULL != rh); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Starting daemon %u\n", next_search); + peer = &peers[next_search]; + peer->daemon_op = + GNUNET_TESTBED_peer_manage_service (NULL, + peer->peer_handle, + "regexprofiler", + &daemon_started, + peer, + 1); + next_search++; + parallel_searches++; +} + +/** + * DHT connect callback. Called when we are connected to the dht service for + * the peer in 'cls'. If successfull we connect to the stats service of this + * peer and then try to match the search string of this peer. + * + * @param cls internal peer id. + * @param op operation handle. + * @param ca_result connect adapter result. + * @param emsg error message. + */ +static void +dht_connect_cb (void *cls, struct GNUNET_TESTBED_Operation *op, + void *ca_result, const char *emsg) +{ + struct RegexPeer *peer = (struct RegexPeer *) cls; + + if (NULL != emsg || NULL == op || NULL == ca_result) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "DHT connect failed: %s\n", emsg); + GNUNET_abort (); + } + + GNUNET_assert (NULL != peer->dht_handle); + GNUNET_assert (peer->op_handle == op); + GNUNET_assert (peer->dht_handle == ca_result); + + peer->search_str_matched = GNUNET_NO; + peer->search_handle = REGEX_INTERNAL_search (peer->dht_handle, + peer->search_str, + ®ex_found_handler, peer, + NULL); + peer->prof_start_time = GNUNET_TIME_absolute_get (); } /** - * Main run function. + * DHT connect adapter. Opens a connection to the dht service. * - * @param cls not used. - * @param args arguments passed to GNUNET_PROGRAM_run - * @param cfgfile the path to configuration file - * @param config the configuration file handle + * @param cls Closure (peer). + * @param cfg Configuration handle. + * + * @return + */ +static void * +dht_ca (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct RegexPeer *peer = cls; + + peer->dht_handle = GNUNET_DHT_connect (cfg, 32); + + return peer->dht_handle; +} + + +/** + * Adapter function called to destroy a connection to the dht service. + * + * @param cls Closure (peer). + * @param op_result Service handle returned from the connect adapter. */ static void -run (void *cls, char *const *args, const char *cfgfile, - const struct GNUNET_CONFIGURATION_Handle *config) +dht_da (void *cls, void *op_result) { - master_host = GNUNET_TESTBED_host_create ("192.168.1.33", NULL, 0); - GNUNET_assert (NULL != master_host); - cfg = GNUNET_CONFIGURATION_dup (config); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting master controller\n"); - master_proc = - GNUNET_TESTBED_controller_start ("192.168.1.33", master_host, cfg, - status_cb, NULL); - abort_task = - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_MINUTES, 60), &do_abort, - NULL); + struct RegexPeer *peer = (struct RegexPeer *) cls; + + GNUNET_assert (peer->dht_handle == op_result); + + if (NULL != peer->search_handle) + { + REGEX_INTERNAL_search_cancel (peer->search_handle); + peer->search_handle = NULL; + } + + if (NULL != peer->dht_handle) + { + GNUNET_DHT_disconnect (peer->dht_handle); + peer->dht_handle = NULL; + } } /** - * Main function for profiling the regex/mesh implementation. Checks if all ssh - * connections to each of the hosts in 'slave_ips' is possible before setting up - * the testbed. + * Signature of a main function for a testcase. * - * @param argc argument count. - * @param argv argument values. + * @param cls NULL + * @param num_peers_ number of peers in 'peers' + * @param testbed_peers handle to peers run in the testbed. NULL upon timeout (see + * GNUNET_TESTBED_test_run()). + * @param links_succeeded the number of overlay link connection attempts that + * succeeded + * @param links_failed the number of overlay link connection attempts that + * failed + */ +static void +test_master (void *cls, + unsigned int num_peers_, + struct GNUNET_TESTBED_Peer **testbed_peers, + unsigned int links_succeeded, + unsigned int links_failed) +{ + unsigned int i; + + GNUNET_assert (num_peers_ == num_peers); + + prof_time = GNUNET_TIME_absolute_get_duration (prof_start_time); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Testbed started in %s\n", + GNUNET_STRINGS_relative_time_to_string (prof_time, GNUNET_NO)); + + if (GNUNET_SCHEDULER_NO_TASK != abort_task) + { + GNUNET_SCHEDULER_cancel (abort_task); + abort_task = GNUNET_SCHEDULER_NO_TASK; + } + + for (i = 0; i < num_peers; i++) + { + peers[i].peer_handle = testbed_peers[i]; + } + if (GNUNET_NO == + GNUNET_CONFIGURATION_get_value_yesno (cfg, "DHT", "DISABLE_TRY_CONNECT")) + { + struct GNUNET_TIME_Relative settle_time; + + settle_time = + GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, + 10 * num_peers); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Waiting for DHT for %s to settle new connections.\n\n", + GNUNET_STRINGS_relative_time_to_string(settle_time, GNUNET_NO)); + GNUNET_SCHEDULER_add_delayed (settle_time, &do_announce, NULL); + } + else + { + GNUNET_SCHEDULER_add_now (&do_announce, NULL); + } + search_timeout_task = + GNUNET_SCHEDULER_add_delayed (search_timeout_time, &search_timed_out, NULL); +} + +/** + * Function that will be called whenever something in the testbed changes. * - * @return 0 on success. + * @param cls closure, NULL + * @param event information on what is happening */ -int -main (int argc, char **argv) +static void +master_controller_cb (void *cls, + const struct GNUNET_TESTBED_EventInformation *event) { - int ret; - int test_hosts; + switch (event->type) + { + case GNUNET_TESTBED_ET_CONNECT: + printf("."); + break; + case GNUNET_TESTBED_ET_PEER_START: + printf("#"); + break; + default: + break; + } + fflush(stdout); +} + + +/******************************************************************************/ +/*************************** TESTBED PEER SETUP *****************************/ +/******************************************************************************/ + + +/** + * Load search strings from given filename. One search string per line. + * + * @param filename filename of the file containing the search strings. + * @param strings set of strings loaded from file. Caller needs to free this + * if number returned is greater than zero. + * @param limit upper limit on the number of strings read from the file + * @return number of strings found in the file. GNUNET_SYSERR on error. + */ +static int +load_search_strings (const char *filename, char ***strings, unsigned int limit) +{ + char *data; + char *buf; + uint64_t filesize; + unsigned int offset; + int str_cnt; unsigned int i; - struct GNUNET_GETOPT_CommandLineOption options[] = { - GNUNET_GETOPT_OPTION_END - }; - char *const argv2[] = { "gnunet-regex-profiler", - "-c", "regex_profiler_test.conf", - NULL - }; + if (NULL == filename) + { + return GNUNET_SYSERR; + } - test_hosts = GNUNET_OK; - for (i = 0; i < NUM_HOSTS; i++) - { - char *const remote_args[] = { - "ssh", "-o", "BatchMode=yes", slaves[i].ip, - "gnunet-helper-testbed --help > /dev/null", NULL - }; - struct GNUNET_OS_Process *auxp; - enum GNUNET_OS_ProcessStatusType type; - unsigned long code; - - fprintf (stderr, "Testing host %i\n", i); - auxp = - GNUNET_OS_start_process_vap (GNUNET_NO, GNUNET_OS_INHERIT_STD_ALL, NULL, - NULL, "ssh", remote_args); - GNUNET_assert (NULL != auxp); - do - { - ret = GNUNET_OS_process_status (auxp, &type, &code); - GNUNET_assert (GNUNET_SYSERR != ret); - (void) usleep (300); - } - while (GNUNET_NO == ret); - (void) GNUNET_OS_process_wait (auxp); - GNUNET_OS_process_destroy (auxp); - if (0 != code) + if (GNUNET_YES != GNUNET_DISK_file_test (filename)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Could not find search strings file %s\n", filename); + return GNUNET_SYSERR; + } + if (GNUNET_OK != GNUNET_DISK_file_size (filename, &filesize, GNUNET_YES, GNUNET_YES)) + filesize = 0; + if (0 == filesize) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Search strings file %s is empty.\n", filename); + return GNUNET_SYSERR; + } + data = GNUNET_malloc (filesize); + if (filesize != GNUNET_DISK_fn_read (filename, data, filesize)) + { + GNUNET_free (data); + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Could not read search strings file %s.\n", + filename); + return GNUNET_SYSERR; + } + buf = data; + offset = 0; + str_cnt = 0; + while (offset < (filesize - 1) && str_cnt < limit) + { + offset++; + if (((data[offset] == '\n')) && (buf != &data[offset])) { - fprintf (stderr, - "Unable to run the test as this system is not configured " - "to use password less SSH logins to host %s.\n", slaves[i].ip); - test_hosts = GNUNET_SYSERR; + data[offset] = '\0'; + str_cnt++; + buf = &data[offset + 1]; } + else if ((data[offset] == '\n') || (data[offset] == '\0')) + buf = &data[offset + 1]; } - if (test_hosts != GNUNET_OK) + *strings = GNUNET_malloc (sizeof (char *) * str_cnt); + offset = 0; + for (i = 0; i < str_cnt; i++) { - fprintf (stderr, "Some hosts have failed the ssh check. Exiting.\n"); - return 1; + GNUNET_asprintf (&(*strings)[i], "%s%s", regex_prefix, &data[offset]); + offset += strlen (&data[offset]) + 1; } - fprintf (stderr, "START.\n"); + GNUNET_free (data); + return str_cnt; +} - result = GNUNET_SYSERR; - ret = - GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2, - "gnunet-regex-profiler", "nohelp", options, &run, - NULL); +/** + * Main function that will be run by the scheduler. + * + * @param cls closure + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param config configuration + */ +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *config) +{ + unsigned int nsearchstrs; + unsigned int i; + struct GNUNET_TIME_Relative abort_time; + + in_shutdown = GNUNET_NO; + + /* Check config */ + if (NULL == config) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("No configuration file given. Exiting\n")); + shutdown_task = GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); + return; + } + cfg = GNUNET_CONFIGURATION_dup (config); + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, "REGEXPROFILER", + "REGEX_PREFIX", + ®ex_prefix)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Configuration option \"regex_prefix\" missing. Exiting\n")); + shutdown_task = GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); + return; + } + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (cfg, "REGEXPROFILER", + "PARALLEL_SEARCHES", + &init_parallel_searches)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Configuration option \"PARALLEL_SEARCHES\" missing." + " Using default (%d)\n", 10); + init_parallel_searches = 10; + } + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_time (cfg, "REGEXPROFILER", + "REANNOUNCE_PERIOD_MAX", + &reannounce_period_max)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "reannounce_period_max not given. Using 10 minutes.\n"); + reannounce_period_max = + GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 10); + } + + /* Check arguments */ + if (NULL == policy_dir) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("No policy directory specified on command line. Exiting.\n")); + return; + } + if (GNUNET_YES != GNUNET_DISK_directory_test (policy_dir, GNUNET_YES)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Specified policies directory does not exist. Exiting.\n")); + shutdown_task = GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); + return; + } + if (-1 == (num_peers = GNUNET_DISK_directory_scan (policy_dir, NULL, NULL))) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("No files found in `%s'\n"), + policy_dir); + return; + } + GNUNET_CONFIGURATION_set_value_string (cfg, "REGEXPROFILER", + "POLICY_DIR", policy_dir); + if (GNUNET_YES != GNUNET_DISK_file_test (strings_file)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("No search strings file given. Exiting.\n")); + shutdown_task = GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); + return; + } + nsearchstrs = load_search_strings (strings_file, + &search_strings, + num_peers); + if (num_peers != nsearchstrs) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Error loading search strings.\n"); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "File (%s) does not contain enough strings (%u/%u).\n", + strings_file, nsearchstrs, num_peers); + shutdown_task = GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); + return; + } + if (0 >= num_peers || NULL == search_strings) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Error loading search strings. Exiting.\n")); + shutdown_task = GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); + return; + } + for (i = 0; i < num_peers; i++) + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "search string: %s\n", + search_strings[i]); + + /* Check logfile */ + if ( (NULL != data_filename) && + (NULL == (data_file = + GNUNET_DISK_file_open (data_filename, + GNUNET_DISK_OPEN_READWRITE | + GNUNET_DISK_OPEN_TRUNCATE | + GNUNET_DISK_OPEN_CREATE, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE))) ) + { + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, + "open", + data_filename); + return; + } + + /* Initialize peers */ + peers = GNUNET_malloc (sizeof (struct RegexPeer) * num_peers); + for (i = 0; i < num_peers; i++) + { + peers[i].id = i; + } + + GNUNET_CONFIGURATION_set_value_number (cfg, + "TESTBED", "OVERLAY_RANDOM_LINKS", + num_peers * 20); + GNUNET_CONFIGURATION_set_value_number (cfg, + "DHT", "FORCE_NSE", + (long long unsigned) + (log (num_peers) / log (2.0))); + event_mask = 0LL; +/* For feedback about the start process activate these and pass master_cb */ + event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_START); +// event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_STOP); + event_mask |= (1LL << GNUNET_TESTBED_ET_CONNECT); +// event_mask |= (1LL << GNUNET_TESTBED_ET_DISCONNECT); + prof_start_time = GNUNET_TIME_absolute_get (); + GNUNET_TESTBED_run (hosts_file, + cfg, + num_peers, + event_mask, + &master_controller_cb, + NULL, /* master_controller_cb cls */ + &test_master, + NULL); /* test_master cls */ + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_time (cfg, "TESTBED", + "SETUP_TIMEOUT", + &abort_time)) + { + abort_time = + GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15); + } + abort_time = GNUNET_TIME_relative_add (abort_time, GNUNET_TIME_UNIT_MINUTES); + abort_task = + GNUNET_SCHEDULER_add_delayed (abort_time, + &do_abort, + (void*) __LINE__); +} - fprintf (stderr, "END.\n"); - if (GNUNET_SYSERR == result || GNUNET_OK != ret) +/** + * Main function. + * + * @param argc argument count + * @param argv argument values + * @return 0 on success + */ +int +main (int argc, char *const *argv) +{ + static const struct GNUNET_GETOPT_CommandLineOption options[] = { + {'o', "output-file", "FILENAME", + gettext_noop ("name of the file for writing statistics"), + GNUNET_YES, &GNUNET_GETOPT_set_string, &data_filename}, + {'t', "matching-timeout", "TIMEOUT", + gettext_noop ("wait TIMEOUT before ending the experiment"), + GNUNET_YES, &GNUNET_GETOPT_set_relative_time, &search_timeout_time}, + {'p', "policy-dir", "DIRECTORY", + gettext_noop ("directory with policy files"), + GNUNET_YES, &GNUNET_GETOPT_set_filename, &policy_dir}, + {'s', "strings-file", "FILENAME", + gettext_noop ("name of file with input strings"), + GNUNET_YES, &GNUNET_GETOPT_set_filename, &strings_file}, + {'H', "hosts-file", "FILENAME", + gettext_noop ("name of file with hosts' names"), + GNUNET_YES, &GNUNET_GETOPT_set_filename, &hosts_file}, + GNUNET_GETOPT_OPTION_END + }; + int ret; + + if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) + return 2; + result = GNUNET_SYSERR; + ret = + GNUNET_PROGRAM_run (argc, argv, + "gnunet-regex-profiler", + _("Profiler for regex"), + options, &run, NULL); + if (GNUNET_OK != ret) + return ret; + if (GNUNET_OK != result) return 1; return 0; }