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