memcmp() -> GNUNET_memcmp(), first take
[oweals/gnunet.git] / src / hostlist / gnunet-daemon-hostlist.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2007, 2008, 2009, 2014 GNUnet e.V.
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 hostlist/gnunet-daemon-hostlist.c
23  * @brief code for bootstrapping via hostlist servers
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "gnunet-daemon-hostlist_client.h"
28 #include "gnunet_core_service.h"
29 #include "gnunet_util_lib.h"
30 #include "gnunet_protocols.h"
31 #include "gnunet_statistics_service.h"
32
33 #if HAVE_MHD
34
35 #include "gnunet-daemon-hostlist_server.h"
36
37 /**
38  * Set if we are allowed to advertise our hostlist to others.
39  */
40 static int advertising;
41
42 /**
43  * Set if the user wants us to run a hostlist server.
44  */
45 static int provide_hostlist;
46
47 /**
48  * Handle to hostlist server's connect handler
49  */
50 static GNUNET_CORE_ConnectEventHandler server_ch;
51
52 #endif
53
54 /**
55  * Set if we are allowed to learn about peers by accessing
56  * hostlist servers.
57  */
58 static int bootstrapping;
59
60 /**
61  * Set if the user allows us to learn about new hostlists
62  * from the network.
63  */
64 static int learning;
65
66 /**
67  * Statistics handle.
68  */
69 static struct GNUNET_STATISTICS_Handle *stats;
70
71 /**
72  * Handle to the core service (NULL until we've connected to it).
73  */
74 static struct GNUNET_CORE_Handle *core;
75
76 /**
77  * Handle to the hostlist client's advertisement handler
78  */
79 static GNUNET_HOSTLIST_UriHandler client_adv_handler;
80
81 /**
82  * Handle to hostlist client's connect handler
83  */
84 static GNUNET_CORE_ConnectEventHandler client_ch;
85
86 /**
87  * Handle to hostlist client's disconnect handler
88  */
89 static GNUNET_CORE_DisconnectEventHandler client_dh;
90
91 GNUNET_NETWORK_STRUCT_BEGIN
92
93 /**
94  * A HOSTLIST_ADV message is used to exchange information about
95  * hostlist advertisements.  This struct is always
96  * followed by the actual url under which the hostlist can be obtained:
97  *
98  * 1) transport-name (0-terminated)
99  * 2) address-length (uint32_t, network byte order; possibly
100  *    unaligned!)
101  * 3) address expiration (GNUNET_TIME_AbsoluteNBO); possibly
102  *    unaligned!)
103  * 4) address (address-length bytes; possibly unaligned!)
104  */
105 struct GNUNET_HOSTLIST_ADV_Message
106 {
107   /**
108    * Type will be GNUNET_MESSAGE_TYPE_HOSTLIST_ADVERTISEMENT.
109    */
110   struct GNUNET_MessageHeader header;
111
112   /**
113    * Always zero (for alignment).
114    */
115   uint32_t reserved GNUNET_PACKED;
116 };
117 GNUNET_NETWORK_STRUCT_END
118
119
120 /**
121  * Our own peer identity.
122  */
123 static struct GNUNET_PeerIdentity me;
124
125
126 /**
127  * Callback invoked once our connection to CORE service is up.
128  *
129  * @param cls NULL
130  * @param my_identity our peer's identity
131  */
132 static void
133 core_init (void *cls,
134            const struct GNUNET_PeerIdentity *my_identity)
135 {
136   me = *my_identity;
137 }
138
139
140 /**
141  * Core handler for p2p hostlist advertisements
142  *
143  * @param cls closure
144  * @param message advertisement message we got
145  * @return #GNUNET_OK if message is well-formed
146  */
147 static int
148 check_advertisement (void *cls,
149                      const struct GNUNET_MessageHeader *message)
150 {
151   size_t size;
152   size_t uri_size;
153   const char *uri;
154
155   size = ntohs (message->size);
156   if (size <= sizeof (struct GNUNET_MessageHeader))
157   {
158     GNUNET_break_op (0);
159     return GNUNET_SYSERR;
160   }
161   uri = (const char *) &message[1];
162   uri_size = size - sizeof (struct GNUNET_MessageHeader);
163   if (uri[uri_size - 1] != '\0')
164   {
165     GNUNET_break_op (0);
166     return GNUNET_SYSERR;
167   }
168   return GNUNET_OK;
169 }
170
171
172 /**
173  * Core handler for p2p hostlist advertisements
174  *
175  * @param cls closure
176  * @param message advertisement message we got
177  * @return #GNUNET_OK on success
178  */
179 static void
180 handle_advertisement (void *cls,
181                       const struct GNUNET_MessageHeader *message)
182 {
183   const char *uri = (const char *) &message[1];
184  
185   GNUNET_assert (NULL != client_adv_handler);
186   (void) (*client_adv_handler) (uri);
187 }
188
189
190 /**
191  * Method called whenever a given peer connects.  Wrapper to call both
192  * client's and server's functions
193  *
194  * @param cls closure
195  * @param peer peer identity this notification is about
196  * @param mq queue for sending messages to @a peer
197  * @return peer
198  */
199 static void *
200 connect_handler (void *cls,
201                  const struct GNUNET_PeerIdentity *peer,
202                  struct GNUNET_MQ_Handle *mq)
203 {
204   if (0 == GNUNET_memcmp (&me,
205                    peer))
206     return NULL;
207   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
208               "A new peer connected, notifying client and server\n");
209   if (NULL != client_ch)
210     GNUNET_assert (NULL ==
211                    (*client_ch) (cls,
212                                  peer,
213                                  mq));
214 #if HAVE_MHD
215   if (NULL != server_ch)
216     GNUNET_assert (NULL ==
217                    (*server_ch) (cls,
218                                  peer,
219                                  mq));
220 #endif
221   return (void *) peer;
222 }
223
224
225 /**
226  * Method called whenever a given peer disconnects. Wrapper to call
227  * both client's and server's functions
228  *
229  * @param cls closure
230  * @param peer peer identity this notification is about
231  */
232 static void
233 disconnect_handler (void *cls,
234                     const struct GNUNET_PeerIdentity *peer,
235                     void *internal_cls)
236 {
237   if (0 == GNUNET_memcmp (&me,
238                    peer))
239     return;
240   /* call hostlist client disconnect handler */
241   if (NULL != client_dh)
242     (*client_dh) (cls,
243                   peer,
244                   NULL);
245 }
246
247
248 /**
249  * Last task run during shutdown.  Disconnects us from
250  * the other services.
251  *
252  * @param cls NULL
253  */
254 static void
255 cleaning_task (void *cls)
256 {
257   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
258               "Hostlist daemon is shutting down\n");
259   if (NULL != core)
260   {
261     GNUNET_CORE_disconnect (core);
262     core = NULL;
263   }
264   if (bootstrapping)
265   {
266     GNUNET_HOSTLIST_client_stop ();
267   }
268 #if HAVE_MHD
269   if (provide_hostlist)
270   {
271     GNUNET_HOSTLIST_server_stop ();
272   }
273 #endif
274   if (NULL != stats)
275   {
276     GNUNET_STATISTICS_destroy (stats,
277                                GNUNET_NO);
278     stats = NULL;
279   }
280 }
281
282
283 /**
284  * Main function that will be run.
285  *
286  * @param cls closure
287  * @param args remaining command-line arguments
288  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
289  * @param cfg configuration
290  */
291 static void
292 run (void *cls,
293      char *const *args,
294      const char *cfgfile,
295      const struct GNUNET_CONFIGURATION_Handle *cfg)
296 {
297   struct GNUNET_MQ_MessageHandler learn_handlers[] = {
298     GNUNET_MQ_hd_var_size (advertisement,
299                            GNUNET_MESSAGE_TYPE_HOSTLIST_ADVERTISEMENT,
300                            struct GNUNET_MessageHeader,
301                            NULL),
302     GNUNET_MQ_handler_end ()
303   };
304   struct GNUNET_MQ_MessageHandler no_learn_handlers[] = {
305     GNUNET_MQ_handler_end ()
306   };
307   if ((! bootstrapping) && (! learning)
308 #if HAVE_MHD
309       && (! provide_hostlist)
310 #endif
311       )
312   {
313     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
314                 _("None of the functions for the hostlist daemon were enabled.  I have no reason to run!\n"));
315     return;
316   }
317   stats = GNUNET_STATISTICS_create ("hostlist", cfg);
318   if (NULL == stats)
319   {
320     GNUNET_break (0);
321     return;
322   }
323   if (bootstrapping)
324     GNUNET_HOSTLIST_client_start (cfg,
325                                   stats,
326                                   &client_ch,
327                                   &client_dh,
328                                   &client_adv_handler,
329                                   learning);
330   core =
331     GNUNET_CORE_connect (cfg,
332                          NULL,
333                          &core_init,
334                          &connect_handler,
335                          &disconnect_handler,
336                          learning ? learn_handlers : no_learn_handlers);
337
338
339 #if HAVE_MHD
340   if (provide_hostlist)
341     GNUNET_HOSTLIST_server_start (cfg,
342                                   stats,
343                                   core,
344                                   &server_ch,
345                                   advertising);
346 #endif
347   GNUNET_SCHEDULER_add_shutdown (&cleaning_task,
348                                  NULL);
349
350   if (NULL == core)
351   {
352     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
353                 _("Failed to connect to `%s' service.\n"), "core");
354     GNUNET_SCHEDULER_shutdown ();
355     return;
356   }
357 }
358
359
360 /**
361  * The main function for the hostlist daemon.
362  *
363  * @param argc number of arguments from the command line
364  * @param argv command line arguments
365  * @return 0 ok, 1 on error
366  */
367 int
368 main (int argc, char *const *argv)
369 {
370   struct GNUNET_GETOPT_CommandLineOption options[] = {
371 #if HAVE_MHD
372     GNUNET_GETOPT_option_flag ('a',
373                                   "advertise",
374                                   gettext_noop ("advertise our hostlist to other peers"),
375                                   &advertising),
376 #endif
377     GNUNET_GETOPT_option_flag ('b',
378                                   "bootstrap",
379                                   gettext_noop ("bootstrap using hostlists (it is highly recommended that you always use this option)"),
380                                   &bootstrapping),
381     GNUNET_GETOPT_option_flag ('e',
382                                   "enable-learning",
383                                   gettext_noop ("enable learning about hostlist servers from other peers"),
384                                   &learning),
385 #if HAVE_MHD
386     GNUNET_GETOPT_option_flag ('p',
387                                   "provide-hostlist",
388                                   gettext_noop ("provide a hostlist server"),
389                                   &provide_hostlist),
390 #endif
391     GNUNET_GETOPT_OPTION_END
392   };
393
394   int ret;
395
396   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
397     return 2;
398
399   GNUNET_log_setup ("hostlist", "WARNING", NULL);
400   ret =
401       (GNUNET_OK ==
402        GNUNET_PROGRAM_run (argc, argv,
403                            "hostlist",
404                            _("GNUnet hostlist server and client"),
405                            options,
406                            &run, NULL)) ? 0 : 1;
407   GNUNET_free ((void*) argv);
408   return ret;
409 }
410
411 /* end of gnunet-daemon-hostlist.c */