error handling
[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
96   (void) cls;
97
98   req_handle = NULL;
99   for (i = 0; i < n; i++)
100   {
101     fprintf (stdout, "%s\n",
102              GNUNET_i2s_full (&recv_peers[i]));
103   }
104   ret = 0;
105
106   GNUNET_SCHEDULER_shutdown ();
107 }
108
109
110 /**
111  * Callback called on receipt view update.
112  * Prints view.
113  *
114  * @param n number of peers
115  * @param recv_peers the received peers
116  */
117 static void
118 view_update_handle (void *cls,
119                     uint64_t n,
120                     const struct GNUNET_PeerIdentity *recv_peers)
121 {
122   uint64_t i;
123
124   (void) cls;
125
126   if (0 == n)
127   {
128     fprintf (stdout, "Empty view\n");
129   }
130   req_handle = NULL;
131   for (i = 0; i < n; i++)
132   {
133     fprintf (stdout, "%s\n",
134              GNUNET_i2s_full (&recv_peers[i]));
135   }
136
137   if (1 == num_view_updates)
138   {
139     ret = 0;
140     GNUNET_SCHEDULER_shutdown ();
141   }
142   else if (1 < num_view_updates)
143   {
144     num_view_updates--;
145   }
146 }
147
148
149 /**
150  * Callback called on receipt of peer from biased stream
151  *
152  * @param n number of peers
153  * @param recv_peers the received peers
154  */
155 static void
156 stream_input_handle (void *cls,
157                      uint64_t num_peers,
158                      const struct GNUNET_PeerIdentity *recv_peers)
159 {
160   uint64_t i;
161
162   (void) cls;
163
164   if (0 == num_peers)
165   {
166     fprintf (stdout, "No peer was returned\n");
167   }
168   req_handle = NULL;
169   for (i = 0; i < num_peers; i++)
170   {
171     fprintf (stdout, "%s\n",
172              GNUNET_i2s_full (&recv_peers[i]));
173   }
174 }
175
176
177 /**
178  * Main function that will be run by the scheduler.
179  *
180  * @param cls closure
181  * @param args remaining command-line arguments
182  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
183  * @param cfg configuration
184  */
185 static void
186 run (void *cls,
187      char *const *args,
188      const char *cfgfile,
189      const struct GNUNET_CONFIGURATION_Handle *cfg)
190 {
191   static uint64_t num_peers;
192   static struct GNUNET_PeerIdentity zero_pid;
193
194   (void) cls;
195   (void) cfgfile;
196
197   rps_handle = GNUNET_RPS_connect (cfg);
198   if (NULL == rps_handle)
199   {
200     fprintf (stderr, "Failed to connect to the rps service\n");
201     return;
202   }
203
204   if ((0 == memcmp (&zero_pid, &peer_id, sizeof(peer_id))) &&
205       (! view_update) &&
206       (! stream_input))
207   {   /* Request n PeerIDs */
208       /* If number was specified use it, else request single peer. */
209     if ((NULL == args[0]) ||
210         (0 == sscanf (args[0], "%lu", &num_peers)) )
211     {
212       num_peers = 1;
213     }
214     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
215                 "Requesting %" PRIu64 " PeerIDs\n", num_peers);
216     req_handle = GNUNET_RPS_request_peers (rps_handle, num_peers, reply_handle,
217                                            NULL);
218     GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
219   }
220   else if (view_update)
221   {
222     /* Get updates of view */
223     if ((NULL == args[0]) ||
224         (0 == sscanf (args[0], "%lu", &num_view_updates)) )
225     {
226       num_view_updates = 0;
227     }
228     GNUNET_RPS_view_request (rps_handle, num_view_updates, view_update_handle,
229                              NULL);
230     if (0 != num_view_updates)
231       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
232                   "Requesting %" PRIu64 " view updates\n", num_view_updates);
233     else
234       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
235                   "Requesting continuous view updates\n");
236     GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
237   }
238   else if (stream_input)
239   {
240     /* Get updates of view */
241     GNUNET_RPS_stream_request (rps_handle, stream_input_handle, NULL);
242     GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
243   }
244   else
245   {   /* Seed PeerID */
246     GNUNET_RPS_seed_ids (rps_handle, 1, &peer_id);
247     fprintf (stdout, "Seeded PeerID %s\n", GNUNET_i2s_full (&peer_id));
248     ret = 0;
249     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
250   }
251 }
252
253
254 /**
255  * The main function to rps.
256  *
257  * @param argc number of arguments from the command line
258  * @param argv command line arguments
259  * @return 0 ok, 1 on error
260  */
261 int
262 main (int argc, char *const *argv)
263 {
264   const char helpstr[] =
265     "Get random GNUnet peers. If none is specified a single is requested.";
266   struct GNUNET_GETOPT_CommandLineOption options[] = {
267     GNUNET_GETOPT_option_base32_auto ('s',
268                                       "seed",
269                                       "PEER_ID",
270                                       gettext_noop ("Seed a PeerID"),
271                                       &peer_id),
272     GNUNET_GETOPT_option_flag ('V',
273                                "view",
274                                gettext_noop (
275                                  "Get updates of view (0 for infinite updates)"),
276                                &view_update),
277     GNUNET_GETOPT_option_flag ('S',
278                                "stream",
279                                gettext_noop ("Get peers from biased stream"),
280                                &stream_input),
281     GNUNET_GETOPT_OPTION_END
282   };
283
284   return (GNUNET_OK ==
285           GNUNET_PROGRAM_run (argc,
286                               argv,
287                               "gnunet-rps [NUMBER_OF_PEERS]",
288                               gettext_noop
289                                 (helpstr),
290                               options, &run, NULL)) ? ret : 1;
291 }
292
293
294 /* end of gnunet-rps.c */