aboutsummaryrefslogtreecommitdiff
path: root/src/peerinfo-tool
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2012-03-05 19:56:16 +0000
committerChristian Grothoff <christian@grothoff.org>2012-03-05 19:56:16 +0000
commitb1780f05127f1c84c442f12fe84ae8e712032164 (patch)
tree58ecfc3fc8b92b3b5705b885260fcf456d6fe7d5 /src/peerinfo-tool
parentdffa6f386418b19956f23f13f3f2a32cd803bca4 (diff)
downloadgnunet-b1780f05127f1c84c442f12fe84ae8e712032164.tar.gz
gnunet-b1780f05127f1c84c442f12fe84ae8e712032164.zip
-LRN: experimental HELLO URIs
Diffstat (limited to 'src/peerinfo-tool')
-rw-r--r--src/peerinfo-tool/Makefile.am5
-rw-r--r--src/peerinfo-tool/gnunet-peerinfo.c386
2 files changed, 389 insertions, 2 deletions
diff --git a/src/peerinfo-tool/Makefile.am b/src/peerinfo-tool/Makefile.am
index 8c5fd8fbb..7270bfb51 100644
--- a/src/peerinfo-tool/Makefile.am
+++ b/src/peerinfo-tool/Makefile.am
@@ -13,11 +13,14 @@ bin_PROGRAMS = \
13 gnunet-peerinfo 13 gnunet-peerinfo
14 14
15gnunet_peerinfo_SOURCES = \ 15gnunet_peerinfo_SOURCES = \
16 gnunet-peerinfo.c 16 gnunet-peerinfo.c \
17 ../transport/gnunet-service-transport_plugins.c
18
17gnunet_peerinfo_LDADD = \ 19gnunet_peerinfo_LDADD = \
18 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ 20 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
19 $(top_builddir)/src/transport/libgnunettransport.la \ 21 $(top_builddir)/src/transport/libgnunettransport.la \
20 $(top_builddir)/src/hello/libgnunethello.la \ 22 $(top_builddir)/src/hello/libgnunethello.la \
23 $(top_builddir)/src/statistics/libgnunetstatistics.la \
21 $(top_builddir)/src/util/libgnunetutil.la 24 $(top_builddir)/src/util/libgnunetutil.la
22 25
23if HAVE_PYTHON_PEXPECT 26if HAVE_PYTHON_PEXPECT
diff --git a/src/peerinfo-tool/gnunet-peerinfo.c b/src/peerinfo-tool/gnunet-peerinfo.c
index 21c996661..1e93a5ee8 100644
--- a/src/peerinfo-tool/gnunet-peerinfo.c
+++ b/src/peerinfo-tool/gnunet-peerinfo.c
@@ -30,6 +30,8 @@
30#include "gnunet_peerinfo_service.h" 30#include "gnunet_peerinfo_service.h"
31#include "gnunet_transport_service.h" 31#include "gnunet_transport_service.h"
32#include "gnunet_program_lib.h" 32#include "gnunet_program_lib.h"
33#include "gnunet_transport_plugin.h"
34#include "../transport/gnunet-service-transport_plugins.h"
33 35
34static int no_resolve; 36static int no_resolve;
35 37
@@ -37,8 +39,29 @@ static int be_quiet;
37 39
38static int get_self; 40static int get_self;
39 41
42static int get_uri;
43
44static char *put_uri;
45
40static struct GNUNET_PEERINFO_Handle *peerinfo; 46static struct GNUNET_PEERINFO_Handle *peerinfo;
41 47
48/**
49 * Configuration handle.
50 */
51const struct GNUNET_CONFIGURATION_Handle *GST_cfg;
52
53/**
54 * Statistics handle.
55 */
56struct GNUNET_STATISTICS_Handle *GST_stats;
57
58/**
59 * Configuration handle.
60 */
61struct GNUNET_PeerIdentity GST_my_identity;
62
63struct GNUNET_MessageHeader *our_hello = NULL;
64
42static const struct GNUNET_CONFIGURATION_Handle *cfg; 65static const struct GNUNET_CONFIGURATION_Handle *cfg;
43 66
44struct PrintContext 67struct PrintContext
@@ -47,8 +70,20 @@ struct PrintContext
47 char **address_list; 70 char **address_list;
48 unsigned int num_addresses; 71 unsigned int num_addresses;
49 uint32_t off; 72 uint32_t off;
73 char *uri;
74 size_t uri_len;
50}; 75};
51 76
77/**
78 * Obtain this peers HELLO message.
79 *
80 * @return our HELLO message
81 */
82const struct GNUNET_MessageHeader *
83GST_hello_get ()
84{
85 return (struct GNUNET_MessageHeader *) our_hello;
86}
52 87
53static void 88static void
54dump_pc (struct PrintContext *pc) 89dump_pc (struct PrintContext *pc)
@@ -150,6 +185,8 @@ print_peer_info (void *cls, const struct GNUNET_PeerIdentity *peer,
150 if (err_msg != NULL) 185 if (err_msg != NULL)
151 FPRINTF (stderr, "%s", _("Error in communication with PEERINFO service\n")); 186 FPRINTF (stderr, "%s", _("Error in communication with PEERINFO service\n"));
152 GNUNET_PEERINFO_disconnect (peerinfo); 187 GNUNET_PEERINFO_disconnect (peerinfo);
188 GST_plugins_unload ();
189 GNUNET_STATISTICS_destroy (GST_stats, GNUNET_NO);
153 return; 190 return;
154 } 191 }
155 if ((be_quiet) || (NULL == hello)) 192 if ((be_quiet) || (NULL == hello))
@@ -169,6 +206,310 @@ print_peer_info (void *cls, const struct GNUNET_PeerIdentity *peer,
169 GNUNET_HELLO_iterate_addresses (hello, GNUNET_NO, &print_address, pc); 206 GNUNET_HELLO_iterate_addresses (hello, GNUNET_NO, &print_address, pc);
170} 207}
171 208
209static int
210compose_uri (void *cls, const struct GNUNET_HELLO_Address *address,
211 struct GNUNET_TIME_Absolute expiration)
212{
213 struct PrintContext *pc = cls;
214 struct GNUNET_TRANSPORT_PluginFunctions *papi;
215 static const char *addr;
216
217 papi = GST_plugins_find (address->transport_name);
218 if (papi == NULL)
219 {
220 /* Not an error - we might just not have the right plugin. */
221 return GNUNET_OK;
222 }
223
224 addr = papi->address_to_string (papi->cls, address->address, address->address_length);
225 if (addr != NULL)
226 {
227 ssize_t l = strlen (addr);
228 if (l > 0)
229 {
230 struct tm *t;
231 time_t seconds;
232 int s;
233 seconds = expiration.abs_value / 1000;
234 t = gmtime(&seconds);
235 pc->uri = GNUNET_realloc (pc->uri, pc->uri_len + 1 + 14 + 1 + strlen (address->transport_name) + 1 + l + 1 /* 0 */);
236 s = sprintf (&pc->uri[pc->uri_len], "!%04u%02u%02u%02u%02u%02u!%s!%s",
237 t->tm_year, t->tm_mon, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec,
238 address->transport_name, addr);
239 if (s > 0)
240 pc->uri_len += s;
241 }
242 }
243 return GNUNET_OK;
244}
245
246/**
247 * Print information about the peer.
248 */
249static void
250print_my_uri (void *cls, const struct GNUNET_PeerIdentity *peer,
251 const struct GNUNET_HELLO_Message *hello, const char *err_msg)
252{
253 struct GNUNET_CRYPTO_HashAsciiEncoded enc;
254 struct PrintContext *pc = cls;
255 char *pkey;
256
257 if (peer == NULL)
258 {
259 if (err_msg != NULL)
260 FPRINTF (stderr, "%s", _("Error in communication with PEERINFO service\n"));
261 GNUNET_PEERINFO_disconnect (peerinfo);
262 GST_plugins_unload ();
263 GNUNET_STATISTICS_destroy (GST_stats, GNUNET_NO);
264 return;
265 }
266 if ((be_quiet) || (NULL == hello))
267 {
268 GNUNET_CRYPTO_hash_to_enc (&peer->hashPubKey, &enc);
269 printf ("%s\n", (const char *) &enc);
270 if (be_quiet && get_uri != GNUNET_YES)
271 return;
272 }
273 pc->peer = *peer;
274 GNUNET_HELLO_iterate_addresses (hello, GNUNET_NO, &count_address, pc);
275 GNUNET_HELLO_iterate_addresses (hello, GNUNET_NO, &compose_uri, pc);
276 printf ("%s\n", pc->uri);
277 GNUNET_free (pc->uri);
278 GNUNET_free (pc);
279}
280
281struct GNUNET_PEERINFO_HelloAddressParsingContext
282{
283 char *tmp;
284 char *pos;
285 size_t tmp_len;
286};
287
288static size_t
289add_addr_to_hello (void *cls, size_t max, void *buffer)
290{
291 struct tm expiration_time;
292 char buf[5];
293 long l;
294 time_t expiration_seconds;
295 struct GNUNET_TIME_Absolute expire;
296
297 struct GNUNET_PEERINFO_HelloAddressParsingContext *ctx = cls;
298 char *exp1, *exp2;
299 struct GNUNET_TRANSPORT_PluginFunctions *papi;
300 void *addr;
301 size_t addr_len;
302
303 /* End of string */
304 if (ctx->pos - ctx->tmp == ctx->tmp_len)
305 return 0;
306
307 /* Parsed past the end of string, OR wrong format */
308 if ((ctx->pos - ctx->tmp > ctx->tmp_len) || ctx->pos[0] != '!')
309 {
310 GNUNET_break (0);
311 return 0;
312 }
313
314 /* Not enough bytes (3 for three '!', 14 for expiration date, and
315 * at least 1 for type and 1 for address (1-byte long address is a joke,
316 * but it is not completely unrealistic. Zero-length address is.
317 */
318 if (ctx->tmp_len - (ctx->pos - ctx->tmp) < 1 /*!*/ * 3 + 14 + /* at least */ 2)
319 {
320 GNUNET_break (0);
321 return 0;
322 }
323 /* Go past the first '!', now we're on expiration date */
324 ctx->pos += 1;
325 /* Its length is known, so check for the next '!' right away */
326 if (ctx->pos[14] != '!')
327 {
328 GNUNET_break (0);
329 return 0;
330 }
331
332 memset (&expiration_time, 0, sizeof (struct tm));
333
334 /* This is FAR more strict than strptime(ctx->pos, "%Y%m%d%H%M%S", ...); */
335 /* FIXME: make it a separate function, since expiration is specified to every address */
336#define GETNDIGITS(n,cond) \
337 strncpy (buf, &ctx->pos[0], n); \
338 buf[n] = '\0'; \
339 errno = 0; \
340 l = strtol (buf, NULL, 10); \
341 if (errno != 0 || cond) \
342 { \
343 GNUNET_break (0); \
344 return 0; \
345 } \
346 ctx->pos += n;
347
348 GETNDIGITS (4, l < 1900)
349 expiration_time.tm_year = l - 1900;
350
351 GETNDIGITS (2, l < 1 || l > 12)
352 expiration_time.tm_mon = l;
353
354 GETNDIGITS (2, l < 1 || l > 31)
355 expiration_time.tm_mday = l;
356
357 GETNDIGITS (2, l < 0 || l > 23)
358 expiration_time.tm_hour = l;
359
360 GETNDIGITS (2, l < 0 || l > 59)
361 expiration_time.tm_min = l;
362
363 /* 60 - with a leap second */
364 GETNDIGITS (2, l < 0 || l > 60)
365 expiration_time.tm_sec = l;
366
367 expiration_time.tm_isdst = -1;
368
369#undef GETNDIGITS
370
371 expiration_seconds = mktime (&expiration_time);
372 if (expiration_seconds == (time_t) -1)
373 {
374 GNUNET_break (0);
375 return 0;
376 }
377 expire.abs_value = expiration_seconds * 1000;
378
379 /* Now we're at '!', advance to the transport type */
380 ctx->pos += 1;
381
382 /* Find the next '!' that separates transport type from
383 * the address
384 */
385 exp1 = strstr (ctx->pos, "!");
386 if (exp1 == NULL)
387 {
388 GNUNET_break (0);
389 return 0;
390 }
391 /* We need it 0-terminated */
392 exp1[0] = '\0';
393 /* Find the '!' that separates address from the next record.
394 * It might not be there, if this is the last record.
395 */
396 exp2 = strstr (&exp1[1], "!");
397 if (exp2 == NULL)
398 exp2 = &ctx->tmp[ctx->tmp_len];
399
400 papi = GST_plugins_find (ctx->pos);
401 if (papi == NULL)
402 {
403 /* Not an error - we might just not have the right plugin.
404 * Skip this part, advance to the next one and recurse.
405 * But only if this is not the end of string.
406 */
407 ctx->pos = exp2 + 1;
408 if (ctx->pos - ctx->tmp >= ctx->tmp_len)
409 return 0;
410 return add_addr_to_hello (cls, max, buffer);
411 }
412
413 if (GNUNET_OK == papi->string_to_address (papi->cls, &exp1[1], exp2 - &exp1[1], &addr, &addr_len))
414 {
415 struct GNUNET_HELLO_Address address;
416 int ret;
417
418 /* address.peer is unset - not used by add_address() */
419 address.address_length = addr_len;
420 address.address = addr;
421 address.transport_name = ctx->pos;
422 ret = GNUNET_HELLO_add_address (&address, expire, buffer, max);
423 GNUNET_free (addr);
424 ctx->pos = exp2;
425 return ret;
426 }
427 return 0;
428}
429
430void
431parse_hello (const struct GNUNET_CONFIGURATION_Handle *c,
432 const char *put_uri)
433{
434 int r;
435 char *scheme_part = NULL;
436 char *path_part = NULL;
437 char *exc;
438 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pub;
439 int std_result;
440 struct GNUNET_HELLO_Message *hello;
441 struct GNUNET_PEERINFO_HelloAddressParsingContext ctx;
442
443 r = GNUNET_STRINGS_parse_uri (put_uri, &scheme_part, (const char **) &path_part);
444 if (r == GNUNET_NO)
445 return;
446 if (scheme_part == NULL || strcmp (scheme_part, "gnunet://") != 0)
447 {
448 GNUNET_free_non_null (scheme_part);
449 return;
450 }
451 GNUNET_free (scheme_part);
452
453 if (strncmp (path_part, "hello/", 6) != 0)
454 return;
455
456 path_part = &path_part[6];
457 ctx.tmp = GNUNET_strdup (path_part);
458 ctx.tmp_len = strlen (path_part);
459 exc = strstr (ctx.tmp, "!");
460 if (exc == NULL)
461 exc = ctx.pos + ctx.tmp_len;
462 ctx.pos = exc;
463
464 std_result = GNUNET_STRINGS_string_to_data (ctx.tmp, exc - ctx.tmp,
465 (unsigned char *) &pub, sizeof (pub));
466 if (std_result != GNUNET_OK)
467 {
468 GNUNET_free (ctx.tmp);
469 return;
470 }
471
472 hello = GNUNET_HELLO_create (&pub, add_addr_to_hello, &ctx);
473 GNUNET_free (ctx.tmp);
474
475 /* WARNING: this adds the address from URI WITHOUT verification! */
476 GNUNET_PEERINFO_add_peer (peerinfo, hello);
477}
478
479static struct GNUNET_TIME_Relative
480receive_stub (void *cls, const struct GNUNET_PeerIdentity *peer,
481 const struct GNUNET_MessageHeader *message,
482 const struct GNUNET_ATS_Information *ats, uint32_t ats_count,
483 struct Session *session, const char *sender_address,
484 uint16_t sender_address_len)
485{
486 struct GNUNET_TIME_Relative t;
487 t.rel_value = 0;
488 return t;
489}
490
491static void
492address_notification_stub (void *cls, int add_remove,
493 const void *addr, size_t addrlen)
494{
495}
496
497static void
498session_end_stub (void *cls, const struct GNUNET_PeerIdentity *peer,
499 struct Session * session)
500{
501}
502
503static const struct GNUNET_ATS_Information
504address_to_type_stub (void *cls, const struct sockaddr *addr,
505 size_t addrlen)
506{
507 struct GNUNET_ATS_Information t;
508 t.type = 0;
509 t.value = 0;
510 return t;
511}
512
172 513
173/** 514/**
174 * Main function that will be run by the scheduler. 515 * Main function that will be run by the scheduler.
@@ -194,7 +535,12 @@ run (void *cls, char *const *args, const char *cfgfile,
194 FPRINTF (stderr, _("Invalid command line argument `%s'\n"), args[0]); 535 FPRINTF (stderr, _("Invalid command line argument `%s'\n"), args[0]);
195 return; 536 return;
196 } 537 }
197 if (get_self != GNUNET_YES) 538 if (put_uri != NULL && get_uri == GNUNET_YES)
539 {
540 FPRINTF (stderr, "%s", _("--put-uri and --get-uri are mutually exclusive\n"));
541 return;
542 }
543 if (put_uri != NULL || get_uri == GNUNET_YES)
198 { 544 {
199 peerinfo = GNUNET_PEERINFO_connect (cfg); 545 peerinfo = GNUNET_PEERINFO_connect (cfg);
200 if (peerinfo == NULL) 546 if (peerinfo == NULL)
@@ -202,6 +548,21 @@ run (void *cls, char *const *args, const char *cfgfile,
202 FPRINTF (stderr, "%s", _("Could not access PEERINFO service. Exiting.\n")); 548 FPRINTF (stderr, "%s", _("Could not access PEERINFO service. Exiting.\n"));
203 return; 549 return;
204 } 550 }
551 GST_cfg = c;
552 GST_stats = GNUNET_STATISTICS_create ("transport", c);
553 /* FIXME: shouldn't we free GST_stats somewhere? */
554 GST_plugins_load (receive_stub, address_notification_stub,
555 session_end_stub, address_to_type_stub);
556 }
557 if (put_uri != NULL)
558 {
559 parse_hello (c, put_uri);
560 GST_plugins_unload ();
561 GNUNET_STATISTICS_destroy (GST_stats, GNUNET_NO);
562 return;
563 }
564 if (get_self != GNUNET_YES)
565 {
205 GNUNET_PEERINFO_iterate (peerinfo, NULL, 566 GNUNET_PEERINFO_iterate (peerinfo, NULL,
206 GNUNET_TIME_relative_multiply 567 GNUNET_TIME_relative_multiply
207 (GNUNET_TIME_UNIT_SECONDS, 5), &print_peer_info, 568 (GNUNET_TIME_UNIT_SECONDS, 5), &print_peer_info,
@@ -233,6 +594,23 @@ run (void *cls, char *const *args, const char *cfgfile,
233 printf ("%s\n", (char *) &enc); 594 printf ("%s\n", (char *) &enc);
234 else 595 else
235 printf (_("I am peer `%s'.\n"), (const char *) &enc); 596 printf (_("I am peer `%s'.\n"), (const char *) &enc);
597 if (get_uri == GNUNET_YES)
598 {
599 struct PrintContext *pc;
600 char *pkey;
601 ssize_t l, pl;
602 pc = GNUNET_malloc (sizeof (struct PrintContext));
603 pkey = GNUNET_CRYPTO_rsa_public_key_to_string (&pub);
604 pl = strlen ("gnunet://hello/");
605 l = strlen (pkey) + pl;
606 pc->uri = GNUNET_malloc (l + 1);
607 strcpy (pc->uri, "gnunet://hello/");
608 strcpy (&pc->uri[pl], pkey);
609 pc->uri_len = l;
610 GNUNET_PEERINFO_iterate (peerinfo, &pid,
611 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5),
612 print_my_uri, pc);
613 }
236 } 614 }
237} 615}
238 616
@@ -257,6 +635,12 @@ main (int argc, char *const *argv)
257 {'s', "self", NULL, 635 {'s', "self", NULL,
258 gettext_noop ("output our own identity only"), 636 gettext_noop ("output our own identity only"),
259 0, &GNUNET_GETOPT_set_one, &get_self}, 637 0, &GNUNET_GETOPT_set_one, &get_self},
638 {'g', "get-hello", NULL,
639 gettext_noop ("also output HELLO uri(s)"),
640 0, &GNUNET_GETOPT_set_one, &get_uri},
641 {'p', "put-hello", "HELLO",
642 gettext_noop ("add given HELLO uri to the database"),
643 1, &GNUNET_GETOPT_set_string, &put_uri},
260 GNUNET_GETOPT_OPTION_END 644 GNUNET_GETOPT_OPTION_END
261 }; 645 };
262 return (GNUNET_OK == 646 return (GNUNET_OK ==