error handling
[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
308   if ((! bootstrapping) && (! learning)
309 #if HAVE_MHD
310       && (! provide_hostlist)
311 #endif
312       )
313   {
314     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
315                 _ (
316                   "None of the functions for the hostlist daemon were enabled.  I have no reason to run!\n"));
317     return;
318   }
319   stats = GNUNET_STATISTICS_create ("hostlist", cfg);
320   if (NULL == stats)
321   {
322     GNUNET_break (0);
323     return;
324   }
325   if (bootstrapping)
326     GNUNET_HOSTLIST_client_start (cfg,
327                                   stats,
328                                   &client_ch,
329                                   &client_dh,
330                                   &client_adv_handler,
331                                   learning);
332   core =
333     GNUNET_CORE_connect (cfg,
334                          NULL,
335                          &core_init,
336                          &connect_handler,
337                          &disconnect_handler,
338                          learning ? learn_handlers : no_learn_handlers);
339
340
341 #if HAVE_MHD
342   if (provide_hostlist)
343     GNUNET_HOSTLIST_server_start (cfg,
344                                   stats,
345                                   core,
346                                   &server_ch,
347                                   advertising);
348 #endif
349   GNUNET_SCHEDULER_add_shutdown (&cleaning_task,
350                                  NULL);
351
352   if (NULL == core)
353   {
354     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
355                 _ ("Failed to connect to `%s' service.\n"), "core");
356     GNUNET_SCHEDULER_shutdown ();
357     return;
358   }
359 }
360
361
362 /**
363  * The main function for the hostlist daemon.
364  *
365  * @param argc number of arguments from the command line
366  * @param argv command line arguments
367  * @return 0 ok, 1 on error
368  */
369 int
370 main (int argc, char *const *argv)
371 {
372   struct GNUNET_GETOPT_CommandLineOption options[] = {
373 #if HAVE_MHD
374     GNUNET_GETOPT_option_flag ('a',
375                                "advertise",
376                                gettext_noop (
377                                  "advertise our hostlist to other peers"),
378                                &advertising),
379 #endif
380     GNUNET_GETOPT_option_flag ('b',
381                                "bootstrap",
382                                gettext_noop (
383                                  "bootstrap using hostlists (it is highly recommended that you always use this option)"),
384                                &bootstrapping),
385     GNUNET_GETOPT_option_flag ('e',
386                                "enable-learning",
387                                gettext_noop (
388                                  "enable learning about hostlist servers from other peers"),
389                                &learning),
390 #if HAVE_MHD
391     GNUNET_GETOPT_option_flag ('p',
392                                "provide-hostlist",
393                                gettext_noop ("provide a hostlist server"),
394                                &provide_hostlist),
395 #endif
396     GNUNET_GETOPT_OPTION_END
397   };
398
399   int ret;
400
401   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
402     return 2;
403
404   GNUNET_log_setup ("hostlist", "WARNING", NULL);
405   ret =
406     (GNUNET_OK ==
407      GNUNET_PROGRAM_run (argc, argv,
408                          "hostlist",
409                          _ ("GNUnet hostlist server and client"),
410                          options,
411                          &run, NULL)) ? 0 : 1;
412   GNUNET_free ((void *) argv);
413   return ret;
414 }
415
416
417 /* end of gnunet-daemon-hostlist.c */