From 34e40e006af57ec7cb7c69acf0273321550117dd Mon Sep 17 00:00:00 2001 From: Omar Tarabai Date: Fri, 15 Aug 2014 18:44:06 +0000 Subject: sensor: test case + fixes --- src/include/gnunet_protocols.h | 5 + src/include/gnunet_sensor_service.h | 22 +- src/include/gnunet_sensor_util_lib.h | 20 + src/sensor/Makefile.am | 9 + src/sensor/gnunet-sensor.c | 28 ++ src/sensor/gnunet-service-sensor.c | 2 + src/sensor/gnunet-service-sensor_reporting.c | 60 ++- src/sensor/sensor_api.c | 139 +++++- src/sensor/test_gnunet-service-sensor_reporting.c | 469 +++++++++++++++++++++ .../test_gnunet-service-sensor_reporting.conf | 13 + .../gnunet-service-sensordashboard.c | 20 +- 11 files changed, 755 insertions(+), 32 deletions(-) create mode 100644 src/sensor/test_gnunet-service-sensor_reporting.c create mode 100644 src/sensor/test_gnunet-service-sensor_reporting.conf diff --git a/src/include/gnunet_protocols.h b/src/include/gnunet_protocols.h index 176391580..68472a3f9 100644 --- a/src/include/gnunet_protocols.h +++ b/src/include/gnunet_protocols.h @@ -2458,6 +2458,11 @@ extern "C" */ #define GNUNET_MESSAGE_TYPE_SENSOR_ANOMALY_FORCE 810 +/** + * Sensor anomaly report exchanged between peers + */ +#define GNUNET_MESSAGE_TYPE_SENSOR_ANOMALY_REPORT_P2P 811 + /******************************************************************************* * PEERSTORE message types diff --git a/src/include/gnunet_sensor_service.h b/src/include/gnunet_sensor_service.h index 59e4248ab..250256cef 100644 --- a/src/include/gnunet_sensor_service.h +++ b/src/include/gnunet_sensor_service.h @@ -48,6 +48,11 @@ struct GNUNET_SENSOR_Handle; */ struct GNUNET_SENSOR_IterateContext; +/** + * Context of a force anomaly request + */ +struct GNUNET_SENSOR_ForceAnomalyContext; + /** * Structure containing brief info about sensor */ @@ -146,6 +151,16 @@ GNUNET_SENSOR_iterate (struct GNUNET_SENSOR_Handle *h, void *callback_cls); +/** + * Cancel a force anomaly request. + * + * @param fa Force anomaly context returned by GNUNET_SENSOR_force_anomaly() + */ +void +GNUNET_SENSOR_force_anomaly_cancel (struct GNUNET_SENSOR_ForceAnomalyContext + *fa); + + /** * Force an anomaly status change on a given sensor. If the sensor reporting * module is running, this will trigger the usual reporting logic, therefore, @@ -157,10 +172,13 @@ GNUNET_SENSOR_iterate (struct GNUNET_SENSOR_Handle *h, * @param h Service handle * @param sensor_name Sensor name to set the anomaly status * @param anomalous The desired status: #GNUNET_YES / #GNUNET_NO + * @param cont Continuation function to be called after the request is sent + * @param cont_cls Closure for cont */ -void +struct GNUNET_SENSOR_ForceAnomalyContext * GNUNET_SENSOR_force_anomaly (struct GNUNET_SENSOR_Handle *h, char *sensor_name, - int anomalous); + int anomalous, GNUNET_SENSOR_Continuation cont, + void *cont_cls); #if 0 /* keep Emacsens' auto-indent happy */ { diff --git a/src/include/gnunet_sensor_util_lib.h b/src/include/gnunet_sensor_util_lib.h index 87ae564fa..897fbbaad 100644 --- a/src/include/gnunet_sensor_util_lib.h +++ b/src/include/gnunet_sensor_util_lib.h @@ -189,6 +189,26 @@ struct GNUNET_SENSOR_SensorInfo }; +/** + * Anomaly report received and stored by sensor dashboard. + * Sensor name and peer id are not included because they are part of the + * peerstore key. + */ +struct GNUNET_SENSOR_DashboardAnomalyEntry +{ + + /** + * New anomaly status + */ + uint16_t anomalous; + + /** + * Percentage of neighbors reported the same anomaly + */ + float anomalous_neighbors; + +}; + GNUNET_NETWORK_STRUCT_BEGIN /** diff --git a/src/sensor/Makefile.am b/src/sensor/Makefile.am index f7f713fdd..4c19fc7f4 100644 --- a/src/sensor/Makefile.am +++ b/src/sensor/Makefile.am @@ -95,6 +95,15 @@ test_sensor_api_SOURCES = \ test_sensor_api_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la +test_gnunet_service_sensor_reporting_SOURCES = \ + test_gnunet-service-sensor_reporting.c +test_gnunet_service_sensor_reporting_LDADD = \ + libgnunetsensor.la \ + libgnunetsensorutil.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/testbed/libgnunettestbed.la \ + $(top_builddir)/src/peerstore/libgnunetpeerstore.la + pkgsensordir = sensors install-data-local: diff --git a/src/sensor/gnunet-sensor.c b/src/sensor/gnunet-sensor.c index ec7b5cb9e..7b7be61ef 100644 --- a/src/sensor/gnunet-sensor.c +++ b/src/sensor/gnunet-sensor.c @@ -39,6 +39,11 @@ static int get_all; */ static char *get_sensor; +/** + * option '-f' + */ +static char *force_anomaly; + /* * Handle to sensor service */ @@ -91,6 +96,21 @@ print_sensor_info (void *cls, const struct SensorInfoShort *sensor, } +/** + * Continuation called after a force anomaly request is sent. + * + * @param cls Closure (unused) + * @param emsg Error message, NULL of no error + */ +void +force_anomaly_cont (void *cls, const char *emsg) +{ + if (NULL != emsg) + printf ("Error: %s\n", emsg); + GNUNET_SCHEDULER_shutdown (); +} + + /** * Main function that will be run by the scheduler. * @@ -118,6 +138,11 @@ run (void *cls, char *const *args, const char *cfgfile, GNUNET_SENSOR_iterate (sensor_handle, GNUNET_TIME_UNIT_FOREVER_REL, get_sensor, &print_sensor_info, NULL); } + else if (NULL != force_anomaly) + { + GNUNET_SENSOR_force_anomaly (sensor_handle, "nse", GNUNET_YES, + &force_anomaly_cont, NULL); + } ret = 0; } @@ -139,6 +164,9 @@ main (int argc, char *const *argv) {'g', "get-sensor", NULL, gettext_noop ("Retrieve information about a single sensor"), 1, &GNUNET_GETOPT_set_string, &get_sensor}, + {'f', "force anomaly", NULL, + gettext_noop ("Force an anomaly on a sensor, use only for testing"), + 1, &GNUNET_GETOPT_set_string, &force_anomaly}, GNUNET_GETOPT_OPTION_END }; diff --git a/src/sensor/gnunet-service-sensor.c b/src/sensor/gnunet-service-sensor.c index 02bc00a1a..e8b01ae33 100644 --- a/src/sensor/gnunet-service-sensor.c +++ b/src/sensor/gnunet-service-sensor.c @@ -130,9 +130,11 @@ handle_anomaly_force (void *cls, struct GNUNET_SERVER_Client *client, { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Force anomaly message received for a sensor we don't have.\n"); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } SENSOR_reporting_anomaly_update (sensor, ntohs (anomaly_msg->anomalous)); + GNUNET_SERVER_receive_done (client, GNUNET_YES); } diff --git a/src/sensor/gnunet-service-sensor_reporting.c b/src/sensor/gnunet-service-sensor_reporting.c index a9d5d2e30..a2015f48e 100644 --- a/src/sensor/gnunet-service-sensor_reporting.c +++ b/src/sensor/gnunet-service-sensor_reporting.c @@ -472,6 +472,8 @@ get_cadet_peer (struct GNUNET_PeerIdentity pid) return cadetp; cadetp = cadetp->next; } + LOG (GNUNET_ERROR_TYPE_DEBUG, "Creating a CADET connection to peer `%s'.\n", + GNUNET_i2s (&pid)); /* Not found, create struct and channel */ cadetp = GNUNET_new (struct CadetPeer); cadetp->peer_id = pid; @@ -490,23 +492,26 @@ get_cadet_peer (struct GNUNET_PeerIdentity pid) * MQ envelope. * * @param ai Anomaly info struct to use + * @param type Message type * @return Envelope with message */ static struct GNUNET_MQ_Envelope * -create_anomaly_report_message (struct AnomalyInfo *ai) +create_anomaly_report_message (struct AnomalyInfo *ai, int type) { struct GNUNET_SENSOR_AnomalyReportMessage *arm; struct GNUNET_MQ_Envelope *ev; - ev = GNUNET_MQ_msg (arm, GNUNET_MESSAGE_TYPE_SENSOR_ANOMALY_REPORT); + ev = GNUNET_MQ_msg (arm, type); GNUNET_CRYPTO_hash (ai->sensor->name, strlen (ai->sensor->name) + 1, &arm->sensorname_hash); arm->sensorversion_major = htons (ai->sensor->version_major); arm->sensorversion_minor = htons (ai->sensor->version_minor); arm->anomalous = htons (ai->anomalous); arm->anomalous_neighbors = - ((float) GNUNET_CONTAINER_multipeermap_size (ai->anomalous_neighbors)) / - neighborhood; + (0 == + neighborhood) ? 0 : ((float) + GNUNET_CONTAINER_multipeermap_size + (ai->anomalous_neighbors)) / neighborhood; return ev; } @@ -542,13 +547,20 @@ create_value_message (struct ValueInfo *vi) * * @param mq Message queue to put the message in * @param ai Anomaly info to report + * @param p2p Is the report sent to a neighboring peer */ static void -send_anomaly_report (struct GNUNET_MQ_Handle *mq, struct AnomalyInfo *ai) +send_anomaly_report (struct GNUNET_MQ_Handle *mq, struct AnomalyInfo *ai, + int p2p) { struct GNUNET_MQ_Envelope *ev; + int type; - ev = create_anomaly_report_message (ai); + type = + (GNUNET_YES == + p2p) ? GNUNET_MESSAGE_TYPE_SENSOR_ANOMALY_REPORT_P2P : + GNUNET_MESSAGE_TYPE_SENSOR_ANOMALY_REPORT; + ev = create_anomaly_report_message (ai, type); GNUNET_MQ_send (mq, ev); } @@ -579,8 +591,9 @@ handle_anomaly_report (void *cls, const struct GNUNET_PeerIdentity *other, arm = (struct GNUNET_SENSOR_AnomalyReportMessage *) message; sensor = GNUNET_CONTAINER_multihashmap_get (sensors, &arm->sensorname_hash); - if (NULL == sensor || sensor->version_major != arm->sensorversion_major || - sensor->version_minor != arm->sensorversion_minor) + if (NULL == sensor || + sensor->version_major != ntohs (arm->sensorversion_major) || + sensor->version_minor != ntohs (arm->sensorversion_minor)) { LOG (GNUNET_ERROR_TYPE_WARNING, "I don't have the sensor reported by the peer `%s'.\n", @@ -610,8 +623,11 @@ handle_anomaly_report (void *cls, const struct GNUNET_PeerIdentity *other, if (NULL != ai->sensor->collection_point && GNUNET_YES == ai->sensor->report_anomalies) { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Sending anomaly report to collection point `%s'.\n", + GNUNET_i2s (ai->sensor->collection_point)); cadetp = get_cadet_peer (*ai->sensor->collection_point); - send_anomaly_report (cadetp->mq, ai); + send_anomaly_report (cadetp->mq, ai, GNUNET_NO); } return GNUNET_OK; } @@ -675,7 +691,7 @@ core_disconnect_cb (void *cls, const struct GNUNET_PeerIdentity *peer) corep = corep_head; while (NULL != corep) { - if (peer == corep->peer_id) + if (0 == GNUNET_CRYPTO_cmp_peer_identity (peer, corep->peer_id)) { GNUNET_CONTAINER_DLL_remove (corep_head, corep_tail, corep); destroy_core_peer (corep); @@ -683,9 +699,6 @@ core_disconnect_cb (void *cls, const struct GNUNET_PeerIdentity *peer) } corep = corep->next; } - LOG (GNUNET_ERROR_TYPE_ERROR, - _("Received disconnect notification from CORE" - " for a peer we didn't know about.\n")); } @@ -712,8 +725,11 @@ core_connect_cb (void *cls, const struct GNUNET_PeerIdentity *peer) ai = ai_head; while (NULL != ai) { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Updating newly connected neighbor `%s' with anomalous sensor.\n", + GNUNET_i2s (peer)); if (GNUNET_YES == ai->anomalous) - send_anomaly_report (corep->mq, ai); + send_anomaly_report (corep->mq, ai, GNUNET_YES); ai = ai->next; } } @@ -773,6 +789,9 @@ cadet_channel_destroyed (void *cls, const struct GNUNET_CADET_Channel *channel, if (GNUNET_YES == cadetp->destroying) return; + LOG (GNUNET_ERROR_TYPE_DEBUG, + "CADET channel was destroyed by remote peer `%s' or failed to start.\n", + GNUNET_i2s (&cadetp->peer_id)); GNUNET_CONTAINER_DLL_remove (cadetp_head, cadetp_tail, cadetp); cadetp->channel = NULL; destroy_cadet_peer (cadetp); @@ -801,6 +820,7 @@ SENSOR_reporting_anomaly_update (struct GNUNET_SENSOR_SensorInfo *sensor, if (GNUNET_NO == module_running) return; + LOG (GNUNET_ERROR_TYPE_DEBUG, "Received an external anomaly update.\n"); ai = get_anomaly_info_by_sensor (sensor); GNUNET_assert (NULL != ai); ai->anomalous = anomalous; @@ -808,15 +828,21 @@ SENSOR_reporting_anomaly_update (struct GNUNET_SENSOR_SensorInfo *sensor, corep = corep_head; while (NULL != corep) { - send_anomaly_report (corep->mq, ai); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Sending an anomaly report to neighbor `%s'.\n", + GNUNET_i2s (corep->peer_id)); + send_anomaly_report (corep->mq, ai, GNUNET_YES); corep = corep->next; } /* Report change to collection point if need */ if (NULL != ai->sensor->collection_point && GNUNET_YES == ai->sensor->report_anomalies) { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Sending anomaly report to collection point `%s'.\n", + GNUNET_i2s (ai->sensor->collection_point)); cadetp = get_cadet_peer (*ai->sensor->collection_point); - send_anomaly_report (cadetp->mq, ai); + send_anomaly_report (cadetp->mq, ai, GNUNET_NO); } } @@ -924,7 +950,7 @@ SENSOR_reporting_start (const struct GNUNET_CONFIGURATION_Handle *c, struct GNUNET_CONTAINER_MultiHashMap *s) { static struct GNUNET_CORE_MessageHandler core_handlers[] = { - {&handle_anomaly_report, GNUNET_MESSAGE_TYPE_SENSOR_ANOMALY_REPORT, + {&handle_anomaly_report, GNUNET_MESSAGE_TYPE_SENSOR_ANOMALY_REPORT_P2P, sizeof (struct GNUNET_SENSOR_AnomalyReportMessage)}, {NULL, 0, 0} }; diff --git a/src/sensor/sensor_api.c b/src/sensor/sensor_api.c index 9a18427d0..628873f91 100644 --- a/src/sensor/sensor_api.c +++ b/src/sensor/sensor_api.c @@ -46,15 +46,25 @@ struct GNUNET_SENSOR_Handle struct GNUNET_CLIENT_Connection *client; /** - * Head of iterator DLL. + * Head of iteration requests DLL. */ struct GNUNET_SENSOR_IterateContext *ic_head; /** - * Tail of iterator DLL. + * Tail of iteration requests DLL. */ struct GNUNET_SENSOR_IterateContext *ic_tail; + /** + * Head of force anomaly requests + */ + struct GNUNET_SENSOR_ForceAnomalyContext *fa_head; + + /** + * Tail of force anomaly requests + */ + struct GNUNET_SENSOR_ForceAnomalyContext *fa_tail; + /** * Message queue used to send data to service */ @@ -115,6 +125,44 @@ struct GNUNET_SENSOR_IterateContext }; +/** + * Context of a force anomaly request + */ +struct GNUNET_SENSOR_ForceAnomalyContext +{ + + /** + * DLL + */ + struct GNUNET_SENSOR_ForceAnomalyContext *next; + + /** + * DLL + */ + struct GNUNET_SENSOR_ForceAnomalyContext *prev; + + /** + * Handle to the SENSOR service. + */ + struct GNUNET_SENSOR_Handle *h; + + /** + * Envelope containing iterate request. + */ + struct GNUNET_MQ_Envelope *ev; + + /** + * User continuation function + */ + GNUNET_SENSOR_Continuation cont; + + /** + * Closure for cont + */ + void *cont_cls; + +}; + /** * Notifier of an error encountered by MQ. @@ -222,7 +270,8 @@ handle_sensor_info (void *cls, const struct GNUNET_MessageHeader *msg) /** - * Disconnect from the sensor service + * Disconnect from the sensor service. + * Please disconnect only when all requests sent are complete or canceled. * * @param h handle to disconnect */ @@ -230,16 +279,34 @@ void GNUNET_SENSOR_disconnect (struct GNUNET_SENSOR_Handle *h) { struct GNUNET_SENSOR_IterateContext *ic; + GNUNET_SENSOR_SensorIterateCB ic_callback; + void *ic_callback_cls; + struct GNUNET_SENSOR_ForceAnomalyContext *fa; + GNUNET_SENSOR_Continuation fa_cont; + void *fa_cont_cls; ic = h->ic_head; while (NULL != ic) { - if (NULL != ic->callback) - ic->callback (ic->callback_cls, NULL, - _("Iterate request canceled due to disconnection.\n")); + ic_callback = ic->callback; + ic_callback_cls = ic->callback_cls; GNUNET_SENSOR_iterate_cancel (ic); + if (NULL != ic_callback) + ic_callback (ic_callback_cls, NULL, + _("Iterate request canceled due to disconnection.\n")); ic = h->ic_head; } + fa = h->fa_head; + while (NULL != fa) + { + fa_cont = fa->cont; + fa_cont_cls = fa->cont_cls; + GNUNET_SENSOR_force_anomaly_cancel (fa); + if (NULL != fa_cont) + fa_cont (fa_cont_cls, + _("Force anomaly request canceled due to disconnection.\n")); + fa = h->fa_head; + } if (NULL != h->mq) { GNUNET_MQ_destroy (h->mq); @@ -413,6 +480,49 @@ GNUNET_SENSOR_iterate (struct GNUNET_SENSOR_Handle *h, } +/** + * Callback from MQ when the request has already been sent to the service. + * Now it can not be canelled. + * + * @param cls closure + */ +static void +force_anomaly_sent (void *cls) +{ + struct GNUNET_SENSOR_ForceAnomalyContext *fa = cls; + GNUNET_SENSOR_Continuation cont; + void *cont_cls; + + fa->ev = NULL; + cont = fa->cont; + cont_cls = fa->cont_cls; + GNUNET_SENSOR_force_anomaly_cancel (fa); + if (NULL != cont) + cont (cont_cls, NULL); +} + + +/** + * Cancel a force anomaly request. + * + * @param fa Force anomaly context returned by GNUNET_SENSOR_force_anomaly() + */ +void +GNUNET_SENSOR_force_anomaly_cancel (struct GNUNET_SENSOR_ForceAnomalyContext + *fa) +{ + struct GNUNET_SENSOR_Handle *h = fa->h; + + if (NULL != fa->ev) + { + GNUNET_MQ_send_cancel (fa->ev); + fa->ev = NULL; + } + GNUNET_CONTAINER_DLL_remove (h->fa_head, h->fa_tail, fa); + GNUNET_free (fa); +} + + /** * Force an anomaly status change on a given sensor. If the sensor reporting * module is running, this will trigger the usual reporting logic, therefore, @@ -424,19 +534,32 @@ GNUNET_SENSOR_iterate (struct GNUNET_SENSOR_Handle *h, * @param h Service handle * @param sensor_name Sensor name to set the anomaly status * @param anomalous The desired status: #GNUNET_YES / #GNUNET_NO + * @param cont Continuation function to be called after the request is sent + * @param cont_cls Closure for cont */ -void +struct GNUNET_SENSOR_ForceAnomalyContext * GNUNET_SENSOR_force_anomaly (struct GNUNET_SENSOR_Handle *h, char *sensor_name, - int anomalous) + int anomalous, GNUNET_SENSOR_Continuation cont, + void *cont_cls) { struct ForceAnomalyMessage *msg; struct GNUNET_MQ_Envelope *ev; + struct GNUNET_SENSOR_ForceAnomalyContext *fa; ev = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SENSOR_ANOMALY_FORCE); GNUNET_CRYPTO_hash (sensor_name, strlen (sensor_name) + 1, &msg->sensor_name_hash); msg->anomalous = htons (anomalous); GNUNET_MQ_send (h->mq, ev); + fa = GNUNET_new (struct GNUNET_SENSOR_ForceAnomalyContext); + + fa->h = h; + fa->cont = cont; + fa->cont_cls = cont_cls; + fa->ev = ev; + GNUNET_CONTAINER_DLL_insert_tail (h->fa_head, h->fa_tail, fa); + GNUNET_MQ_notify_sent (ev, &force_anomaly_sent, fa); + return fa; } diff --git a/src/sensor/test_gnunet-service-sensor_reporting.c b/src/sensor/test_gnunet-service-sensor_reporting.c new file mode 100644 index 000000000..969ab16ec --- /dev/null +++ b/src/sensor/test_gnunet-service-sensor_reporting.c @@ -0,0 +1,469 @@ + /* + * This file is part of GNUnet. + * (C) + * + * GNUnet is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 3, or (at your + * option) any later version. + * + * GNUnet is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNUnet; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +/** + * @file sensor/test_gnunet-service-sensor_reporting.c + * @brief testcase for gnunet-service-sensor_reporting.c + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_testbed_service.h" +#include "gnunet_sensor_util_lib.h" +#include "sensor.h" +#include "gnunet_peerstore_service.h" +#include "gnunet_sensor_service.h" + +/** + * Number of peers to start for the test + */ +#define NUM_PEERS 2 + +/** + * Test timeout + */ +#define TEST_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1) + +/** + * Information about a test peer + */ +struct TestPeer +{ + + /** + * DLL + */ + struct TestPeer *prev; + + /** + * DLL + */ + struct TestPeer *next; + + /** + * TESTBED information about the peer + */ + struct GNUNET_TESTBED_Peer *testbed_peer; + + /** + * Peer indentity + */ + struct GNUNET_PeerIdentity peer_id; + + /** + * Peerstore watch context for this peer's anomaly reports + */ + struct GNUNET_PEERSTORE_WatchContext *wc; + + /** + * TESTBED operation connecting us to sensor service + */ + struct GNUNET_TESTBED_Operation *sensor_op; + +}; + +/** + * Test name + */ +const static char *testname = "test_gnunet-service-sensor_reporting"; + +/** + * Name of GNUNET config file used in this test + */ +const static char *cfg_filename = "test_gnunet-service-sensor_reporting.conf"; + +/** + * Test sensor name + */ +const static char *sensor_name = "test-sensor-statistics"; + +/** + * Path to read test sensor from + */ +const static char *sensor_path_src = "test_sensors/test-sensor-statistics"; + +/** + * Path to write new test sensor to + */ +const static char *sensor_path_dest = + "/tmp/test-gnunet-service-sensor-reporting/test-sensor-statistics"; + +/** + * Head of DLL of peers + */ +static struct TestPeer *peer_head; + +/** + * Tail of DLL of peers + */ +static struct TestPeer *peer_tail; + +/** + * Number of peers started and got information for + */ +static int started_peers = 0; + +/** + * TESTBED operation connecting us to peerstore service + */ +struct GNUNET_TESTBED_Operation *peerstore_op; + +/** + * Handle to the peerstore service + */ +struct GNUNET_PEERSTORE_Handle *peerstore; + +/** + * Task used to shutdown / expire the test + */ +static GNUNET_SCHEDULER_TaskIdentifier shutdown_task; + +/** + * Status of the test to be returned by main() + */ +static int ok = 1; + + +/** + * Shutdown task + * + * @param cls Closure (unused) + * @param tc Task context (unused) + */ +static void +do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + //TODO: destroy list of peers + if (NULL != peerstore_op) + { + GNUNET_TESTBED_operation_done (peerstore_op); + peerstore_op = NULL; + } + GNUNET_SCHEDULER_shutdown (); +} + + +/** + * Write new temp sensor directory with a sensor updated with collection point + * peer id + */ +void +write_new_sensor_dir (struct TestPeer *cp_peer) +{ + struct GNUNET_CONFIGURATION_Handle *sensorcfg; + + GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_test (sensor_path_src)); + sensorcfg = GNUNET_CONFIGURATION_create (); + GNUNET_assert (GNUNET_SYSERR != + GNUNET_CONFIGURATION_parse (sensorcfg, sensor_path_src)); + GNUNET_CONFIGURATION_set_value_string (sensorcfg, sensor_name, + "COLLECTION_POINT", + GNUNET_i2s_full (&cp_peer->peer_id)); + GNUNET_assert (GNUNET_OK == + GNUNET_DISK_directory_create_for_file (sensor_path_dest)); + GNUNET_CONFIGURATION_write (sensorcfg, sensor_path_dest); + GNUNET_CONFIGURATION_destroy (sensorcfg); +} + + +/** + * Function called by PEERSTORE for each matching record. + * + * @param cls closure + * @param record peerstore record information + * @param emsg error message, or NULL if no errors + * @return #GNUNET_YES to continue iterating, #GNUNET_NO to stop + */ +static int +peerstore_watch_cb (void *cls, struct GNUNET_PEERSTORE_Record *record, + char *emsg) +{ + struct TestPeer *peer = cls; + struct GNUNET_SENSOR_DashboardAnomalyEntry *anomaly; + + GNUNET_assert (NULL != record); + GNUNET_assert (record->value_size == + sizeof (struct GNUNET_SENSOR_DashboardAnomalyEntry)); + anomaly = record->value; + GNUNET_assert (0 == + GNUNET_CRYPTO_cmp_peer_identity (&peer->peer_id, + record->peer)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peerstore watch got an anomaly report from peer `%s':\n" + "Anomalous: %d\n" "Anomalous neigbors: %f.\n", + GNUNET_i2s (&peer->peer_id), anomaly->anomalous, + anomaly->anomalous_neighbors); + //TODO + return GNUNET_YES; +} + + +/** + * Callback to be called when sensor service connect operation is completed + * + * @param cls the callback closure from functions generating an operation + * @param op the operation that has been finished + * @param ca_result the service handle returned from GNUNET_TESTBED_ConnectAdapter() + * @param emsg error message in case the operation has failed; will be NULL if + * operation has executed successfully. + */ +static void +sensor_connect_cb (void *cls, struct GNUNET_TESTBED_Operation *op, + void *ca_result, const char *emsg) +{ + struct TestPeer *peer = cls; + struct GNUNET_SENSOR_Handle *sensor = ca_result; + + GNUNET_SENSOR_force_anomaly (sensor, (char *) sensor_name, GNUNET_YES, NULL, + NULL); +} + + +/** + * Adapter function called to establish a connection to sensor service. + * + * @param cls closure + * @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 * +sensor_connect_adapter (void *cls, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct GNUNET_SENSOR_Handle *sensor; + + sensor = GNUNET_SENSOR_connect (cfg); + return sensor; +} + + +/** + * Adapter function called to destroy a connection to sensor service. + * + * @param cls closure + * @param op_result service handle returned from the connect adapter + */ +static void +sensor_disconnect_adapter (void *cls, void *op_result) +{ + struct GNUNET_SENSOR_Handle *sensor = op_result; + + GNUNET_SENSOR_disconnect (sensor); +} + + +/** + * Callback to be called when sensor service is started + * + * @param cls the callback closure from functions generating an operation + * @param op the operation that has been finished + * @param emsg error message in case the operation has failed; will be NULL if + * operation has executed successfully. + */ +static void +sensor_service_started (void *cls, struct GNUNET_TESTBED_Operation *op, + const char *emsg) +{ + struct TestPeer *peer = cls; + + GNUNET_assert (NULL == emsg); + peer->sensor_op = + GNUNET_TESTBED_service_connect (NULL, peer->testbed_peer, "sensor", + &sensor_connect_cb, peer, + &sensor_connect_adapter, + &sensor_disconnect_adapter, NULL); + GNUNET_TESTBED_operation_done (op); +} + + +/** + * Callback to be called when peerstore service connect operation is completed + * + * @param cls the callback closure from functions generating an operation + * @param op the operation that has been finished + * @param ca_result the service handle returned from GNUNET_TESTBED_ConnectAdapter() + * @param emsg error message in case the operation has failed; will be NULL if + * operation has executed successfully. + */ +static void +peerstore_connect_cb (void *cls, struct GNUNET_TESTBED_Operation *op, + void *ca_result, const char *emsg) +{ + struct TestPeer *peer; + + peer = peer_head; + while (NULL != peer) + { + GNUNET_PEERSTORE_watch (peerstore, "sensordashboard-anomalies", + &peer->peer_id, sensor_name, &peerstore_watch_cb, + peer); + /* Start sensor service */ + GNUNET_TESTBED_peer_manage_service (NULL, peer->testbed_peer, "sensor", + &sensor_service_started, peer, 1); + peer = peer->next; + } +} + + +/** + * Adapter function called to establish a connection to peerstore service. + * + * @param cls closure + * @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 * +peerstore_connect_adapter (void *cls, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + peerstore = GNUNET_PEERSTORE_connect (cfg); + GNUNET_assert (NULL != peerstore); + return peerstore; +} + + +/** + * Adapter function called to destroy a connection to peerstore service. + * + * @param cls closure + * @param op_result service handle returned from the connect adapter + */ +static void +peerstore_disconnect_adapter (void *cls, void *op_result) +{ + GNUNET_PEERSTORE_disconnect (peerstore, GNUNET_NO); + peerstore = NULL; + peerstore_op = NULL; +} + + +/** + * Callback to be called when dashboard service is started + * + * @param cls the callback closure from functions generating an operation + * @param op the operation that has been finished + * @param emsg error message in case the operation has failed; will be NULL if + * operation has executed successfully. + */ +static void +dashboard_started (void *cls, struct GNUNET_TESTBED_Operation *op, + const char *emsg) +{ + GNUNET_assert (NULL == emsg); + GNUNET_TESTBED_operation_done (op); + /* Connect to peerstore service on first peer */ + peerstore_op = + GNUNET_TESTBED_service_connect (NULL, peer_head->testbed_peer, + "peerstore", &peerstore_connect_cb, NULL, + &peerstore_connect_adapter, + &peerstore_disconnect_adapter, NULL); +} + + +/** + * Callback to be called when the requested peer information is available + * + * @param cb_cls the closure from GNUNET_TETSBED_peer_get_information() + * @param op the operation this callback corresponds to + * @param pinfo the result; will be NULL if the operation has failed + * @param emsg error message if the operation has failed; will be NULL if the + * operation is successfull + */ +static void +peer_info_cb (void *cb_cls, struct GNUNET_TESTBED_Operation *op, + const struct GNUNET_TESTBED_PeerInformation *pinfo, + const char *emsg) +{ + struct GNUNET_TESTBED_Peer *testbed_peer = cb_cls; + struct TestPeer *peer; + + peer = GNUNET_new (struct TestPeer); + + peer->testbed_peer = testbed_peer; + GNUNET_CRYPTO_get_peer_identity (pinfo->result.cfg, &peer->peer_id); + if (NULL == peer_head) /* First peer (collection point) */ + { + /* Rewrite sensor with collection point peer id */ + write_new_sensor_dir (peer); + } + GNUNET_CONTAINER_DLL_insert_tail (peer_head, peer_tail, peer); + started_peers++; + if (NUM_PEERS == started_peers) + { + /* Start dashboard service on first peer */ + GNUNET_TESTBED_peer_manage_service (NULL, peer_head->testbed_peer, + "sensordashboard", &dashboard_started, + NULL, 1); + } + GNUNET_TESTBED_operation_done (op); +} + + +/** + * Signature of a main function for a testcase. + * + * @param cls closure + * @param h the run handle + * @param num_peers number of peers in 'peers' + * @param 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 + * @see GNUNET_TESTBED_test_run() + */ +static void +test_master (void *cls, struct GNUNET_TESTBED_RunHandle *h, + unsigned int num_peers, struct GNUNET_TESTBED_Peer **peers, + unsigned int links_succeeded, unsigned int links_failed) +{ + int i; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%d peers started. %d links succeeded. %d links failed.\n", + num_peers, links_succeeded, links_failed); + GNUNET_assert (NUM_PEERS == num_peers); + GNUNET_assert (0 == links_failed); + /* Schedule test timeout */ + shutdown_task = + GNUNET_SCHEDULER_add_delayed (TEST_TIMEOUT, &do_shutdown, NULL); + /* Collect peer information */ + for (i = 0; i < num_peers; i++) + { + GNUNET_TESTBED_peer_get_information (peers[i], + GNUNET_TESTBED_PIT_CONFIGURATION, + &peer_info_cb, peers[i]); + } +} + + +int +main (int argc, char *argv[]) +{ + GNUNET_log_setup (testname, "INFO", NULL); + if (GNUNET_OK == + GNUNET_TESTBED_test_run (testname, cfg_filename, NUM_PEERS, 0, NULL, NULL, + &test_master, NULL)) + return ok; + return 1; +} diff --git a/src/sensor/test_gnunet-service-sensor_reporting.conf b/src/sensor/test_gnunet-service-sensor_reporting.conf new file mode 100644 index 000000000..4dc073856 --- /dev/null +++ b/src/sensor/test_gnunet-service-sensor_reporting.conf @@ -0,0 +1,13 @@ +[testbed] +OVERLAY_TOPOLOGY = CLIQUE + +[arm] +DEFAULTSERVICES = core + +[sensor] +SENSOR_DIR = /tmp/test-gnunet-service-sensor-reporting/ + +START_MONITORING = NO +START_REPORTING = YES +START_ANALYSIS = NO +START_UPDATE = NO \ No newline at end of file diff --git a/src/sensordashboard/gnunet-service-sensordashboard.c b/src/sensordashboard/gnunet-service-sensordashboard.c index 7dc1b33d6..1af3be332 100644 --- a/src/sensordashboard/gnunet-service-sensordashboard.c +++ b/src/sensordashboard/gnunet-service-sensordashboard.c @@ -421,9 +421,12 @@ handle_anomaly_report (void *cls, struct GNUNET_CADET_Channel *channel, struct ClientPeerContext *cp = *channel_ctx; struct GNUNET_SENSOR_AnomalyReportMessage *anomaly_msg; struct GNUNET_SENSOR_SensorInfo *sensor; - uint16_t anomalous; + struct GNUNET_SENSOR_DashboardAnomalyEntry *anomaly_entry; struct GNUNET_TIME_Absolute expiry; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received an anomaly report message from peer `%s'.\n", + GNUNET_i2s (&cp->peerid)); anomaly_msg = (struct GNUNET_SENSOR_AnomalyReportMessage *) message; sensor = GNUNET_CONTAINER_multihashmap_get (sensors, @@ -433,13 +436,20 @@ handle_anomaly_report (void *cls, struct GNUNET_CADET_Channel *channel, GNUNET_break_op (0); return GNUNET_SYSERR; } - anomalous = ntohs (anomaly_msg->anomalous); + anomaly_entry = GNUNET_new (struct GNUNET_SENSOR_DashboardAnomalyEntry); + anomaly_entry->anomalous = ntohs (anomaly_msg->anomalous); + anomaly_entry->anomalous_neighbors = anomaly_msg->anomalous_neighbors; expiry = (GNUNET_YES == - anomalous) ? GNUNET_TIME_UNIT_FOREVER_ABS : GNUNET_TIME_absolute_get (); + anomaly_entry->anomalous) ? GNUNET_TIME_UNIT_FOREVER_ABS : + GNUNET_TIME_absolute_get (); GNUNET_PEERSTORE_store (peerstore, anomalies_subsystem, &cp->peerid, - sensor->name, &anomalous, sizeof (anomalous), expiry, - GNUNET_PEERSTORE_STOREOPTION_REPLACE, NULL, NULL); + sensor->name, anomaly_entry, + sizeof (struct GNUNET_SENSOR_DashboardAnomalyEntry), + expiry, GNUNET_PEERSTORE_STOREOPTION_REPLACE, NULL, + NULL); + GNUNET_free (anomaly_entry); + GNUNET_CADET_receive_done (channel); return GNUNET_OK; } -- cgit v1.2.3