123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905 |
- /*
- This file is part of GNUnet.
- Copyright (C) 2001-2014, 2016 GNUnet e.V.
- GNUnet is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3, or (at your
- option) any later version.
- GNUnet is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with GNUnet; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
- */
- /**
- * @file peerinfo-tool/gnunet-peerinfo.c
- * @brief Print information about other known peers.
- * @author Christian Grothoff
- * @author Matthias Wachs
- */
- #include "platform.h"
- #include "gnunet_util_lib.h"
- #include "gnunet_hello_lib.h"
- #include "gnunet_transport_service.h"
- #include "gnunet_transport_hello_service.h"
- #include "gnunet_peerinfo_service.h"
- #include "gnunet-peerinfo_plugins.h"
- /**
- * How long until we time out during address lookup?
- */
- #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
- /**
- * Structure we use to collect printable address information.
- */
- struct PrintContext;
- /**
- * Record we keep for each printable address.
- */
- struct AddressRecord
- {
- /**
- * Current address-to-string context (if active, otherwise NULL).
- */
- struct GNUNET_TRANSPORT_AddressToStringContext *atsc;
- /**
- * Address expiration time
- */
- struct GNUNET_TIME_Absolute expiration;
- /**
- * Printable address.
- */
- char *result;
- /**
- * Print context this address record belongs to.
- */
- struct PrintContext *pc;
- };
- /**
- * Structure we use to collect printable address information.
- */
- struct PrintContext
- {
- /**
- * Kept in DLL.
- */
- struct PrintContext *next;
- /**
- * Kept in DLL.
- */
- struct PrintContext *prev;
- /**
- * Identity of the peer.
- */
- struct GNUNET_PeerIdentity peer;
- /**
- * List of printable addresses.
- */
- struct AddressRecord *address_list;
- /**
- * Number of completed addresses in @e address_list.
- */
- unsigned int num_addresses;
- /**
- * Number of addresses allocated in @e address_list.
- */
- unsigned int address_list_size;
- /**
- * Current offset in @e address_list (counted down).
- */
- unsigned int off;
- /**
- * Hello was friend only, #GNUNET_YES or #GNUNET_NO
- */
- int friend_only;
- };
- /**
- * Option '-n'
- */
- static int no_resolve;
- /**
- * Option '-q'
- */
- static int be_quiet;
- /**
- * Option '-f'
- */
- static int include_friend_only;
- /**
- * Option '-s'
- */
- static int get_self;
- /**
- * Option
- */
- static int get_uri;
- /**
- * Option
- */
- static int default_operation;
- /**
- * Option '-i'
- */
- static int get_info;
- /**
- * Option
- */
- static char *put_uri;
- /**
- * Option -d
- */
- static char *dump_hello;
- /**
- * Handle to peerinfo service.
- */
- static struct GNUNET_PEERINFO_Handle *peerinfo;
- /**
- * Configuration handle.
- */
- static const struct GNUNET_CONFIGURATION_Handle *cfg;
- /**
- * Main state machine task (if active).
- */
- static struct GNUNET_SCHEDULER_Task *tt;
- /**
- * Pending #GNUNET_TRANSPORT_hello_get() operation.
- */
- static struct GNUNET_TRANSPORT_HelloGetHandle *gh;
- /**
- * Current iterator context (if active, otherwise NULL).
- */
- static struct GNUNET_PEERINFO_IteratorContext *pic;
- /**
- * My peer identity.
- */
- static struct GNUNET_PeerIdentity my_peer_identity;
- /**
- * Head of list of print contexts.
- */
- static struct PrintContext *pc_head;
- /**
- * Tail of list of print contexts.
- */
- static struct PrintContext *pc_tail;
- /**
- * Handle to current #GNUNET_PEERINFO_add_peer() operation.
- */
- static struct GNUNET_MQ_Envelope *ac;
- /**
- * Hello of this peer (if initialized).
- */
- static struct GNUNET_HELLO_Message *my_hello;
- /**
- * Main state machine that goes over all options and
- * runs the next requested function.
- *
- * @param cls unused
- */
- static void
- state_machine (void *cls);
- /* ********************* 'get_info' ******************* */
- /**
- * Print the collected address information to the console and free @a pc.
- *
- * @param pc printing context
- */
- static void
- dump_pc (struct PrintContext *pc)
- {
- unsigned int i;
- printf (_("%sPeer `%s'\n"),
- (GNUNET_YES == pc->friend_only) ? "F2F: " : "",
- GNUNET_i2s_full (&pc->peer));
- for (i = 0; i < pc->num_addresses; i++)
- {
- if (NULL != pc->address_list[i].result)
- {
- printf (_("\tExpires: %s \t %s\n"),
- GNUNET_STRINGS_absolute_time_to_string (pc->address_list[i].expiration),
- pc->address_list[i].result);
- GNUNET_free (pc->address_list[i].result);
- }
- }
- printf ("\n");
- GNUNET_free_non_null (pc->address_list);
- GNUNET_CONTAINER_DLL_remove (pc_head,
- pc_tail,
- pc);
- GNUNET_free (pc);
- if ( (NULL == pc_head) &&
- (NULL == pic) )
- tt = GNUNET_SCHEDULER_add_now (&state_machine,
- NULL);
- }
- /* ************************* list all known addresses **************** */
- /**
- * Function to call with a human-readable format of an address
- *
- * @param cls closure
- * @param address NULL on error, otherwise 0-terminated printable UTF-8 string
- * @param res result of the address to string conversion:
- * if #GNUNET_OK: address was valid (conversion to
- * string might still have failed)
- * if #GNUNET_SYSERR: address is invalid
- */
- static void
- process_resolved_address (void *cls,
- const char *address,
- int res)
- {
- struct AddressRecord *ar = cls;
- struct PrintContext *pc = ar->pc;
- if (NULL != address)
- {
- if (0 != strlen (address))
- {
- if (NULL != ar->result)
- GNUNET_free (ar->result);
- ar->result = GNUNET_strdup (address);
- }
- return;
- }
- ar->atsc = NULL;
- if (GNUNET_SYSERR == res)
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- _("Failure: Cannot convert address to string for peer `%s'\n"),
- GNUNET_i2s (&ar->pc->peer));
- pc->num_addresses++;
- if (pc->num_addresses == pc->address_list_size)
- dump_pc (pc);
- }
- /**
- * Iterator callback to go over all addresses and count them.
- *
- * @param cls `struct PrintContext *` with `off` to increment
- * @param address the address
- * @param expiration expiration time
- * @return #GNUNET_OK to keep the address and continue
- */
- static int
- count_address (void *cls,
- const struct GNUNET_HELLO_Address *address,
- struct GNUNET_TIME_Absolute expiration)
- {
- struct PrintContext *pc = cls;
- pc->off++;
- return GNUNET_OK;
- }
- /**
- * Iterator callback to go over all addresses.
- *
- * @param cls closure
- * @param address the address
- * @param expiration expiration time
- * @return #GNUNET_OK to keep the address and continue
- */
- static int
- print_address (void *cls,
- const struct GNUNET_HELLO_Address *address,
- struct GNUNET_TIME_Absolute expiration)
- {
- struct PrintContext *pc = cls;
- struct AddressRecord *ar;
- GNUNET_assert (0 < pc->off);
- ar = &pc->address_list[--pc->off];
- ar->pc = pc;
- ar->expiration = expiration;
- GNUNET_asprintf (&ar->result,
- "%s:%u:%u",
- address->transport_name,
- address->address_length,
- address->local_info);
- ar->atsc = GNUNET_TRANSPORT_address_to_string (cfg,
- address,
- no_resolve,
- TIMEOUT,
- &process_resolved_address, ar);
- return GNUNET_OK;
- }
- /**
- * Print information about the peer. Currently prints the `struct
- * GNUNET_PeerIdentity` and the transport address.
- *
- * @param cls the `struct PrintContext *`
- * @param peer identity of the peer
- * @param hello addresses of the peer
- * @param err_msg error message
- */
- static void
- print_peer_info (void *cls,
- const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_HELLO_Message *hello,
- const char *err_msg)
- {
- struct PrintContext *pc;
- int friend_only;
- if (NULL == peer)
- {
- pic = NULL; /* end of iteration */
- if (NULL != err_msg)
- {
- FPRINTF (stderr,
- _("Error in communication with PEERINFO service: %s\n"),
- err_msg);
- }
- if (NULL == pc_head)
- tt = GNUNET_SCHEDULER_add_now (&state_machine, NULL);
- return;
- }
- friend_only = GNUNET_NO;
- if (NULL != hello)
- friend_only = GNUNET_HELLO_is_friend_only (hello);
- if ( (GNUNET_YES == be_quiet) ||
- (NULL == hello) )
- {
- printf ("%s%s\n",
- (GNUNET_YES == friend_only) ? "F2F: " : "",
- GNUNET_i2s_full (peer));
- return;
- }
- pc = GNUNET_new (struct PrintContext);
- GNUNET_CONTAINER_DLL_insert (pc_head,
- pc_tail,
- pc);
- pc->peer = *peer;
- pc->friend_only = friend_only;
- GNUNET_HELLO_iterate_addresses (hello,
- GNUNET_NO,
- &count_address,
- pc);
- if (0 == pc->off)
- {
- dump_pc (pc);
- return;
- }
- pc->address_list_size = pc->off;
- pc->address_list = GNUNET_malloc (sizeof (struct AddressRecord) * pc->off);
- GNUNET_HELLO_iterate_addresses (hello,
- GNUNET_NO,
- &print_address,
- pc);
- }
- /* ************************* DUMP Hello ************************** */
- /**
- * Count the number of addresses in the HELLO.
- *
- * @param cls pointer to an `int *` used for the counter
- * @param address an address to count
- * @param expiration (unused)
- * @return #GNUNET_OK
- */
- static int
- count_addr (void *cls,
- const struct GNUNET_HELLO_Address *address,
- struct GNUNET_TIME_Absolute expiration)
- {
- int *c = cls;
- (*c)++;
- return GNUNET_OK;
- }
- /**
- * Write HELLO of my peer to a file.
- *
- * @param cls the `struct GetUriContext *`
- * @param peer identity of the peer (unused)
- * @param hello addresses of the peer
- * @param err_msg error message
- */
- static void
- dump_my_hello ()
- {
- unsigned int size;
- unsigned int c_addr;
- size = GNUNET_HELLO_size (my_hello);
- if (0 == size)
- {
- FPRINTF (stderr,
- _("Failure: Received invalid %s\n"),
- "HELLO");
- return;
- }
- if (GNUNET_SYSERR ==
- GNUNET_DISK_fn_write (dump_hello,
- my_hello,
- size,
- GNUNET_DISK_PERM_USER_READ |
- GNUNET_DISK_PERM_USER_WRITE |
- GNUNET_DISK_PERM_GROUP_READ |
- GNUNET_DISK_PERM_OTHER_READ))
- {
- FPRINTF (stderr,
- _("Failed to write HELLO with %u bytes to file `%s'\n"),
- size,
- dump_hello);
- if (0 != UNLINK (dump_hello))
- GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING |
- GNUNET_ERROR_TYPE_BULK,
- "unlink",
- dump_hello);
- }
- c_addr = 0;
- GNUNET_HELLO_iterate_addresses (my_hello,
- GNUNET_NO,
- count_addr,
- &c_addr);
- if (! be_quiet)
- {
- FPRINTF (stderr,
- _("Wrote %s HELLO containing %u addresses with %u bytes to file `%s'\n"),
- (GNUNET_YES == GNUNET_HELLO_is_friend_only (my_hello)) ? "friend-only": "public",
- c_addr,
- size,
- dump_hello);
- }
- GNUNET_free (dump_hello);
- dump_hello = NULL;
- }
- /* ************************* GET URI ************************** */
- /**
- * Print URI of the peer.
- *
- * @param cls the `struct GetUriContext *`
- * @param peer identity of the peer (unused)
- * @param hello addresses of the peer
- * @param err_msg error message
- */
- static void
- print_my_uri (void *cls,
- const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_HELLO_Message *hello,
- const char *err_msg)
- {
- char *uri;
- if (NULL == peer)
- {
- pic = NULL;
- if (NULL != err_msg)
- FPRINTF (stderr,
- _("Error in communication with PEERINFO service: %s\n"),
- err_msg);
- tt = GNUNET_SCHEDULER_add_now (&state_machine, NULL);
- return;
- }
- if (NULL == hello)
- return;
- uri = GNUNET_HELLO_compose_uri (hello,
- &GPI_plugins_find);
- if (NULL != uri)
- {
- printf ("%s\n",
- (const char *) uri);
- GNUNET_free (uri);
- }
- }
- /* ************************* import HELLO by URI ********************* */
- /**
- * Continuation called from #GNUNET_PEERINFO_add_peer()
- *
- * @param cls closure, NULL
- */
- static void
- add_continuation (void *cls)
- {
- ac = NULL;
- tt = GNUNET_SCHEDULER_add_now (&state_machine, NULL);
- }
- /**
- * Parse the PUT URI given at the command line and add it to our peerinfo
- * database.
- *
- * @param put_uri URI string to parse
- * @return #GNUNET_OK on success,
- * #GNUNET_SYSERR if the URI was invalid,
- * #GNUNET_NO on other errors
- */
- static int
- parse_hello_uri (const char *put_uri)
- {
- struct GNUNET_HELLO_Message *hello = NULL;
- int ret = GNUNET_HELLO_parse_uri (put_uri,
- &my_peer_identity.public_key,
- &hello,
- &GPI_plugins_find);
- if (NULL != hello)
- {
- /* WARNING: this adds the address from URI WITHOUT verification! */
- if (GNUNET_OK == ret)
- ac = GNUNET_PEERINFO_add_peer (peerinfo,
- hello,
- &add_continuation,
- NULL);
- else
- tt = GNUNET_SCHEDULER_add_now (&state_machine, NULL);
- GNUNET_free (hello);
- }
- return ret;
- }
- /* ************************ Main state machine ********************* */
- /**
- * Main state machine that goes over all options and
- * runs the next requested function.
- *
- * @param cls unused
- */
- static void
- shutdown_task (void *cls)
- {
- struct PrintContext *pc;
- struct AddressRecord *ar;
- unsigned int i;
- if (NULL != ac)
- {
- GNUNET_MQ_send_cancel (ac);
- ac = NULL;
- }
- if (NULL != tt)
- {
- GNUNET_SCHEDULER_cancel (tt);
- tt = NULL;
- }
- if (NULL != pic)
- {
- GNUNET_PEERINFO_iterate_cancel (pic);
- pic = NULL;
- }
- if (NULL != gh)
- {
- GNUNET_TRANSPORT_hello_get_cancel (gh);
- gh = NULL;
- }
- while (NULL != (pc = pc_head))
- {
- GNUNET_CONTAINER_DLL_remove (pc_head,
- pc_tail,
- pc);
- for (i=0;i<pc->address_list_size;i++)
- {
- ar = &pc->address_list[i];
- GNUNET_free_non_null (ar->result);
- if (NULL != ar->atsc)
- {
- GNUNET_TRANSPORT_address_to_string_cancel (ar->atsc);
- ar->atsc = NULL;
- }
- }
- GNUNET_free_non_null (pc->address_list);
- GNUNET_free (pc);
- }
- GPI_plugins_unload ();
- if (NULL != peerinfo)
- {
- GNUNET_PEERINFO_disconnect (peerinfo);
- peerinfo = NULL;
- }
- if (NULL != my_hello)
- {
- GNUNET_free (my_hello);
- my_hello = NULL;
- }
- }
- /**
- * Function called with our peer's HELLO message.
- * Used to obtain our peer's public key.
- *
- * @param cls NULL
- * @param hello the HELLO message
- */
- static void
- hello_callback (void *cls,
- const struct GNUNET_MessageHeader *hello)
- {
- if (NULL == hello)
- {
- fprintf (stderr,
- "Failed to get my own HELLO from this peer!\n");
- GNUNET_SCHEDULER_shutdown ();
- return;
- }
- my_hello = (struct GNUNET_HELLO_Message *) GNUNET_copy_message (hello);
- GNUNET_assert (GNUNET_OK ==
- GNUNET_HELLO_get_id (my_hello,
- &my_peer_identity));
- GNUNET_TRANSPORT_hello_get_cancel (gh);
- gh = NULL;
- if (NULL != dump_hello)
- dump_my_hello ();
- tt = GNUNET_SCHEDULER_add_now (&state_machine, NULL);
- }
- /**
- * Main function that will be run by the scheduler.
- *
- * @param cls closure
- * @param args remaining command-line arguments
- * @param cfgfile name of the configuration file used (for saving, can be NULL!)
- * @param c configuration
- */
- static void
- run (void *cls,
- char *const *args,
- const char *cfgfile,
- const struct GNUNET_CONFIGURATION_Handle *c)
- {
- cfg = c;
- if ( (NULL != args[0]) &&
- (NULL == put_uri) &&
- (args[0] == strcasestr (args[0],
- "gnunet://hello/")) )
- {
- put_uri = GNUNET_strdup (args[0]);
- args++;
- }
- if (NULL != args[0])
- {
- FPRINTF (stderr,
- _("Invalid command line argument `%s'\n"),
- args[0]);
- return;
- }
- if (NULL == (peerinfo = GNUNET_PEERINFO_connect (cfg)))
- {
- FPRINTF (stderr,
- "%s",
- "Could not access PEERINFO service. Exiting.\n");
- return;
- }
- if ( (GNUNET_YES == get_self) ||
- (GNUNET_YES == get_uri) ||
- (NULL != dump_hello) )
- {
- gh = GNUNET_TRANSPORT_hello_get (cfg,
- GNUNET_TRANSPORT_AC_ANY,
- &hello_callback,
- NULL);
- }
- else
- {
- tt = GNUNET_SCHEDULER_add_now (&state_machine,
- NULL);
- }
- GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
- NULL);
- }
- /**
- * Main state machine that goes over all options and
- * runs the next requested function.
- *
- * @param cls unused
- */
- static void
- state_machine (void *cls)
- {
- tt = NULL;
- if (NULL != put_uri)
- {
- GPI_plugins_load (cfg);
- if (GNUNET_SYSERR == parse_hello_uri (put_uri))
- {
- fprintf (stderr,
- _("Invalid URI `%s'\n"),
- put_uri);
- GNUNET_SCHEDULER_shutdown ();
- }
- GNUNET_free (put_uri);
- put_uri = NULL;
- }
- else if (GNUNET_YES == get_info)
- {
- get_info = GNUNET_NO;
- GPI_plugins_load (cfg);
- pic = GNUNET_PEERINFO_iterate (peerinfo,
- include_friend_only,
- NULL,
- &print_peer_info,
- NULL);
- }
- else if (GNUNET_YES == get_self)
- {
- get_self = GNUNET_NO;
- if (be_quiet)
- printf ("%s\n",
- GNUNET_i2s_full (&my_peer_identity));
- else
- printf (_("I am peer `%s'.\n"),
- GNUNET_i2s_full (&my_peer_identity));
- tt = GNUNET_SCHEDULER_add_now (&state_machine,
- NULL);
- }
- else if (GNUNET_YES == get_uri)
- {
- GPI_plugins_load (cfg);
- pic = GNUNET_PEERINFO_iterate (peerinfo,
- include_friend_only,
- &my_peer_identity,
- &print_my_uri,
- NULL);
- get_uri = GNUNET_NO;
- }
- else if (GNUNET_YES == default_operation)
- {
- /* default operation list all */
- default_operation = GNUNET_NO;
- get_info = GNUNET_YES;
- tt = GNUNET_SCHEDULER_add_now (&state_machine,
- NULL);
- }
- else
- {
- GNUNET_SCHEDULER_shutdown ();
- }
- default_operation = GNUNET_NO;
- }
- /**
- * The main function to obtain peer information.
- *
- * @param argc number of arguments from the command line
- * @param argv command line arguments
- * @return 0 ok, 1 on error
- */
- int
- main (int argc, char *const *argv)
- {
- struct GNUNET_GETOPT_CommandLineOption options[] = {
- GNUNET_GETOPT_option_flag ('n',
- "numeric",
- gettext_noop ("don't resolve host names"),
- &no_resolve),
- GNUNET_GETOPT_option_flag ('q',
- "quiet",
- gettext_noop ("output only the identity strings"),
- &be_quiet),
- GNUNET_GETOPT_option_flag ('f',
- "friends",
- gettext_noop ("include friend-only information"),
- &include_friend_only),
- GNUNET_GETOPT_option_flag ('s',
- "self",
- gettext_noop ("output our own identity only"),
- &get_self),
-
- GNUNET_GETOPT_option_flag ('i',
- "info",
- gettext_noop ("list all known peers"),
- &get_info),
- GNUNET_GETOPT_option_string ('d',
- "dump-hello",
- NULL,
- gettext_noop ("dump hello to file"),
- &dump_hello),
- GNUNET_GETOPT_option_flag ('g',
- "get-hello",
- gettext_noop ("also output HELLO uri(s)"),
- &get_uri),
- GNUNET_GETOPT_option_string ('p',
- "put-hello",
- "HELLO",
- gettext_noop ("add given HELLO uri to the database"),
- &put_uri),
- GNUNET_GETOPT_OPTION_END
- };
- int ret;
- default_operation = GNUNET_YES;
- if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc,
- argv,
- &argc,
- &argv))
- return 2;
- ret = (GNUNET_OK ==
- GNUNET_PROGRAM_run (argc,
- argv,
- "gnunet-peerinfo",
- gettext_noop ("Print information about peers."),
- options,
- &run,
- NULL)) ? 0 : 1;
- GNUNET_free ((void*) argv);
- return ret;
- }
- /* end of gnunet-peerinfo.c */
|