- changes
[oweals/gnunet.git] / src / integration-tests / connection_watchdog.c
index f707550768e1a70fa09088ee1a6dd5e970bddbf8..456782ddd2ff115a12479adcfbd5fbc86a3de292 100644 (file)
@@ -35,8 +35,8 @@
 #include "gnunet_statistics_service.h"
 
 
-#define CHECK_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
-#define STATS_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
+#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;
@@ -72,19 +79,57 @@ 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;
 };
 
 
-int map_check_it (void *cls,
-                  const GNUNET_HashCode * key,
-                  void *value)
+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 struct 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,
-     "Inconsistend peer `%s': TRANSPORT %s <-> CORE %s\n",
+     "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");
@@ -95,12 +140,33 @@ int map_check_it (void *cls,
 }
 
 
-int map_cleanup_it (void *cls,
-                  const GNUNET_HashCode * key,
-                  void *value)
+static int 
+map_cleanup_it (void *cls,
+               const struct GNUNET_HashCode * key,
+               void *value)
 {
   struct PeerContainer *pc = value;
-  GNUNET_CONTAINER_multihashmap_remove(peers, key, 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;
 }
@@ -136,13 +202,6 @@ map_check (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 static void
 stats_check (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
 
-enum protocol
-{
-  tcp,
-  udp,
-  unixdomain
-};
-
 static int
 check_lowlevel_connections (int port, int protocol)
 {
@@ -171,11 +230,11 @@ check_lowlevel_connections (int port, int protocol)
       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);
 
-  GNUNET_asprintf(&cmdline, "ss %s \\( sport = :%u or dport = :%u \\)", proto, port, port);
-
-  if (system ("ss > /dev/null 2> /dev/null"))
-    if (system ("ss > /dev/null 2> /dev/null") == 0)
+  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;
@@ -188,10 +247,10 @@ check_lowlevel_connections (int port, int protocol)
     return -1;
   }
 
+  count = 0;
   while (NULL != fgets (line, sizeof (line), f))
   {
     /* read */
-
     //printf ("%s", line);
     count ++;
   }
@@ -205,9 +264,24 @@ check_lowlevel_connections (int port, int protocol)
 #endif
 }
 
-int stats_check_cb (void *cls, const char *subsystem,
-                   const char *name, uint64_t value,
-                   int is_persistent)
+
+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;
 
@@ -217,16 +291,18 @@ int stats_check_cb (void *cls, const char *subsystem,
     (*val) = value;
 
   counter ++;
-  if (STATS_VALUES == counter)
+  if ((STATS_VALUES == counter) || ((GNUNET_NO == have_tcp) && (STATS_VALUES - 1 == counter)))
   {
     int fail = GNUNET_NO;
-    int low_level_connections_tcp = check_lowlevel_connections (2086, tcp);
+
+
+
     int low_level_connections_udp = check_lowlevel_connections (2086, udp);
 
     if (transport_connections != core_connections)
     {
       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-           "Transport connections are inconsistent:\n %u transport notifications <-> %u core notifications\n",
+           "%u transport notifications <-> %u core notifications\n",
            transport_connections, core_connections);
       fail = GNUNET_YES;
     }
@@ -234,14 +310,15 @@ int stats_check_cb (void *cls, const char *subsystem,
     if (transport_connections != statistics_transport_connections)
     {
       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-           "Transport connections are inconsistent:\n %u transport notifications <-> %u in statistics (peers connected)\n",
+           "%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,
-           "Transport connections are inconsistent:\n %u core notifications <-> %u in statistics (entries session map)\n",
+           "%u core notifications <-> %u in statistics (entries session map)\n",
            core_connections, statistics_core_entries_session_map);
       fail = GNUNET_YES;
     }
@@ -249,48 +326,50 @@ int stats_check_cb (void *cls, const char *subsystem,
     if (core_connections != statistics_core_neighbour_entries)
     {
       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-           "Transport connections are inconsistent:\n %u core notifications <-> %u in statistics (neighbour entries allocated)\n",
+           "%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,
-         "Statistics consistency check successful : (%u transport / %u core) connections established\n", transport_connections, core_connections);
+         "Check successful : (%u transport / %u core) connections established\n", transport_connections, core_connections);
 
-    /* This is only an issue when transport_connections > statistics_transport_tcp_connections */
-    if ((low_level_connections_tcp != -1) && (statistics_transport_tcp_connections > low_level_connections_tcp))
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-           "Lowlevel connections are inconsistent:\n %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)
+    /* TCP plugin specific checks */
+    if (GNUNET_YES == have_tcp)
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-           "%u TCP connections, %u UDP connections \n",
-           low_level_connections_tcp, low_level_connections_udp);
-    }
-    else
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-           "Error obtaining TCP connections\n");
-    }
-
-
-    if (transport_connections > statistics_transport_tcp_connections)
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-           "Transport connections are inconsistent: %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,
-           "Transport connections are inconsistent: %u transport notifications <-> %u in statistics (statistics_transport_tcp_connections)\n",
-           transport_connections, statistics_transport_tcp_connections);
+      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)
@@ -303,6 +382,102 @@ int stats_check_cb (void *cls, const char *subsystem,
   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 struct 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)
@@ -314,6 +489,8 @@ stats_check (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
     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 ;
@@ -321,9 +498,63 @@ stats_check (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
   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, "transport", "# TCP sessions active", GNUNET_TIME_UNIT_MINUTES, NULL, &stats_check_cb, &statistics_transport_tcp_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", "# entries in session map", GNUNET_TIME_UNIT_MINUTES, NULL, &stats_check_cb, &statistics_core_entries_session_map);
+  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;
 }
 
 
@@ -341,11 +572,20 @@ map_connect (const struct GNUNET_PeerIdentity *peer, void * source)
   }
 
   pc = GNUNET_CONTAINER_multihashmap_get(peers, &peer->hashPubKey);
+  GNUNET_assert (NULL != pc);
+
   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
     {
@@ -362,6 +602,18 @@ map_connect (const struct GNUNET_PeerIdentity *peer, void * source)
     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
     {
@@ -408,8 +660,21 @@ map_disconnect (const struct GNUNET_PeerIdentity * peer, void * source)
   }
 
   pc = GNUNET_CONTAINER_multihashmap_get(peers, &peer->hashPubKey);
+  GNUNET_assert (NULL != pc);
+
   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;
@@ -426,6 +691,17 @@ map_disconnect (const struct GNUNET_PeerIdentity * peer, void * source)
   }
   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;
@@ -445,6 +721,8 @@ map_disconnect (const struct GNUNET_PeerIdentity * peer, void * source)
   {
     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);
   }
 
@@ -461,12 +739,16 @@ map_disconnect (const struct GNUNET_PeerIdentity * peer, void * source)
 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");
@@ -485,10 +767,18 @@ cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
     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);
 }
 
-void
+static void
 transport_notify_connect_cb (void *cls,
                 const struct GNUNET_PeerIdentity
                 * peer,
@@ -509,7 +799,7 @@ transport_notify_connect_cb (void *cls,
  * @param cls closure
  * @param peer the peer that disconnected
  */
-void
+static void
 transport_notify_disconnect_cb (void *cls,
                                const struct
                                GNUNET_PeerIdentity * peer)
@@ -522,6 +812,111 @@ transport_notify_disconnect_cb (void *cls,
 
 }
 
+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,
@@ -549,7 +944,7 @@ core_disconnect_cb (void *cls,
 {
   if (0 != memcmp (peer, &my_peer_id, sizeof (struct GNUNET_PeerIdentity)))
   {
-    GNUNET_assert (core_connections >= 0);
+    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);
@@ -568,7 +963,78 @@ 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_ERROR, "Connected to core service\n");
+  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);
 }
 
 /**
@@ -587,19 +1053,22 @@ run (void *cls, char *const *args, const char *cfgfile,
   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, NULL,
+  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_ERROR, "Connected to transport service\n");
-  ch =  GNUNET_CORE_connect (cfg, 1, NULL,
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Connected to transport service\n");
+  ch =  GNUNET_CORE_connect (cfg, NULL,
                              &core_init_cb,
                              &core_connect_cb,
                              &core_disconnect_cb,
-                             NULL, GNUNET_NO,
+                             &core_notify_receive_cb, GNUNET_NO,
                              NULL, GNUNET_NO,
                              NULL);
   GNUNET_assert (ch != NULL);
@@ -619,10 +1088,16 @@ run (void *cls, char *const *args, const char *cfgfile,
 int
 main (int argc, char *const *argv)
 {
+  ping = GNUNET_NO;
   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
-    /* FIMXE: add options here */
+   {'p', "ping", NULL, gettext_noop ("Send ping messages to test connectivity (default == NO)"),
+    GNUNET_NO, &GNUNET_GETOPT_set_one, &ping},
     GNUNET_GETOPT_OPTION_END
   };
+
+  if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
+    return 2;
+
   return (GNUNET_OK ==
           GNUNET_PROGRAM_run (argc, argv, "cn",
                               gettext_noop ("help text"), options, &run,