2 This file is part of GNUnet.
3 (C) 2009 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
22 * @file src/transport/gnunet-transport.c
23 * @brief Tool to help configure, measure and control the transport subsystem.
24 * @author Christian Grothoff
25 * @author Nathan Evans
27 * This utility can be used to test if a transport mechanism for
28 * GNUnet is properly configured.
32 #include "gnunet_program_lib.h"
33 #include "gnunet_protocols.h"
34 #include "gnunet_transport_service.h"
37 * Which peer should we connect to?
42 * Handle to transport service.
44 static struct GNUNET_TRANSPORT_Handle *handle;
49 static int benchmark_send;
54 static int benchmark_receive;
59 static int benchmark_receive;
64 static int iterate_connections;
67 * Global return value (0 success).
72 * Number of bytes of traffic we received so far.
74 static unsigned long long traffic_received;
77 * Number of bytes of traffic we sent so far.
79 static unsigned long long traffic_sent;
82 * Starting time of transmitting/receiving data.
84 static struct GNUNET_TIME_Absolute start_time;
87 * Handle for current transmission request.
89 static struct GNUNET_TRANSPORT_TransmitHandle *th;
92 * Identity of the peer we transmit to / connect to.
93 * (equivalent to 'cpid' string).
95 static struct GNUNET_PeerIdentity pid;
98 * Task scheduled for cleanup / termination of the process.
100 static GNUNET_SCHEDULER_TaskIdentifier end;
103 * Selected level of verbosity.
105 static int verbosity;
110 * Shutdown, print statistics.
113 do_disconnect (void *cls,
114 const struct GNUNET_SCHEDULER_TaskContext *tc)
116 struct GNUNET_TIME_Relative duration;
120 GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
123 GNUNET_TRANSPORT_disconnect (handle);
124 if (benchmark_receive)
126 duration = GNUNET_TIME_absolute_get_duration (start_time);
128 _("Received %llu bytes/s (%llu bytes in %llu ms)\n"),
129 1000 * traffic_received / (1+duration.rel_value),
131 (unsigned long long) duration.rel_value);
135 duration = GNUNET_TIME_absolute_get_duration (start_time);
137 _("Transmitted %llu bytes/s (%llu bytes in %llu ms)\n"),
138 1000 * traffic_sent / (1+duration.rel_value),
140 (unsigned long long) duration.rel_value);
146 * Function called to notify a client about the socket
147 * begin ready to queue more data. "buf" will be
148 * NULL and "size" zero if the socket was closed for
149 * writing in the meantime.
152 * @param size number of bytes available in buf
153 * @param buf where the callee should write the message
154 * @return number of bytes written to buf
157 transmit_data (void *cls, size_t size,
160 struct GNUNET_MessageHeader *m = buf;
162 GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader));
163 GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE);
164 m->size = ntohs (size);
165 m->type = ntohs (GNUNET_MESSAGE_TYPE_DUMMY);
166 memset (&m[1], 52, size - sizeof (struct GNUNET_MessageHeader));
167 traffic_sent += size;
168 th = GNUNET_TRANSPORT_notify_transmit_ready (handle,
172 GNUNET_TIME_UNIT_FOREVER_REL,
173 &transmit_data, NULL);
176 _("Transmitting %u bytes to %s\n"),
184 * Function called to notify transport users that another
185 * peer connected to us.
188 * @param peer the peer that connected
189 * @param ats performance data
190 * @param ats_count number of entries in ats (excluding 0-termination)
193 notify_connect (void *cls,
194 const struct GNUNET_PeerIdentity
197 GNUNET_ATS_Information
198 * ats, uint32_t ats_count)
202 _("Connected to %s\n"),
204 if (0 != memcmp (&pid,
206 sizeof (struct GNUNET_PeerIdentity)))
211 start_time = GNUNET_TIME_absolute_get ();
212 th = GNUNET_TRANSPORT_notify_transmit_ready (handle,
216 GNUNET_TIME_UNIT_FOREVER_REL,
217 &transmit_data, NULL);
221 /* all done, terminate instantly */
222 GNUNET_SCHEDULER_cancel (end);
223 end = GNUNET_SCHEDULER_add_now (&do_disconnect,
230 * Function called to notify transport users that another
231 * peer disconnected from us.
234 * @param peer the peer that disconnected
237 notify_disconnect (void *cls,
239 GNUNET_PeerIdentity * peer)
243 _("Disconnected from %s\n"),
245 if ( (0 == memcmp (&pid,
247 sizeof (struct GNUNET_PeerIdentity))) &&
250 GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
252 GNUNET_SCHEDULER_cancel (end);
253 end = GNUNET_SCHEDULER_add_now (&do_disconnect,
260 * Function called by the transport for each received message.
263 * @param peer (claimed) identity of the other peer
264 * @param message the message
265 * @param ats performance data
266 * @param ats_count number of entries in ats
269 notify_receive (void *cls,
271 GNUNET_PeerIdentity * peer,
273 GNUNET_MessageHeader *
276 GNUNET_ATS_Information
277 * ats, uint32_t ats_count)
279 if (! benchmark_receive)
283 _("Received %u bytes from %s\n"),
284 (unsigned int) ntohs (message->size),
286 if (traffic_received == 0)
287 start_time = GNUNET_TIME_absolute_get ();
288 traffic_received += ntohs (message->size);
293 * Function to call with a human-readable format of an address
296 * @param address NULL on error, otherwise 0-terminated printable UTF-8 string
299 process_address (void *cls, const struct GNUNET_PeerIdentity *peer,
300 const char *transport, const void *addr, size_t addrlen)
302 if ((peer != NULL) || (transport != NULL) ||
303 ((addr != NULL) && (addrlen > 0)))
305 _("Peer `%s' plugin: `%s' address `%s'\n"),
306 (peer != NULL) ? GNUNET_i2s (peer) : "<unknown>",
307 (transport != NULL) ? transport : "<unknown>",
308 ((addr != NULL) && (addrlen > 0) && (transport != NULL)) ?
309 "how do i resolve the name without transport service?" :
315 * Main function that will be run by the scheduler.
318 * @param args remaining command-line arguments
319 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
320 * @param cfg configuration
323 run (void *cls, char *const *args, const char *cfgfile,
324 const struct GNUNET_CONFIGURATION_Handle *cfg)
326 if (benchmark_send && (NULL == cpid))
328 fprintf (stderr, _("Option `%s' makes no sense without option `%s'.\n"),
336 GNUNET_CRYPTO_hash_from_string (cpid, &pid.hashPubKey))
339 _("Failed to parse peer identity `%s'\n"),
343 handle = GNUNET_TRANSPORT_connect (cfg, NULL, NULL,
347 GNUNET_TRANSPORT_try_connect (handle, &pid);
348 end = GNUNET_SCHEDULER_add_delayed (benchmark_send
349 ? GNUNET_TIME_UNIT_FOREVER_REL
350 : GNUNET_TIME_UNIT_SECONDS,
353 } else if (benchmark_receive)
355 handle = GNUNET_TRANSPORT_connect (cfg, NULL, NULL,
359 GNUNET_TRANSPORT_try_connect (handle, &pid);
360 end = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
364 if (iterate_connections)
366 GNUNET_TRANSPORT_address_iterate (cfg, GNUNET_TIME_UNIT_MINUTES,
367 &process_address, NULL);
373 main (int argc, char *const *argv)
375 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
376 {'b', "benchmark", NULL,
377 gettext_noop ("measure how fast we are receiving data (until CTRL-C)"),
378 0, &GNUNET_GETOPT_set_one, &benchmark_receive},
379 {'C', "connect", "PEER",
380 gettext_noop ("try to connect to the given peer"),
381 1, &GNUNET_GETOPT_set_string, &cpid},
382 {'i', "information", NULL,
383 gettext_noop ("provide information about all current connections (once)"),
384 0, &GNUNET_GETOPT_set_one, &iterate_connections},
386 gettext_noop ("send data for benchmarking to the other peer (until CTRL-C)"),
387 0, &GNUNET_GETOPT_set_one, &benchmark_send},
388 GNUNET_GETOPT_OPTION_VERBOSE(&verbosity),
389 GNUNET_GETOPT_OPTION_END
392 GNUNET_PROGRAM_run (argc, argv, "gnunet-transport",
393 gettext_noop ("Direct access to transport service."),
394 options, &run, NULL)) ? ret : 1;
398 /* end of gnunet-transport.c */