- use small mesh hashes for info api
[oweals/gnunet.git] / src / mesh / gnunet-mesh.c
index 314039bfd231cad26a3f6b722d7332c102a36a52..7677b244f85e853b57e030e608a30a52625a51ce 100644 (file)
@@ -26,6 +26,7 @@
 #include "platform.h"
 #include "gnunet_util_lib.h"
 #include "gnunet_mesh_service.h"
+#include "mesh.h"
 
 
 /**
 static int monitor_connections;
 
 /**
- * Option -i.
+ * Option -P.
  */
-static int get_info;
+static int request_peers;
+
+/**
+ * Option -T.
+ */
+static int request_tunnels;
 
 /**
  * Option --tunnel
@@ -58,6 +64,21 @@ static char *channel_id;
  */
 static uint32_t listen_port;
 
+/**
+ * Request echo service
+ */
+int echo;
+
+/**
+ * Time of last echo request.
+ */
+struct GNUNET_TIME_Absolute echo_time;
+
+/**
+ * Task for next echo request.
+ */
+GNUNET_SCHEDULER_TaskIdentifier echo_task;
+
 /**
  * Peer to connect to.
  */
@@ -107,6 +128,7 @@ static void
 shutdown_task (void *cls,
                const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown\n");
   if (NULL != ch)
   {
     GNUNET_MESH_channel_destroy (ch);
@@ -153,7 +175,14 @@ data_ready (void *cls, size_t size, void *buf)
   msg->size = htons (total_size);
   msg->type = htons (GNUNET_MESSAGE_TYPE_MESH_CLI);
   memcpy (&msg[1], cls, data_size);
-  listen_stdio ();
+  if (GNUNET_NO == echo)
+  {
+    listen_stdio ();
+  }
+  else
+  {
+    echo_time = GNUNET_TIME_absolute_get ();
+  }
 
   return total_size;
 }
@@ -170,7 +199,7 @@ static void
 read_stdio (void *cls,
             const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
-  char buf[60000];
+  static char buf[60000];
 
   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
   {
@@ -179,12 +208,6 @@ read_stdio (void *cls,
 
   data_size = read (0, buf, 60000);
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "stdio read %u bytes\n", data_size);
-  {
-    struct GNUNET_HashCode hash;
-    GNUNET_CRYPTO_hash (buf, data_size, &hash);
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "  hash SEND %s (%u)\n",
-                GNUNET_h2s_full (&hash), data_size);
-  }
   if (data_size < 1)
   {
     GNUNET_SCHEDULER_shutdown();
@@ -277,10 +300,30 @@ channel_incoming (void *cls,
     return NULL;
   }
   ch = channel;
-  listen_stdio ();
+  if (GNUNET_NO == echo)
+  {
+    listen_stdio ();
+    return NULL;
+  }
+  data_size = 0;
   return NULL;
 }
 
+/**
+ * @brief Send an echo request to the remote peer.
+ *
+ * @param cls Closure (NULL).
+ * @param tc Task context.
+ */
+static void
+send_echo (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  GNUNET_MESH_notify_transmit_ready (ch, GNUNET_NO,
+                                     GNUNET_TIME_UNIT_FOREVER_REL,
+                                     sizeof (struct GNUNET_MessageHeader),
+                                     &data_ready, NULL);
+}
+
 
 
 /**
@@ -311,7 +354,10 @@ create_channel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting to `%s'\n", target_id);
   opt = GNUNET_MESH_OPTION_DEFAULT | GNUNET_MESH_OPTION_RELIABLE;
   ch = GNUNET_MESH_channel_create (mh, NULL, &pid, target_port, opt);
-  listen_stdio ();
+  if (GNUNET_NO == echo)
+    listen_stdio ();
+  else
+    GNUNET_SCHEDULER_add_now (send_echo, NULL);
 }
 
 
@@ -336,81 +382,194 @@ data_callback (void *cls,
                const struct GNUNET_MessageHeader *message)
 {
   uint16_t len;
+  ssize_t done;
+  uint16_t off;
+  const char *buf;
   GNUNET_break (ch == channel);
 
+  if (GNUNET_YES == echo)
+  {
+    if (0 != listen_port)
+    {
+      /* Just listening to echo incoming messages*/
+      GNUNET_MESH_notify_transmit_ready (channel, GNUNET_NO,
+                                        GNUNET_TIME_UNIT_FOREVER_REL,
+                                        sizeof (struct GNUNET_MessageHeader),
+                                        &data_ready, NULL);
+      return GNUNET_OK;
+    }
+    else
+    {
+      struct GNUNET_TIME_Relative latency;
+
+      latency = GNUNET_TIME_absolute_get_duration (echo_time);
+      echo_time = GNUNET_TIME_UNIT_FOREVER_ABS;
+      FPRINTF (stdout, "time: %s\n",
+               GNUNET_STRINGS_relative_time_to_string (latency, GNUNET_NO));
+      echo_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
+                                                &send_echo, NULL);
+    }
+  }
+
   len = ntohs (message->size) - sizeof (*message);
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got %u bytes\n", len);
-  GNUNET_BIO_write (1, (char *) &message[1], len);
+  buf = (const char *) &message[1];
+  off = 0;
+  while (off < len)
   {
-    struct GNUNET_HashCode hash;
-
-    GNUNET_CRYPTO_hash (message, ntohs (message->size), &hash);
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "  api hash RECV %s (%u)\n",
-                GNUNET_h2s_full (&hash), ntohs (message->size));
-    GNUNET_CRYPTO_hash (&message[1], len, &hash);
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "  hash RECV %s (%u)\n",
-                GNUNET_h2s_full (&hash), len);
+    done = write (1, &buf[off], len - off);
+    if (done <= 0)
+    {
+      if (-1 == done)
+        GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
+                             "write");
+      return GNUNET_SYSERR;
+    }
+    off += done;
   }
   return GNUNET_OK;
 }
 
 
 /**
- * Method called to retrieve information about each tunnel the mesh peer
- * is aware of.
+ * Method called to retrieve information about all peers in MESH, called
+ * once per peer.
+ *
+ * After last peer has been reported, an additional call with NULL is done.
  *
  * @param cls Closure.
- * @param tunnel_number Tunnel number.
- * @param origin that started the tunnel (owner).
- * @param target other endpoint of the tunnel
+ * @param peer Peer, or NULL on "EOF".
+ * @param tunnel Do we have a tunnel towards this peer?
+ * @param n_paths Number of known paths towards this peer.
+ * @param best_path How long is the best path?
+ *                  (0 = unknown, 1 = ourselves, 2 = neighbor)
  */
-void /* FIXME static */
-tunnels_callback (void *cls,
-                  uint32_t tunnel_number,
-                  const struct GNUNET_PeerIdentity *origin,
-                  const struct GNUNET_PeerIdentity *target)
+static void
+peers_callback (void *cls, const struct GNUNET_PeerIdentity *peer,
+                int tunnel, unsigned int n_paths, unsigned int best_path)
 {
-  FPRINTF (stdout, "Tunnel %s [%u]\n",
-           GNUNET_i2s_full (origin), tunnel_number);
-  FPRINTF (stdout, "\n");
+  if (NULL == peer)
+  {
+    if (GNUNET_YES != monitor_connections)
+    {
+      GNUNET_SCHEDULER_shutdown();
+    }
+    return;
+  }
+  FPRINTF (stdout, "%s tunnel: %c, paths: %u\n",
+           GNUNET_i2s_full (peer), tunnel ? 'Y' : 'N', n_paths);
 }
 
 
 /**
- * Method called to retrieve information about each tunnel the mesh peer
- * is aware of.
+ * Method called to retrieve information about all tunnels in MESH.
  *
  * @param cls Closure.
- * @param peer Peer in the tunnel's tree.
- * @param parent Parent of the current peer. All 0 when peer is root.
+ * @param peer Destination peer.
+ * @param channels Number of channels.
+ * @param connections Number of connections.
+ * @param estate Encryption state.
+ * @param cstate Connectivity state.
+ */
+void
+tunnels_callback (void *cls,
+                  const struct GNUNET_PeerIdentity *peer,
+                  unsigned int channels,
+                  unsigned int connections,
+                  uint16_t estate,
+                  uint16_t cstate)
+{
+  if (NULL == peer)
+  {
+    if (GNUNET_YES != monitor_connections)
+    {
+      GNUNET_SCHEDULER_shutdown();
+    }
+    return;
+  }
+  FPRINTF (stdout, "%s [ENC: %u, CON: %u] CHs: %u, CONNs: %u\n",
+           GNUNET_i2s_full (peer), estate, cstate, channels, connections);
+}
+
+
+/**
+ * Method called to retrieve information about a specific tunnel the mesh peer
+ * has established, o`r is trying to establish.
  *
+ * @param cls Closure.
+ * @param peer Peer towards whom the tunnel is directed.
+ * @param n_channels Number of channels.
+ * @param n_connections Number of connections.
+ * @param channels Channels.
+ * @param connections Connections.
+ * @param estate Encryption status.
+ * @param cstate Connectivity status.
  */
-void /* FIXME static */
+void
 tunnel_callback (void *cls,
                  const struct GNUNET_PeerIdentity *peer,
-                 const struct GNUNET_PeerIdentity *parent)
+                 unsigned int n_channels,
+                 unsigned int n_connections,
+                 uint32_t *channels,
+                 struct GNUNET_MeshHash *connections,
+                 unsigned int estate,
+                 unsigned int cstate)
 {
+  unsigned int i;
+
+  if (NULL != peer)
+  {
+    FPRINTF (stdout, "Tunnel %s\n", GNUNET_i2s_full (peer));
+    FPRINTF (stdout, "- %u channels\n", n_channels);
+    for (i = 0; i < n_channels; i++)
+      FPRINTF (stdout, "   %u\n", channels[i]);
+    FPRINTF (stdout, "- %u connections\n", n_connections);
+    for (i = 0; i < n_connections; i++)
+      FPRINTF (stdout, "   %s\n", GM_h2s (&connections[i]));
+    FPRINTF (stdout, "- enc state: %u\n", estate);
+    FPRINTF (stdout, "- con state: %u\n", cstate);
+  }
+  if (GNUNET_YES != monitor_connections)
+  {
+    GNUNET_SCHEDULER_shutdown();
+  }
+  return;
+
 }
 
 
 /**
- * Call MESH's monitor API, get all tunnels known to peer.
+ * Call MESH's meta API, get all peers known to a peer.
  *
  * @param cls Closure (unused).
  * @param tc TaskContext
  */
 static void
-get_tunnels (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+get_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
   {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown\n");
     return;
   }
-//   GNUNET_MESH_get_tunnels (mh, &tunnels_callback, NULL);
-  if (GNUNET_YES != monitor_connections)
+  GNUNET_MESH_get_peers (mh, &peers_callback, NULL);
+}
+
+/**
+ * Call MESH's meta API, get all tunnels known to a peer.
+ *
+ * @param cls Closure (unused).
+ * @param tc TaskContext
+ */
+static void
+get_tunnels (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
   {
-    GNUNET_SCHEDULER_shutdown();
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown\n");
+    return;
   }
+  GNUNET_MESH_get_tunnels (mh, &tunnels_callback, NULL);
 }
 
 
@@ -436,7 +595,7 @@ show_tunnel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
     GNUNET_SCHEDULER_shutdown();
     return;
   }
-//   GNUNET_MESH_show_tunnel (mh, &pid, 0, tunnel_callback, NULL);
+  GNUNET_MESH_get_tunnel (mh, &pid, tunnel_callback, NULL);
 }
 
 
@@ -489,14 +648,16 @@ run (void *cls, char *const *args, const char *cfgfile,
 
   target_id = args[0];
   target_port = args[0] && args[1] ? atoi(args[1]) : 0;
-  if ( (0 != get_info
+  if ( (0 != (request_peers | request_tunnels)
         || 0 != monitor_connections
         || NULL != tunnel_id
         || NULL != conn_id
         || NULL != channel_id)
        && target_id != NULL)
   {
-    FPRINTF (stderr, _("You must NOT give a TARGET when using options\n"));
+    FPRINTF (stderr,
+             _("You must NOT give a TARGET"
+               "when using 'request all' options\n"));
     return;
   }
 
@@ -531,7 +692,12 @@ run (void *cls, char *const *args, const char *cfgfile,
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show connection\n");
     GNUNET_SCHEDULER_add_now (&show_connection, NULL);
   }
-  else if (GNUNET_YES == get_info)
+  else if (GNUNET_YES == request_peers)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show all peers\n");
+    GNUNET_SCHEDULER_add_now (&get_peers, NULL);
+  }
+  else if (GNUNET_YES == request_tunnels)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show all tunnels\n");
     GNUNET_SCHEDULER_add_now (&get_tunnels, NULL);
@@ -572,27 +738,36 @@ main (int argc, char *const *argv)
   int res;
   const char helpstr[] = "Create channels and retreive info about meshs status.";
   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
-    {'a', "channel", "TUNNEL_ID:CHANNEL_ID",
-     gettext_noop ("provide information about a particular channel"),
-     GNUNET_YES, &GNUNET_GETOPT_set_string, &channel_id},
-    {'b', "connection", "TUNNEL_ID:CONNECTION_ID",
+//     {'a', "channel", "TUNNEL_ID:CHANNEL_ID",
+//      gettext_noop ("provide information about a particular channel"),
+//      GNUNET_YES, &GNUNET_GETOPT_set_string, &channel_id},
+    {'C', "connection", "CONNECTION_ID",
      gettext_noop ("provide information about a particular connection"),
      GNUNET_YES, &GNUNET_GETOPT_set_string, &conn_id},
-    {'i', "info", NULL,
-     gettext_noop ("provide information about all tunnels"),
-     GNUNET_NO, &GNUNET_GETOPT_set_one, &get_info},
-    {'m', "monitor", NULL,
-     gettext_noop ("provide information about all tunnels (continuously) NOT IMPLEMENTED"), /* FIXME */
-     GNUNET_NO, &GNUNET_GETOPT_set_one, &monitor_connections},
+    {'e', "echo", NULL,
+     gettext_noop ("activate echo mode"),
+     GNUNET_NO, &GNUNET_GETOPT_set_one, &echo},
+//     {'m', "monitor", NULL,
+//      gettext_noop ("provide information about all tunnels (continuously) NOT IMPLEMENTED"), /* FIXME */
+//      GNUNET_NO, &GNUNET_GETOPT_set_one, &monitor_connections},
     {'p', "port", NULL,
      gettext_noop ("port to listen to (default; 0)"),
      GNUNET_YES, &GNUNET_GETOPT_set_uint, &listen_port},
+    {'P', "peers", NULL,
+    gettext_noop ("provide information about all peers"),
+    GNUNET_NO, &GNUNET_GETOPT_set_one, &request_peers},
     {'t', "tunnel", "TUNNEL_ID",
      gettext_noop ("provide information about a particular tunnel"),
      GNUNET_YES, &GNUNET_GETOPT_set_string, &tunnel_id},
+    {'T', "tunnels", NULL,
+     gettext_noop ("provide information about all tunnels"),
+     GNUNET_NO, &GNUNET_GETOPT_set_one, &request_tunnels},
+
     GNUNET_GETOPT_OPTION_END
   };
 
+  monitor_connections = GNUNET_NO;
+
   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
     return 2;