/**
* @file src/transport/gnunet-transport.c
- * @brief Tool to help configure the transports.
+ * @brief Tool to help configure, measure and control the transport subsystem.
* @author Christian Grothoff
*
* This utility can be used to test if a transport mechanism for
static struct GNUNET_TRANSPORT_Handle *handle;
+static int benchmark_send;
+
+static int benchmark_receive;
+
+static int ret;
+
+static unsigned long long traffic_received;
+
+static unsigned long long traffic_sent;
+
+static struct GNUNET_TIME_Absolute start_time;
+
+static struct GNUNET_TRANSPORT_TransmitHandle *th;
+
+static struct GNUNET_PeerIdentity pid;
+
+static GNUNET_SCHEDULER_TaskIdentifier end;
+
+
+/**
+ * Shutdown, print statistics.
+ */
static void
do_disconnect (void *cls,
const struct GNUNET_SCHEDULER_TaskContext *tc)
{
- GNUNET_TRANSPORT_disconnect (handle);
+ struct GNUNET_TIME_Relative duration;
+
+ if (NULL != th)
+ {
+ GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
+ th = NULL;
+ }
+ GNUNET_TRANSPORT_disconnect (handle);
+ if (benchmark_receive)
+ {
+ duration = GNUNET_TIME_absolute_get_duration (start_time);
+ fprintf (stderr,
+ "Received %llu bytes/s\n",
+ traffic_received / (1+duration.rel_value));
+ }
+ if (benchmark_send)
+ {
+ duration = GNUNET_TIME_absolute_get_duration (start_time);
+ fprintf (stderr,
+ "Transmitted %llu bytes/s\n",
+ traffic_sent / (1+duration.rel_value));
+ }
+}
+
+
+/**
+ * Function called to notify a client about the socket
+ * begin ready to queue more data. "buf" will be
+ * NULL and "size" zero if the socket was closed for
+ * writing in the meantime.
+ *
+ * @param cls closure
+ * @param size number of bytes available in buf
+ * @param buf where the callee should write the message
+ * @return number of bytes written to buf
+ */
+static size_t
+transmit_data (void *cls, size_t size,
+ void *buf)
+{
+ struct GNUNET_MessageHeader *m = buf;
+
+ GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader));
+ GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE);
+ m->size = ntohs (size);
+ m->type = ntohs (GNUNET_MESSAGE_TYPE_DUMMY);
+ memset (&m[1], 52, size - sizeof (struct GNUNET_MessageHeader));
+ traffic_sent += size;
+ th = GNUNET_TRANSPORT_notify_transmit_ready (handle,
+ &pid,
+ 32 * 1024,
+ 0,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ &transmit_data, NULL);
+ return size;
+}
+
+
+/**
+ * Function called to notify transport users that another
+ * peer connected to us.
+ *
+ * @param cls closure
+ * @param peer the peer that connected
+ * @param ats performance data
+ * @param ats_count number of entries in ats (excluding 0-termination)
+ */
+static void
+notify_connect (void *cls,
+ const struct GNUNET_PeerIdentity
+ * peer,
+ const struct
+ GNUNET_ATS_Information
+ * ats, uint32_t ats_count)
+{
+ if (0 != memcmp (&pid,
+ peer,
+ sizeof (struct GNUNET_PeerIdentity)))
+ return;
+ ret = 0;
+ if (benchmark_send)
+ {
+ start_time = GNUNET_TIME_absolute_get ();
+ th = GNUNET_TRANSPORT_notify_transmit_ready (handle,
+ peer,
+ 32 * 1024,
+ 0,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ &transmit_data, NULL);
+ }
+ else
+ {
+ /* all done, terminate instantly */
+ GNUNET_SCHEDULER_cancel (end);
+ end = GNUNET_SCHEDULER_add_now (&do_disconnect,
+ NULL);
+ }
+}
+
+
+/**
+ * Function called to notify transport users that another
+ * peer disconnected from us.
+ *
+ * @param cls closure
+ * @param peer the peer that disconnected
+ */
+static void
+notify_disconnect (void *cls,
+ const struct
+ GNUNET_PeerIdentity * peer)
+{
+ if ( (0 == memcmp (&pid,
+ peer,
+ sizeof (struct GNUNET_PeerIdentity))) &&
+ (NULL != th) )
+ {
+ GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
+ th = NULL;
+ GNUNET_SCHEDULER_cancel (end);
+ end = GNUNET_SCHEDULER_add_now (&do_disconnect,
+ NULL);
+ }
+}
+
+
+/**
+ * Function called by the transport for each received message.
+ *
+ * @param cls closure
+ * @param peer (claimed) identity of the other peer
+ * @param message the message
+ * @param ats performance data
+ * @param ats_count number of entries in ats
+ */
+static void
+notify_receive (void *cls,
+ const struct
+ GNUNET_PeerIdentity * peer,
+ const struct
+ GNUNET_MessageHeader *
+ message,
+ const struct
+ GNUNET_ATS_Information
+ * ats, uint32_t ats_count)
+{
+ if (! benchmark_receive)
+ return;
+ if (traffic_received == 0)
+ start_time = GNUNET_TIME_absolute_get ();
+ traffic_received += ntohs (message->size);
}
run (void *cls, char *const *args, const char *cfgfile,
const struct GNUNET_CONFIGURATION_Handle *cfg)
{
- struct GNUNET_PeerIdentity pid;
+ if (benchmark_send && (NULL == cpid))
+ {
+ fprintf (stderr, _("Option `%s' makes no sense without option `%s'.\n"),
+ "-s", "-C");
+ return;
+ }
if (NULL != cpid)
{
+ ret = 1;
handle = GNUNET_TRANSPORT_connect (cfg, NULL, NULL,
- NULL, NULL, NULL);
+ ¬ify_receive,
+ ¬ify_connect,
+ ¬ify_disconnect);
if (GNUNET_OK !=
GNUNET_CRYPTO_hash_from_string (cpid, &pid.hashPubKey))
{
return;
}
GNUNET_TRANSPORT_try_connect (handle, &pid);
- GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
- &do_disconnect,
- NULL);
+ end = GNUNET_SCHEDULER_add_delayed (benchmark_send
+ ? GNUNET_TIME_UNIT_FOREVER_REL
+ : GNUNET_TIME_UNIT_SECONDS,
+ &do_disconnect,
+ NULL);
}
}
main (int argc, char *const *argv)
{
static const struct GNUNET_GETOPT_CommandLineOption options[] = {
+ {'b', "benchmark", NULL,
+ gettext_noop ("measure how fast we are receiving data (until CTRL-C)"),
+ 0, &GNUNET_GETOPT_set_one, &benchmark_receive},
{'C', "connect", "PEER",
gettext_noop ("try to connect to the given peer"),
1, &GNUNET_GETOPT_set_string, &cpid},
+ {'s', "send", NULL,
+ gettext_noop ("send data for benchmarking to the other peer (until CTRL-C)"),
+ 0, &GNUNET_GETOPT_set_one, &benchmark_send},
GNUNET_GETOPT_OPTION_END
};
return (GNUNET_OK ==
GNUNET_PROGRAM_run (argc, argv, "gnunet-transport",
gettext_noop ("Direct access to transport service."),
- options, &run, NULL)) ? 0 : 1;
+ options, &run, NULL)) ? ret : 1;
}