paragraph for gnunet devs that don't know how to use the web
[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
19 /**
20  * @file hostlist/gnunet-daemon-hostlist.c
21  * @brief code for bootstrapping via hostlist servers
22  * @author Christian Grothoff
23  */
24 #include "platform.h"
25 #include "gnunet-daemon-hostlist_client.h"
26 #include "gnunet_core_service.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_protocols.h"
29 #include "gnunet_statistics_service.h"
30
31 #if HAVE_MHD
32
33 #include "gnunet-daemon-hostlist_server.h"
34
35 /**
36  * Set if we are allowed to advertise our hostlist to others.
37  */
38 static int advertising;
39
40 /**
41  * Set if the user wants us to run a hostlist server.
42  */
43 static int provide_hostlist;
44
45 /**
46  * Handle to hostlist server's connect handler
47  */
48 static GNUNET_CORE_ConnectEventHandler server_ch;
49
50 #endif
51
52 /**
53  * Set if we are allowed to learn about peers by accessing
54  * hostlist servers.
55  */
56 static int bootstrapping;
57
58 /**
59  * Set if the user allows us to learn about new hostlists
60  * from the network.
61  */
62 static int learning;
63
64 /**
65  * Statistics handle.
66  */
67 static struct GNUNET_STATISTICS_Handle *stats;
68
69 /**
70  * Handle to the core service (NULL until we've connected to it).
71  */
72 static struct GNUNET_CORE_Handle *core;
73
74 /**
75  * Handle to the hostlist client's advertisement handler
76  */
77 static GNUNET_HOSTLIST_UriHandler client_adv_handler;
78
79 /**
80  * Handle to hostlist client's connect handler
81  */
82 static GNUNET_CORE_ConnectEventHandler client_ch;
83
84 /**
85  * Handle to hostlist client's disconnect handler
86  */
87 static GNUNET_CORE_DisconnectEventHandler client_dh;
88
89 GNUNET_NETWORK_STRUCT_BEGIN
90
91 /**
92  * A HOSTLIST_ADV message is used to exchange information about
93  * hostlist advertisements.  This struct is always
94  * followed by the actual url under which the hostlist can be obtained:
95  *
96  * 1) transport-name (0-terminated)
97  * 2) address-length (uint32_t, network byte order; possibly
98  *    unaligned!)
99  * 3) address expiration (GNUNET_TIME_AbsoluteNBO); possibly
100  *    unaligned!)
101  * 4) address (address-length bytes; possibly unaligned!)
102  */
103 struct GNUNET_HOSTLIST_ADV_Message
104 {
105   /**
106    * Type will be GNUNET_MESSAGE_TYPE_HOSTLIST_ADVERTISEMENT.
107    */
108   struct GNUNET_MessageHeader header;
109
110   /**
111    * Always zero (for alignment).
112    */
113   uint32_t reserved GNUNET_PACKED;
114 };
115 GNUNET_NETWORK_STRUCT_END
116
117
118 /**
119  * Our own peer identity.
120  */
121 static struct GNUNET_PeerIdentity me;
122
123
124 /**
125  * Callback invoked once our connection to CORE service is up.
126  *
127  * @param cls NULL
128  * @param my_identity our peer's identity
129  */
130 static void
131 core_init (void *cls,
132            const struct GNUNET_PeerIdentity *my_identity)
133 {
134   me = *my_identity;
135 }
136
137
138 /**
139  * Core handler for p2p hostlist advertisements
140  *
141  * @param cls closure
142  * @param message advertisement message we got
143  * @return #GNUNET_OK if message is well-formed
144  */
145 static int
146 check_advertisement (void *cls,
147                      const struct GNUNET_MessageHeader *message)
148 {
149   size_t size;
150   size_t uri_size;
151   const char *uri;
152
153   size = ntohs (message->size);
154   if (size <= sizeof (struct GNUNET_MessageHeader))
155   {
156     GNUNET_break_op (0);
157     return GNUNET_SYSERR;
158   }
159   uri = (const char *) &message[1];
160   uri_size = size - sizeof (struct GNUNET_MessageHeader);
161   if (uri[uri_size - 1] != '\0')
162   {
163     GNUNET_break_op (0);
164     return GNUNET_SYSERR;
165   }
166   return GNUNET_OK;
167 }
168
169
170 /**
171  * Core handler for p2p hostlist advertisements
172  *
173  * @param cls closure
174  * @param message advertisement message we got
175  * @return #GNUNET_OK on success
176  */
177 static void
178 handle_advertisement (void *cls,
179                       const struct GNUNET_MessageHeader *message)
180 {
181   const char *uri = (const char *) &message[1];
182  
183   GNUNET_assert (NULL != client_adv_handler);
184   (void) (*client_adv_handler) (uri);
185 }
186
187
188 /**
189  * Method called whenever a given peer connects.  Wrapper to call both
190  * client's and server's functions
191  *
192  * @param cls closure
193  * @param peer peer identity this notification is about
194  * @param mq queue for sending messages to @a peer
195  * @return peer
196  */
197 static void *
198 connect_handler (void *cls,
199                  const struct GNUNET_PeerIdentity *peer,
200                  struct GNUNET_MQ_Handle *mq)
201 {
202   if (0 == memcmp (&me,
203                    peer,
204                    sizeof (struct GNUNET_PeerIdentity)))
205     return NULL;
206   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
207               "A new peer connected, notifying client and server\n");
208   if (NULL != client_ch)
209     GNUNET_assert (NULL ==
210                    (*client_ch) (cls,
211                                  peer,
212                                  mq));
213 #if HAVE_MHD
214   if (NULL != server_ch)
215     GNUNET_assert (NULL ==
216                    (*server_ch) (cls,
217                                  peer,
218                                  mq));
219 #endif
220   return (void *) peer;
221 }
222
223
224 /**
225  * Method called whenever a given peer disconnects. Wrapper to call
226  * both client's and server's functions
227  *
228  * @param cls closure
229  * @param peer peer identity this notification is about
230  */
231 static void
232 disconnect_handler (void *cls,
233                     const struct GNUNET_PeerIdentity *peer,
234                     void *internal_cls)
235 {
236   if (0 == memcmp (&me,
237                    peer,
238                    sizeof (struct GNUNET_PeerIdentity)))
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 */