RPS: Use stp(n)cpy instead of strncat in loop
[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 it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your 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      Affero General Public License for more details.
14     
15      You should have received a copy of the GNU Affero General Public License
16      along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18      SPDX-License-Identifier: AGPL3.0-or-later
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  * @brief Do we want to receive updates of the view? (Option --view)
50  */
51 static int view_update;
52
53 /**
54  * @brief Do we want to receive updates of the view? (Option --view)
55  */
56 static int stream_input;
57
58 /**
59  * @brief Number of updates we want to receive
60  */
61 static uint64_t num_view_updates;
62
63
64 /**
65  * Task run when user presses CTRL-C to abort.
66  * Cancels pending request and disconnects.
67  *
68  * @param cls NULL
69  */
70 static void
71 do_shutdown (void *cls)
72 {
73   (void) cls;
74
75   if (NULL != req_handle)
76     GNUNET_RPS_request_cancel (req_handle);
77   GNUNET_RPS_disconnect (rps_handle);
78 }
79
80
81 /**
82  * Callback called on receipt of reply.
83  * Prints replied PeerIDs.
84  *
85  * @param cls closure
86  * @param n number of peers
87  * @param recv_peers the received peers
88  */
89 static void
90 reply_handle (void *cls,
91               uint64_t n,
92               const struct GNUNET_PeerIdentity *recv_peers)
93 {
94   uint64_t i;
95   (void) cls;
96
97   req_handle = NULL;
98   for (i = 0; i < n; i++)
99   {
100     FPRINTF (stdout, "%s\n",
101         GNUNET_i2s_full (&recv_peers[i]));
102   }
103   ret = 0;
104
105   GNUNET_SCHEDULER_shutdown ();
106 }
107
108 /**
109  * Callback called on receipt view update.
110  * Prints view.
111  *
112  * @param n number of peers
113  * @param recv_peers the received peers
114  */
115 static void
116 view_update_handle (void *cls,
117                     uint64_t n,
118                     const struct GNUNET_PeerIdentity *recv_peers)
119 {
120   uint64_t i;
121   (void) cls;
122
123   if (0 == n)
124   {
125     FPRINTF (stdout, "Empty view\n");
126   }
127   req_handle = NULL;
128   for (i = 0; i < n; i++)
129   {
130     FPRINTF (stdout, "%s\n",
131         GNUNET_i2s_full (&recv_peers[i]));
132   }
133
134   if (1 == num_view_updates)
135   {
136     ret = 0;
137     GNUNET_SCHEDULER_shutdown ();
138   }
139   else if (1 < num_view_updates)
140   {
141     num_view_updates--;
142   }
143 }
144
145
146 /**
147  * Callback called on receipt of peer from biased stream
148  *
149  * @param n number of peers
150  * @param recv_peers the received peers
151  */
152 static void
153 stream_input_handle (void *cls,
154                      uint64_t num_peers,
155                      const struct GNUNET_PeerIdentity *recv_peers)
156 {
157   uint64_t i;
158   (void) cls;
159
160   if (0 == num_peers)
161   {
162     FPRINTF (stdout, "No peer was returned\n");
163   }
164   req_handle = NULL;
165   for (i = 0; i < num_peers; i++)
166   {
167     FPRINTF (stdout, "%s\n",
168              GNUNET_i2s_full (&recv_peers[i]));
169   }
170 }
171
172
173 /**
174  * Main function that will be run by the scheduler.
175  *
176  * @param cls closure
177  * @param args remaining command-line arguments
178  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
179  * @param cfg configuration
180  */
181 static void
182 run (void *cls,
183      char *const *args,
184      const char *cfgfile,
185      const struct GNUNET_CONFIGURATION_Handle *cfg)
186 {
187   static uint64_t num_peers;
188   static struct GNUNET_PeerIdentity zero_pid;
189   (void) cls;
190   (void) cfgfile;
191
192   rps_handle = GNUNET_RPS_connect (cfg);
193   if (NULL == rps_handle)
194   {
195     FPRINTF (stderr, "Failed to connect to the rps service\n");
196     return;
197   }
198
199   if ((0 == memcmp (&zero_pid, &peer_id, sizeof (peer_id))) &&
200       (!view_update) &&
201       (!stream_input))
202   { /* Request n PeerIDs */
203     /* If number was specified use it, else request single peer. */
204     if (NULL == args[0] ||
205         0 == sscanf (args[0], "%lu", &num_peers))
206     {
207       num_peers = 1;
208     }
209     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
210         "Requesting %" PRIu64 " PeerIDs\n", num_peers);
211     req_handle = GNUNET_RPS_request_peers (rps_handle, num_peers, reply_handle, NULL);
212     GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
213   } else if (view_update)
214   {
215     /* Get updates of view */
216     if (NULL == args[0] ||
217         0 == sscanf (args[0], "%lu", &num_view_updates))
218     {
219       num_view_updates = 0;
220     }
221     GNUNET_RPS_view_request (rps_handle, num_view_updates, view_update_handle, NULL);
222     if (0 != num_view_updates)
223       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
224           "Requesting %" PRIu64 " view updates\n", num_view_updates);
225     else
226       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
227           "Requesting continuous view updates\n");
228     GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
229   } else if (stream_input)
230   {
231     /* Get updates of view */
232     GNUNET_RPS_stream_request (rps_handle, stream_input_handle, NULL);
233     GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
234   }
235   else
236   { /* Seed PeerID */
237     GNUNET_RPS_seed_ids (rps_handle, 1, &peer_id);
238     FPRINTF (stdout, "Seeded PeerID %s\n", GNUNET_i2s_full (&peer_id));
239     ret = 0;
240     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
241   }
242 }
243
244 /**
245  * The main function to rps.
246  *
247  * @param argc number of arguments from the command line
248  * @param argv command line arguments
249  * @return 0 ok, 1 on error
250  */
251 int
252 main (int argc, char *const *argv)
253 {
254   const char helpstr[] =
255     "Get random GNUnet peers. If none is specified a single is requested.";
256   struct GNUNET_GETOPT_CommandLineOption options[] = {
257     GNUNET_GETOPT_option_base32_auto ('s',
258                                           "seed",
259                                           "PEER_ID",
260                                           gettext_noop ("Seed a PeerID"),
261                                           &peer_id),
262     GNUNET_GETOPT_option_flag ('V',
263                                "view",
264                                gettext_noop ("Get updates of view (0 for infinite updates)"),
265                                &view_update),
266     GNUNET_GETOPT_option_flag ('S',
267                                "stream",
268                                gettext_noop ("Get peers from biased stream"),
269                                &stream_input),
270     GNUNET_GETOPT_OPTION_END
271   };
272   return (GNUNET_OK ==
273           GNUNET_PROGRAM_run (argc,
274                               argv,
275                               "gnunet-rps [NUMBER_OF_PEERS]",
276                               gettext_noop
277                               (helpstr),
278                               options, &run, NULL)) ? ret : 1;
279 }
280
281 /* end of gnunet-rps.c */