aboutsummaryrefslogtreecommitdiff
path: root/src/integration-tests/connection_watchdog.c
diff options
context:
space:
mode:
authorBertrand Marc <beberking@gmail.com>2012-06-06 20:47:48 +0200
committerBertrand Marc <beberking@gmail.com>2012-06-06 20:47:48 +0200
commit740b30688bd745a527f96f9116c19acb3480971a (patch)
tree2709a3f4dba11c174aa9e1ba3612e30c578e76a9 /src/integration-tests/connection_watchdog.c
parent2b81464a43485fcc8ce079fafdee7b7a171835f4 (diff)
Imported Upstream version 0.9.3upstream/0.9.3
Diffstat (limited to 'src/integration-tests/connection_watchdog.c')
-rw-r--r--src/integration-tests/connection_watchdog.c1099
1 files changed, 1099 insertions, 0 deletions
diff --git a/src/integration-tests/connection_watchdog.c b/src/integration-tests/connection_watchdog.c
new file mode 100644
index 0000000..ac19338
--- /dev/null
+++ b/src/integration-tests/connection_watchdog.c
@@ -0,0 +1,1099 @@
+/*
+ This file is part of GNUnet.
+ (C) 2009, 2010 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
+ 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 integration-tests/connection_watchdog.c
+ * @brief tool to monitor core and transport connections for consistency
+ * @author Matthias Wachs
+ */
+#include "platform.h"
+#include "gnunet_common.h"
+#include "gnunet_constants.h"
+#include "gnunet_arm_service.h"
+#include "gnunet_core_service.h"
+#include "gnunet_getopt_lib.h"
+#include "gnunet_os_lib.h"
+#include "gnunet_program_lib.h"
+#include "gnunet_scheduler_lib.h"
+#include "gnunet_transport_service.h"
+#include "gnunet_statistics_service.h"
+
+
+#define CHECK_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
+#define STATS_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
+#define REPEATED_STATS_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
+#define STATS_VALUES 4
+
+/**
+ * Final status code.
+ */
+static int ret;
+static int ping;
+
+static int have_tcp;
+static int have_udp;
+static int have_http;
+static int have_https;
+static int have_unix;
+
+static struct GNUNET_TRANSPORT_Handle *th;
+static struct GNUNET_CORE_Handle *ch;
+static struct GNUNET_PeerIdentity my_peer_id;
+static const struct GNUNET_CONFIGURATION_Handle *mycfg;
+static struct GNUNET_STATISTICS_Handle *stats;
+
+
+static unsigned int transport_connections;
+static unsigned int core_connections;
+
+static GNUNET_SCHEDULER_TaskIdentifier check_task;
+static GNUNET_SCHEDULER_TaskIdentifier statistics_task;
+
+static uint64_t statistics_transport_connections;
+static uint64_t statistics_transport_tcp_connections;
+static uint64_t statistics_core_neighbour_entries;
+static uint64_t statistics_core_entries_session_map;
+
+int stat_check_running;
+
+static struct GNUNET_CONTAINER_MultiHashMap *peers;
+
+struct PeerContainer
+{
+ struct GNUNET_PeerIdentity id;
+ int transport_connected;
+ int core_connected;
+ struct GNUNET_TRANSPORT_TransmitHandle *th_ping;
+ struct GNUNET_CORE_TransmitHandle *ch_ping;
+
+ struct GNUNET_TRANSPORT_TransmitHandle *th_pong;
+ struct GNUNET_CORE_TransmitHandle *ch_pong;
+};
+
+
+enum protocol
+{
+ tcp,
+ udp,
+ unixdomain
+};
+
+struct TransportPlugin
+{
+ /**
+ * This is a doubly-linked list.
+ */
+ struct TransportPlugin *next;
+
+ /**
+ * This is a doubly-linked list.
+ */
+ struct TransportPlugin *prev;
+
+ /**
+ * Short name for the plugin (i.e. "tcp").
+ */
+ char *short_name;
+
+ int port;
+
+ int protocol;
+};
+
+struct TransportPlugin *phead;
+struct TransportPlugin *ptail;
+
+static int
+map_check_it (void *cls,
+ const GNUNET_HashCode * key,
+ void *value)
+{
+ int *fail = cls;
+ struct PeerContainer *pc = value;
+ if (pc->core_connected != pc->transport_connected)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Inconsistent peer `%s': TRANSPORT %s <-> CORE %s\n",
+ GNUNET_i2s (&pc->id),
+ (GNUNET_YES == pc->transport_connected) ? "YES" : "NO",
+ (GNUNET_YES == pc->core_connected) ? "YES" : "NO");
+ (*fail) ++;
+ }
+
+ return GNUNET_OK;
+}
+
+
+static int
+map_cleanup_it (void *cls,
+ const GNUNET_HashCode * key,
+ void *value)
+{
+ struct PeerContainer *pc = value;
+ GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_remove(peers, key, value));
+ if (NULL != pc->th_ping)
+ {
+ GNUNET_TRANSPORT_notify_transmit_ready_cancel(pc->th_ping);
+ pc->th_ping = NULL;
+ }
+ if (NULL != pc->th_pong)
+ {
+ GNUNET_TRANSPORT_notify_transmit_ready_cancel(pc->th_pong);
+ pc->th_pong = NULL;
+ }
+ if (NULL != pc->ch_ping)
+ {
+ GNUNET_CORE_notify_transmit_ready_cancel (pc->ch_ping);
+ pc->ch_ping = NULL;
+ }
+ if (NULL != pc->ch_pong)
+ {
+ GNUNET_CORE_notify_transmit_ready_cancel(pc->ch_pong);
+ pc->ch_pong = NULL;
+ }
+ GNUNET_free (pc);
+ return GNUNET_OK;
+}
+
+static void
+map_cleanup (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ GNUNET_CONTAINER_multihashmap_iterate (peers, &map_cleanup_it, NULL);
+ GNUNET_CONTAINER_multihashmap_destroy(peers);
+}
+
+static void
+map_check (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ int fail = 0;
+ check_task = GNUNET_SCHEDULER_NO_TASK;
+ GNUNET_CONTAINER_multihashmap_iterate (peers, &map_check_it, &fail);
+ if (0 > fail)
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Inconsistent peers after connection consistency check: %u\n", fail);
+ else
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Inconsistent peers after connection consistency check: %u\n", fail);
+
+
+ if (NULL != cls)
+ {
+ GNUNET_SCHEDULER_add_now (cls, NULL);
+ }
+}
+
+
+static void
+stats_check (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+static int
+check_lowlevel_connections (int port, int protocol)
+{
+ FILE *f;
+ char * cmdline;
+ char * proto;
+ char line[1024];
+ int count = -1;
+#ifdef MINGW
+ /* not supported */
+ return count;
+#else
+
+ switch (protocol) {
+ case tcp:
+ proto = "-t";
+ break;
+ case udp:
+ proto = "-u";
+ break;
+ case unixdomain:
+ proto = "-x";
+ break;
+ default:
+ proto = "";
+ break;
+ }
+
+ /* Use netstat to get a numeric list of all connections on port 'port' in state 'ESTABLISHED' */
+ GNUNET_asprintf(&cmdline, "netstat -n %s | grep %u | grep ESTABLISHED", proto, port);
+
+ if (system ("netstat -n > /dev/null 2> /dev/null"))
+ if (system ("netstat -n > /dev/null 2> /dev/null") == 0)
+ f = popen (cmdline, "r");
+ else
+ f = NULL;
+ else
+ f = popen (cmdline, "r");
+ if (!f)
+ {
+ GNUNET_log_strerror(GNUNET_ERROR_TYPE_ERROR, "ss");
+ GNUNET_free (cmdline);
+ return -1;
+ }
+
+ count = 0;
+ while (NULL != fgets (line, sizeof (line), f))
+ {
+ /* read */
+ //printf ("%s", line);
+ count ++;
+ }
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%i TCP connections established with port %u\n",
+ count, port);
+
+ pclose (f);
+ GNUNET_free (cmdline);
+ return count;
+#endif
+}
+
+
+static struct TransportPlugin *
+find_plugin (char * name)
+{
+ struct TransportPlugin *cur = NULL;
+
+ for (cur = phead; cur != NULL; cur = cur->next)
+ {
+ if (0 == strcmp(name, cur->short_name))
+ return cur;
+ }
+ return cur;
+}
+
+static int
+stats_check_cb (void *cls, const char *subsystem,
+ const char *name, uint64_t value,
+ int is_persistent)
+{
+ static int counter;
+
+ uint64_t *val = cls;
+
+ if (NULL != val)
+ (*val) = value;
+
+ counter ++;
+ if ((STATS_VALUES == counter) || ((GNUNET_NO == have_tcp) && (STATS_VALUES - 1 == counter)))
+ {
+ int fail = GNUNET_NO;
+
+
+
+ int low_level_connections_udp = check_lowlevel_connections (2086, udp);
+
+ if (transport_connections != core_connections)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%u transport notifications <-> %u core notifications\n",
+ transport_connections, core_connections);
+ fail = GNUNET_YES;
+ }
+
+ if (transport_connections != statistics_transport_connections)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%u transport notifications <-> %u in statistics (peers connected)\n",
+ transport_connections, statistics_transport_connections);
+ fail = GNUNET_YES;
+ }
+
+ if (core_connections != statistics_core_entries_session_map)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%u core notifications <-> %u in statistics (entries session map)\n",
+ core_connections, statistics_core_entries_session_map);
+ fail = GNUNET_YES;
+ }
+
+ if (core_connections != statistics_core_neighbour_entries)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%u core notifications <-> %u in statistics (neighbour entries allocated)\n",
+ core_connections, statistics_core_neighbour_entries);
+ fail = GNUNET_YES;
+ }
+
+ if (GNUNET_NO == fail)
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Check successful : (%u transport / %u core) connections established\n", transport_connections, core_connections);
+
+ /* TCP plugin specific checks */
+ if (GNUNET_YES == have_tcp)
+ {
+ struct TransportPlugin * p = find_plugin ("tcp");
+ int low_level_connections_tcp = check_lowlevel_connections (p->port, p->protocol);
+
+ if (low_level_connections_tcp != -1)
+ {
+ if (statistics_transport_tcp_connections > low_level_connections_tcp)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%u transport tcp sessions <-> %i established tcp connections\n",
+ statistics_transport_tcp_connections, low_level_connections_tcp);
+ fail = GNUNET_YES;
+ }
+ else if (low_level_connections_tcp != -1)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "%u TCP connections, %u UDP connections \n",
+ low_level_connections_tcp, low_level_connections_udp);
+ }
+ }
+ if (transport_connections > statistics_transport_tcp_connections)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%u transport notifications <-> %u in statistics (statistics_transport_tcp_connections)\n",
+ transport_connections, statistics_transport_tcp_connections);
+ fail = GNUNET_YES;
+ }
+ else
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ " %u transport notifications <-> %u in statistics (statistics_transport_tcp_connections)\n",
+ transport_connections, statistics_transport_tcp_connections);
+ }
+ }
+
+ if (GNUNET_SCHEDULER_NO_TASK == statistics_task)
+ statistics_task = GNUNET_SCHEDULER_add_delayed(REPEATED_STATS_DELAY, &stats_check, NULL);
+
+ stat_check_running = GNUNET_NO;
+ counter = 0;
+ }
+
+ return GNUNET_OK;
+}
+
+GNUNET_NETWORK_STRUCT_BEGIN
+
+struct PING
+{
+ struct GNUNET_MessageHeader header;
+
+ uint16_t src;
+};
+
+struct PONG
+{
+ struct GNUNET_MessageHeader header;
+
+ uint16_t src;
+};
+GNUNET_NETWORK_STRUCT_END
+
+
+static size_t
+send_transport_ping_cb (void *cls, size_t size, void *buf)
+{
+ struct PeerContainer * pc = cls;
+ struct PING ping;
+ size_t mlen = sizeof (struct PING);
+
+ if (size < mlen)
+ {
+ GNUNET_break (0);
+ return 0;
+ }
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Sending transport ping to `%s'\n", GNUNET_i2s (&pc->id));
+ ping.header.size = htons (mlen);
+ ping.header.type = htons (1234);
+ ping.src = htons (0);
+
+ pc->th_ping = NULL;
+
+ memcpy (buf, &ping, mlen);
+ return mlen;
+}
+
+size_t send_core_ping_cb (void *cls, size_t size, void *buf)
+{
+struct PeerContainer * pc = cls;
+struct PING ping;
+size_t mlen = sizeof (struct PING);
+
+if (size < mlen)
+{
+ GNUNET_break (0);
+ return 0;
+}
+
+GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Sending core ping to `%s'\n", GNUNET_i2s (&pc->id));
+ping.header.size = htons (mlen);
+ping.header.type = htons (1234);
+ping.src = htons (1);
+
+pc->ch_ping = NULL;
+
+memcpy (buf, &ping, mlen);
+return mlen;
+}
+
+
+int map_ping_it (void *cls,
+ const GNUNET_HashCode * key,
+ void *value)
+{
+ struct PeerContainer *pc = value;
+
+ if (ping == GNUNET_YES)
+ {
+ if ((GNUNET_YES == pc->transport_connected) && (NULL == pc->th_ping))
+ pc->th_ping = GNUNET_TRANSPORT_notify_transmit_ready(th, &pc->id,
+ sizeof (struct PING), UINT_MAX,
+ GNUNET_TIME_UNIT_FOREVER_REL, &send_transport_ping_cb, pc);
+ else
+ GNUNET_break(0);
+
+ if ((GNUNET_YES == pc->core_connected) && (NULL == pc->ch_ping))
+ pc->ch_ping = GNUNET_CORE_notify_transmit_ready(ch,
+ GNUNET_NO, UINT_MAX,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ &pc->id,
+ sizeof (struct PING),
+ send_core_ping_cb, pc);
+ else
+ GNUNET_break (0);
+ }
+ return GNUNET_OK;
+}
+
+
+static void
+stats_check (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ statistics_task = GNUNET_SCHEDULER_NO_TASK;
+
+ if (GNUNET_YES == stat_check_running)
+ {
+ statistics_task = GNUNET_SCHEDULER_add_delayed(STATS_DELAY, &stats_check, NULL);
+ }
+
+ GNUNET_CONTAINER_multihashmap_iterate (peers, &map_ping_it, NULL);
+
+ stat_check_running = GNUNET_YES;
+
+ statistics_transport_connections = 0 ;
+ statistics_core_entries_session_map = 0;
+ statistics_core_neighbour_entries = 0;
+
+ GNUNET_STATISTICS_get (stats, "transport", "# peers connected", GNUNET_TIME_UNIT_MINUTES, NULL, &stats_check_cb, &statistics_transport_connections);
+ GNUNET_STATISTICS_get (stats, "core", "# neighbour entries allocated", GNUNET_TIME_UNIT_MINUTES, NULL, &stats_check_cb, &statistics_core_neighbour_entries);
+ GNUNET_STATISTICS_get (stats, "core", "# peers connected", GNUNET_TIME_UNIT_MINUTES, NULL, &stats_check_cb, &statistics_core_entries_session_map);
+
+ /* TCP plugin specific checks */
+ if (GNUNET_YES == have_tcp)
+ GNUNET_STATISTICS_get (stats, "transport", "# TCP sessions active", GNUNET_TIME_UNIT_MINUTES, NULL, &stats_check_cb, &statistics_transport_tcp_connections);
+}
+
+
+
+size_t send_transport_pong_cb (void *cls, size_t size, void *buf)
+{
+ struct PeerContainer * pc = cls;
+ struct PING ping;
+ size_t mlen = sizeof (struct PING);
+
+ if (size < mlen)
+ {
+ GNUNET_break (0);
+ return 0;
+ }
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Sending transport pong to `%s'\n", GNUNET_i2s (&pc->id));
+ ping.header.size = htons (mlen);
+ ping.header.type = htons (4321);
+ ping.src = htons (0);
+
+ pc->th_pong = NULL;
+
+ memcpy (buf, &ping, mlen);
+ return mlen;
+}
+
+static size_t
+send_core_pong_cb (void *cls, size_t size, void *buf)
+{
+struct PeerContainer * pc = cls;
+struct PING ping;
+size_t mlen = sizeof (struct PING);
+
+if (size < mlen)
+{
+ GNUNET_break (0);
+ return 0;
+}
+
+GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Sending core pong to `%s'\n", GNUNET_i2s (&pc->id));
+ping.header.size = htons (mlen);
+ping.header.type = htons (4321);
+ping.src = htons (1);
+
+pc->ch_pong = NULL;
+
+memcpy (buf, &ping, mlen);
+return mlen;
+}
+
+
+static void
+map_connect (const struct GNUNET_PeerIdentity *peer, void * source)
+{
+ struct PeerContainer * pc;
+ if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains(peers, &peer->hashPubKey))
+ {
+ pc = GNUNET_malloc (sizeof (struct PeerContainer));
+ pc->id = *peer;
+ pc->core_connected = GNUNET_NO;
+ pc->transport_connected = GNUNET_NO;
+ GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(peers, &peer->hashPubKey, pc, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+ }
+
+ pc = GNUNET_CONTAINER_multihashmap_get(peers, &peer->hashPubKey);
+ if (source == th)
+ {
+ if (GNUNET_NO == pc->transport_connected)
+ {
+ pc->transport_connected = GNUNET_YES;
+ if (GNUNET_YES == ping)
+ {
+ if (NULL == pc->th_ping)
+ pc->th_ping = GNUNET_TRANSPORT_notify_transmit_ready(th, peer, sizeof (struct PING), UINT_MAX, GNUNET_TIME_UNIT_FOREVER_REL, &send_transport_ping_cb, pc);
+ else
+ GNUNET_break(0);
+ }
+ }
+ else
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%s notified multiple times about for peers `%s' (%s : %s)\n",
+ "TRANSPORT",
+ GNUNET_i2s (&pc->id),
+ "CORE", (pc->core_connected == GNUNET_YES) ? "yes" : "no");
+ GNUNET_break (0);
+ }
+ }
+ if (source == ch)
+ {
+ if (GNUNET_NO == pc->core_connected)
+ {
+ pc->core_connected = GNUNET_YES;
+ if (GNUNET_YES == ping)
+ {
+ if (NULL == pc->ch_ping)
+ pc->ch_ping = GNUNET_CORE_notify_transmit_ready(ch,
+ GNUNET_NO, UINT_MAX,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ peer,
+ sizeof (struct PING),
+ send_core_ping_cb, pc);
+ else
+ GNUNET_break (0);
+ }
+ }
+ else
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%s notified multiple times about for peers `%s' (%s : %s)\n",
+ "CORE",
+ GNUNET_i2s (&pc->id),
+ "TRANSPORT", (pc->transport_connected == GNUNET_YES) ? "yes" : "no");
+ GNUNET_break (0);
+ }
+ }
+ if (GNUNET_SCHEDULER_NO_TASK != check_task)
+ GNUNET_SCHEDULER_cancel(check_task);
+ check_task = GNUNET_SCHEDULER_add_delayed(CHECK_DELAY, &map_check, NULL);
+
+ if (GNUNET_SCHEDULER_NO_TASK != statistics_task)
+ GNUNET_SCHEDULER_cancel(statistics_task);
+ statistics_task = GNUNET_SCHEDULER_add_delayed(STATS_DELAY, &stats_check, NULL);
+}
+
+
+static void
+map_disconnect (const struct GNUNET_PeerIdentity * peer, void * source)
+{
+
+ struct PeerContainer * pc;
+ if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains(peers, &peer->hashPubKey))
+ {
+ if (source == th)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%s disconnect notification for unknown peer `%s'\n",
+ "TRANSPORT", GNUNET_i2s (peer));
+ GNUNET_break (0);
+ return;
+ }
+ if (source == ch)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%s disconnect notification for unknown peer `%s'\n",
+ "CORE", GNUNET_i2s (peer));
+ return;
+ }
+ }
+
+ pc = GNUNET_CONTAINER_multihashmap_get(peers, &peer->hashPubKey);
+ if (source == th)
+ {
+ if (NULL != pc->th_ping)
+ {
+ GNUNET_TRANSPORT_notify_transmit_ready_cancel(pc->th_ping);
+ pc->th_ping = NULL;
+ }
+ if (NULL != pc->th_pong)
+ {
+ GNUNET_TRANSPORT_notify_transmit_ready_cancel(pc->th_pong);
+ pc->th_pong = NULL;
+ }
+
+ if (GNUNET_YES == pc->transport_connected)
+ {
+ pc->transport_connected = GNUNET_NO;
+ }
+ else
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%s notified for not connected peer `%s' (%s : %s)\n",
+ "TRANSPORT",
+ GNUNET_i2s (&pc->id),
+ "CORE", (pc->core_connected == GNUNET_YES) ? "yes" : "no");
+ GNUNET_break (0);
+ }
+ }
+ if (source == ch)
+ {
+ if (NULL != pc->ch_ping)
+ {
+ GNUNET_CORE_notify_transmit_ready_cancel (pc->ch_ping);
+ pc->ch_ping = NULL;
+ }
+ if (NULL != pc->ch_pong)
+ {
+ GNUNET_CORE_notify_transmit_ready_cancel (pc->ch_pong);
+ pc->ch_pong = NULL;
+ }
+
+ if (GNUNET_YES == pc->core_connected)
+ {
+ pc->core_connected = GNUNET_NO;
+ }
+ else
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%s notified for not connected peer `%s' (%s : %s)\n",
+ "CORE",
+ GNUNET_i2s (&pc->id),
+ "TRANSPORT", (pc->transport_connected == GNUNET_YES) ? "yes" : "no");
+ GNUNET_break (0);
+ }
+ }
+
+ if ((GNUNET_NO == pc->core_connected) && (GNUNET_NO == pc->transport_connected))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Removing peer `%s'\n", GNUNET_i2s (&pc->id));
+ GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_remove (peers, &peer->hashPubKey, pc));
+
+
+ GNUNET_free (pc);
+ }
+
+ if (GNUNET_SCHEDULER_NO_TASK != check_task)
+ GNUNET_SCHEDULER_cancel(check_task);
+ check_task = GNUNET_SCHEDULER_add_delayed(CHECK_DELAY, &map_check, NULL);
+
+ if (GNUNET_SCHEDULER_NO_TASK != statistics_task)
+ GNUNET_SCHEDULER_cancel(statistics_task);
+ statistics_task = GNUNET_SCHEDULER_add_delayed(STATS_DELAY, &stats_check, NULL);
+}
+
+
+static void
+cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct TransportPlugin * cur = phead;
+
+ if (NULL != th)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Disconnecting from transport service\n");
+ GNUNET_TRANSPORT_disconnect (th);
+ th = NULL;
+ }
+
+
+ if (NULL != ch)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Disconnecting from core service\n");
+ GNUNET_CORE_disconnect (ch);
+ ch = NULL;
+ }
+
+ if (GNUNET_SCHEDULER_NO_TASK != statistics_task)
+ {
+ GNUNET_SCHEDULER_cancel(statistics_task);
+ statistics_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+
+ if (GNUNET_SCHEDULER_NO_TASK != check_task)
+ {
+ GNUNET_SCHEDULER_cancel(check_task);
+ check_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+
+ for (cur = phead; cur != NULL; cur = phead)
+ {
+ GNUNET_CONTAINER_DLL_remove(phead, ptail, cur);
+ GNUNET_free (cur->short_name);
+ GNUNET_free (cur);
+ }
+
+ check_task = GNUNET_SCHEDULER_add_now (&map_check, &map_cleanup);
+}
+
+static void
+transport_notify_connect_cb (void *cls,
+ const struct GNUNET_PeerIdentity
+ * peer,
+ const struct
+ GNUNET_ATS_Information * ats,
+ uint32_t ats_count)
+{
+ transport_connections ++;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "TRANSPORT connect for peer `%s' (%u total)\n",
+ GNUNET_i2s (peer), transport_connections);
+ map_connect (peer, th);
+}
+
+/**
+ * Function called to notify transport users that another
+ * peer disconnected from us.
+ *
+ * @param cls closure
+ * @param peer the peer that disconnected
+ */
+static void
+transport_notify_disconnect_cb (void *cls,
+ const struct
+ GNUNET_PeerIdentity * peer)
+{
+ GNUNET_assert (transport_connections > 0);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "TRANSPORT disconnect for peer `%s' (%u total)\n",
+ GNUNET_i2s (peer), transport_connections) ;
+ map_disconnect (peer, th);
+ transport_connections --;
+
+}
+
+static void
+transport_notify_receive_cb (void *cls,
+ const struct
+ GNUNET_PeerIdentity * peer,
+ const struct
+ GNUNET_MessageHeader *
+ message,
+ const struct
+ GNUNET_ATS_Information * ats,
+ uint32_t ats_count)
+{
+
+
+ struct PeerContainer *pc = NULL;
+
+ pc = GNUNET_CONTAINER_multihashmap_get(peers, &peer->hashPubKey);
+
+ if (NULL == pc)
+ {
+ GNUNET_break (0);
+ return;
+ }
+
+ if ((message->size == ntohs (sizeof (struct PING))) && (message->type == ntohs (1234)))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Received %s %s from peer `%s'\n",
+ "TRANSPORT",
+ "PING",
+ GNUNET_i2s (peer)) ;
+ if (GNUNET_YES == ping)
+ {
+ if (NULL == pc->th_pong)
+ pc->th_pong = GNUNET_TRANSPORT_notify_transmit_ready(th,
+ peer, sizeof (struct PONG),
+ UINT_MAX, GNUNET_TIME_UNIT_FOREVER_REL,
+ &send_transport_pong_cb, pc);
+ else
+ GNUNET_break (0);
+ }
+
+ }
+ if ((message->size == ntohs (sizeof (struct PONG))) && (message->type == ntohs (4321)))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Received %s %s from peer `%s'\n",
+ "TRANSPORT",
+ "PONG",
+ GNUNET_i2s (peer));
+ }
+}
+
+static int
+core_notify_receive_cb (void *cls,
+ const struct GNUNET_PeerIdentity * peer,
+ const struct GNUNET_MessageHeader * message,
+ const struct GNUNET_ATS_Information* atsi,
+ unsigned int atsi_count)
+{
+ struct PeerContainer *pc = NULL;
+
+ pc = GNUNET_CONTAINER_multihashmap_get(peers, &peer->hashPubKey);
+
+ if (NULL == pc)
+ {
+ if (0 == memcmp (peer, &my_peer_id, sizeof (my_peer_id)))
+ return GNUNET_OK;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Received unexpected message type %u from unknown peer `%s'\n",
+ ntohs (message->type),
+ GNUNET_i2s (peer));
+
+ GNUNET_break (0);
+ return GNUNET_OK;
+ }
+
+ if ((message->size == ntohs (sizeof (struct PING))) && (message->type == ntohs (1234)))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Received %s %s from peer `%s'\n",
+ "CORE",
+ "PING",
+ GNUNET_i2s (peer));
+ if (GNUNET_YES == ping)
+ {
+ if (NULL == pc->ch_pong)
+ pc->ch_pong = GNUNET_CORE_notify_transmit_ready(ch,
+ GNUNET_NO, UINT_MAX,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ peer,
+ sizeof (struct PONG),
+ send_core_pong_cb, pc);
+ else
+ GNUNET_break (0);
+ }
+ }
+
+ if ((message->size == ntohs (sizeof (struct PONG))) && (message->type == ntohs (4321)))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Received %s %s from peer `%s'\n",
+ "CORE",
+ "PONG",
+ GNUNET_i2s (peer));
+
+ }
+
+ return GNUNET_OK;
+}
+
+static void
+core_connect_cb (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_ATS_Information *atsi,
+ unsigned int atsi_count)
+{
+ if (0 != memcmp (peer, &my_peer_id, sizeof (struct GNUNET_PeerIdentity)))
+ {
+ core_connections ++;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "CORE connect for peer `%s' (%u total)\n",
+ GNUNET_i2s (peer), core_connections);
+ map_connect (peer, ch);
+ }
+ else
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "CORE connect for myself `%s' (%u total)\n",
+ GNUNET_i2s (peer), core_connections);
+ }
+}
+
+static void
+core_disconnect_cb (void *cls,
+ const struct
+ GNUNET_PeerIdentity * peer)
+{
+ if (0 != memcmp (peer, &my_peer_id, sizeof (struct GNUNET_PeerIdentity)))
+ {
+ GNUNET_assert (core_connections > 0);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "CORE disconnect for peer `%s' (%u total)\n",
+ GNUNET_i2s (peer), core_connections);
+ map_disconnect (peer, ch);
+ core_connections --;
+ }
+ else
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "CORE disconnect for myself `%s' (%u total)\n",
+ GNUNET_i2s (peer), core_connections);
+ }
+
+}
+
+static void
+core_init_cb (void *cls, struct GNUNET_CORE_Handle *server,
+ const struct GNUNET_PeerIdentity *my_identity)
+{
+ my_peer_id = *my_identity;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Connected to core service\n");
+}
+
+
+static void
+init ()
+{
+ struct TransportPlugin * cur;
+ char *plugs;
+ char *pos;
+ char *secname;
+ int counter;
+ unsigned long long port;
+
+ have_tcp = GNUNET_NO;
+ have_udp = GNUNET_NO;
+ have_http = GNUNET_NO;
+ have_https = GNUNET_NO;
+ have_unix = GNUNET_NO;
+
+ if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (mycfg, "TRANSPORT", "PLUGINS", &plugs))
+ return;
+ counter = 0;
+ for (pos = strtok (plugs, " "); pos != NULL; pos = strtok (NULL, " "))
+ {
+ counter++;
+
+ GNUNET_asprintf(&secname, "transport-%s", pos);
+
+ if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (mycfg, secname, "PORT", &port))
+ {
+ GNUNET_free (secname);
+ continue;
+ }
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport plugin: `%s' port %llu\n"), pos, port);
+ cur = GNUNET_malloc(sizeof (struct TransportPlugin));
+ cur->short_name = GNUNET_strdup (pos);
+ cur->port = port;
+ if (0 == strcmp("tcp", pos))
+ {
+ have_tcp = GNUNET_YES;
+ cur->protocol = tcp;
+ }
+ if (0 == strcmp("udp", pos))
+ {
+ have_udp = GNUNET_YES;
+ cur->protocol = udp;
+ }
+ if (0 == strcmp("http", pos))
+ {
+ have_http = GNUNET_YES;
+ cur->protocol = tcp;
+ }
+ if (0 == strcmp("https", pos))
+ {
+ have_https = GNUNET_YES;
+ cur->protocol = tcp;
+ }
+ if (0 == strcmp("unix", pos))
+ {
+ have_unix = GNUNET_YES;
+ cur->protocol = unixdomain;
+ }
+
+ GNUNET_CONTAINER_DLL_insert(phead, ptail, cur);
+ GNUNET_free (secname);
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Found %u transport plugins: `%s'\n"),
+ counter, plugs);
+
+ GNUNET_free (plugs);
+}
+
+/**
+ * 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 cfg configuration
+ */
+static void
+run (void *cls, char *const *args, const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ transport_connections = 0;
+ core_connections = 0;
+ mycfg = cfg;
+
+ init();
+
+ stats = GNUNET_STATISTICS_create ("watchdog", cfg);
+ peers = GNUNET_CONTAINER_multihashmap_create (20);
+
+ th = GNUNET_TRANSPORT_connect(cfg, NULL, NULL,
+ &transport_notify_receive_cb,
+ &transport_notify_connect_cb,
+ &transport_notify_disconnect_cb);
+ GNUNET_assert (th != NULL);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Connected to transport service\n");
+ ch = GNUNET_CORE_connect (cfg, 1, NULL,
+ &core_init_cb,
+ &core_connect_cb,
+ &core_disconnect_cb,
+ &core_notify_receive_cb, GNUNET_NO,
+ NULL, GNUNET_NO,
+ NULL);
+ GNUNET_assert (ch != NULL);
+
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task, NULL);
+
+}
+
+
+/**
+ * The main function.
+ *
+ * @param argc number of arguments from the command line
+ * @param argv command line arguments
+ * @return 0 ok, 1 on error
+ */
+int
+main (int argc, char *const *argv)
+{
+ ping = GNUNET_NO;
+ static const struct GNUNET_GETOPT_CommandLineOption options[] = {
+ {'p', "ping", NULL, gettext_noop ("Send ping messages to test connectivity (default == NO)"),
+ GNUNET_NO, &GNUNET_GETOPT_set_one, &ping},
+ GNUNET_GETOPT_OPTION_END
+ };
+ return (GNUNET_OK ==
+ GNUNET_PROGRAM_run (argc, argv, "cn",
+ gettext_noop ("help text"), options, &run,
+ NULL)) ? ret : 1;
+}
+
+/* end of connection_watchdog.c */