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