7181a913b51c5665871f2df2dd92c02e23cc2034
[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
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      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      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, USA.
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 == memcmp (&me,
205                    peer,
206                    sizeof (struct GNUNET_PeerIdentity)))
207     return NULL;
208   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
209               "A new peer connected, notifying client and server\n");
210   if (NULL != client_ch)
211     GNUNET_assert (NULL ==
212                    (*client_ch) (cls,
213                                  peer,
214                                  mq));
215 #if HAVE_MHD
216   if (NULL != server_ch)
217     GNUNET_assert (NULL ==
218                    (*server_ch) (cls,
219                                  peer,
220                                  mq));
221 #endif
222   return (void *) peer;
223 }
224
225
226 /**
227  * Method called whenever a given peer disconnects. Wrapper to call
228  * both client's and server's functions
229  *
230  * @param cls closure
231  * @param peer peer identity this notification is about
232  */
233 static void
234 disconnect_handler (void *cls,
235                     const struct GNUNET_PeerIdentity *peer,
236                     void *internal_cls)
237 {
238   if (0 == memcmp (&me,
239                    peer,
240                    sizeof (struct GNUNET_PeerIdentity)))
241     return;
242   /* call hostlist client disconnect handler */
243   if (NULL != client_dh)
244     (*client_dh) (cls,
245                   peer,
246                   NULL);
247 }
248
249
250 /**
251  * Last task run during shutdown.  Disconnects us from
252  * the other services.
253  *
254  * @param cls NULL
255  */
256 static void
257 cleaning_task (void *cls)
258 {
259   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
260               "Hostlist daemon is shutting down\n");
261   if (NULL != core)
262   {
263     GNUNET_CORE_disconnecT (core);
264     core = NULL;
265   }
266   if (bootstrapping)
267   {
268     GNUNET_HOSTLIST_client_stop ();
269   }
270 #if HAVE_MHD
271   if (provide_hostlist)
272   {
273     GNUNET_HOSTLIST_server_stop ();
274   }
275 #endif
276   if (NULL != stats)
277   {
278     GNUNET_STATISTICS_destroy (stats,
279                                GNUNET_NO);
280     stats = NULL;
281   }
282 }
283
284
285 /**
286  * Main function that will be run.
287  *
288  * @param cls closure
289  * @param args remaining command-line arguments
290  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
291  * @param cfg configuration
292  */
293 static void
294 run (void *cls,
295      char *const *args,
296      const char *cfgfile,
297      const struct GNUNET_CONFIGURATION_Handle *cfg)
298 {
299   struct GNUNET_MQ_MessageHandler learn_handlers[] = {
300     GNUNET_MQ_hd_var_size (advertisement,
301                            GNUNET_MESSAGE_TYPE_HOSTLIST_ADVERTISEMENT,
302                            struct GNUNET_MessageHeader,
303                            NULL),
304     GNUNET_MQ_handler_end ()
305   };
306   struct GNUNET_MQ_MessageHandler no_learn_handlers[] = {
307     GNUNET_MQ_handler_end ()
308   };
309   if ((! bootstrapping) && (! learning)
310 #if HAVE_MHD
311       && (! provide_hostlist)
312 #endif
313       )
314   {
315     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
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   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
373 #if HAVE_MHD
374     {'a', "advertise", NULL,
375      gettext_noop ("advertise our hostlist to other peers"),
376      GNUNET_NO, &GNUNET_GETOPT_set_one, &advertising},
377 #endif
378     {'b', "bootstrap", NULL,
379      gettext_noop
380      ("bootstrap using hostlists (it is highly recommended that you always use this option)"),
381      GNUNET_NO, &GNUNET_GETOPT_set_one, &bootstrapping},
382     {'e', "enable-learning", NULL,
383      gettext_noop ("enable learning about hostlist servers from other peers"),
384      GNUNET_NO, &GNUNET_GETOPT_set_one, &learning},
385 #if HAVE_MHD
386     {'p', "provide-hostlist", NULL,
387      gettext_noop ("provide a hostlist server"),
388      GNUNET_NO, &GNUNET_GETOPT_set_one, &provide_hostlist},
389 #endif
390     GNUNET_GETOPT_OPTION_END
391   };
392
393   int ret;
394
395   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
396     return 2;
397
398   GNUNET_log_setup ("hostlist", "WARNING", NULL);
399   ret =
400       (GNUNET_OK ==
401        GNUNET_PROGRAM_run (argc, argv,
402                            "hostlist",
403                            _("GNUnet hostlist server and client"),
404                            options,
405                            &run, NULL)) ? 0 : 1;
406   GNUNET_free ((void*) argv);
407   return ret;
408 }
409
410 /* end of gnunet-daemon-hostlist.c */