Merge branch 'master' of ssh://gnunet.org/gnunet
[oweals/gnunet.git] / src / rps / gnunet-rps.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C)
4
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.
9
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.
14
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., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, USA.
19 */
20
21 /**
22  * @file rps/gnunet-rps.c
23  * @brief random peer sampling
24  * @author Julius Bünger
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_rps_service.h"
29 #include <inttypes.h>
30
31 static int ret;
32
33 /**
34  * RPS handle
35  */
36 static struct GNUNET_RPS_Handle *rps_handle;
37
38 /**
39  * Request handle
40  */
41 static struct GNUNET_RPS_Request_Handle *req_handle;
42
43 /**
44  * PeerID (Option --seed)
45  */
46 static struct GNUNET_PeerIdentity *peer_id;
47
48
49 /**
50  * Set an option of type 'struct GNUNET_PeerIdentity *' from the command line.
51  * A pointer to this function should be passed as part of the
52  * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options
53  * of this type.  It should be followed by a pointer to a value of
54  * type 'struct GNUNET_PeerIdentity *', which will be allocated with the requested string.
55  *
56  * @param ctx command line processing context
57  * @param scls additional closure (will point to the 'char *',
58  *             which will be allocated)
59  * @param option name of the option
60  * @param value actual value of the option (a PeerID)
61  * @return #GNUNET_OK
62  */
63 static int
64 GNUNET_GETOPT_set_peerid (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
65                           void *scls, const char *option, const char *value)
66 {
67   struct GNUNET_PeerIdentity **val = (struct GNUNET_PeerIdentity **) scls;
68
69   GNUNET_assert (NULL != value);
70   GNUNET_free_non_null (*val);
71   /* Not quite sure whether that is a sane way */
72   *val = GNUNET_new (struct GNUNET_PeerIdentity);
73   if (GNUNET_OK !=
74       GNUNET_CRYPTO_eddsa_public_key_from_string (value,
75                                                   strlen (value),
76                                                   &((*val)->public_key)))
77   {
78     FPRINTF (stderr, "Invalid peer ID %s\n", value);
79     return GNUNET_SYSERR;
80   }
81   return GNUNET_OK;
82 }
83
84
85 /**
86  * Task run when user presses CTRL-C to abort.
87  * Cancels pending request and disconnects.
88  *
89  * @param cls NULL
90  */
91 static void
92 do_shutdown (void *cls)
93 {
94   if (NULL != req_handle)
95     GNUNET_RPS_request_cancel (req_handle);
96   GNUNET_RPS_disconnect (rps_handle);
97 }
98
99
100 /**
101  * Callback called on receipt of reply.
102  * Prints replied PeerIDs.
103  *
104  * @param cls closure
105  * @param n number of peers
106  * @param recv_peers the received peers
107  */
108 static void
109 reply_handle (void *cls,
110               uint64_t n,
111               const struct GNUNET_PeerIdentity *recv_peers)
112 {
113   uint64_t i;
114
115   req_handle = NULL;
116   for (i = 0; i < n; i++)
117   {
118     FPRINTF (stdout, "%s\n",
119         GNUNET_i2s_full (&recv_peers[i]));
120   }
121   ret = 0;
122
123   GNUNET_SCHEDULER_shutdown ();
124 }
125
126
127 /**
128  * Main function that will be run by the scheduler.
129  *
130  * @param cls closure
131  * @param args remaining command-line arguments
132  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
133  * @param cfg configuration
134  */
135 static void
136 run (void *cls,
137      char *const *args,
138      const char *cfgfile,
139      const struct GNUNET_CONFIGURATION_Handle *cfg)
140 {
141   static uint64_t num_peers;
142
143   rps_handle = GNUNET_RPS_connect (cfg);
144
145   if (NULL == peer_id)
146   { /* Request n PeerIDs */
147     /* If number was specified use it, else request single peer. */
148     num_peers = (NULL == args[0]) ? 1 : atoi (args[0]);
149     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
150         "Requesting %" PRIu64 " PeerIDs\n", num_peers);
151     req_handle = GNUNET_RPS_request_peers (rps_handle, num_peers, reply_handle, NULL);
152     GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
153   }
154   else
155   { /* Seed PeerID */
156     GNUNET_RPS_seed_ids (rps_handle, 1, peer_id);
157     FPRINTF (stdout, "Seeded PeerID %s\n", GNUNET_i2s_full (peer_id));
158     ret = 0;
159     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
160   }
161 }
162
163 /**
164  * The main function to rps.
165  *
166  * @param argc number of arguments from the command line
167  * @param argv command line arguments
168  * @return 0 ok, 1 on error
169  */
170 int
171 main (int argc, char *const *argv)
172 {
173   const char helpstr[] =
174     "Get random GNUnet peers. If none is specified a single is requested.";
175   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
176     {'s', "seed", "PEER_ID",
177       gettext_noop ("Seed a PeerID"),
178       GNUNET_YES, &GNUNET_GETOPT_set_peerid, &peer_id},
179     GNUNET_GETOPT_OPTION_END
180   };
181   return (GNUNET_OK ==
182           GNUNET_PROGRAM_run (argc,
183                               argv,
184                               "gnunet-rps [NUMBER_OF_PEERS]",
185                               gettext_noop
186                               (helpstr),
187                               options, &run, NULL)) ? ret : 1;
188 }
189
190 /* end of gnunet-rps.c */