aboutsummaryrefslogtreecommitdiff
path: root/src/service/hostlist
diff options
context:
space:
mode:
Diffstat (limited to 'src/service/hostlist')
-rw-r--r--src/service/hostlist/.gitignore4
-rw-r--r--src/service/hostlist/Makefile.am82
-rw-r--r--src/service/hostlist/gnunet-daemon-hostlist.c401
-rw-r--r--src/service/hostlist/gnunet-daemon-hostlist.h43
-rw-r--r--src/service/hostlist/gnunet-daemon-hostlist_client.c1878
-rw-r--r--src/service/hostlist/gnunet-daemon-hostlist_client.h70
-rw-r--r--src/service/hostlist/gnunet-daemon-hostlist_server.c915
-rw-r--r--src/service/hostlist/gnunet-daemon-hostlist_server.h61
-rw-r--r--src/service/hostlist/hostlist.conf45
-rw-r--r--src/service/hostlist/hostlists_learn_peer2.filebin0 -> 72 bytes
-rw-r--r--src/service/hostlist/learning_data.conf8
-rw-r--r--src/service/hostlist/meson.build23
-rw-r--r--src/service/hostlist/test_gnunet_daemon_hostlist.c264
-rw-r--r--src/service/hostlist/test_gnunet_daemon_hostlist_data.conf28
-rw-r--r--src/service/hostlist/test_gnunet_daemon_hostlist_learning.c593
-rw-r--r--src/service/hostlist/test_gnunet_daemon_hostlist_peer1.conf44
-rw-r--r--src/service/hostlist/test_gnunet_daemon_hostlist_peer2.conf44
-rw-r--r--src/service/hostlist/test_gnunet_daemon_hostlist_reconnect.c263
-rw-r--r--src/service/hostlist/test_hostlist_defaults.conf18
-rw-r--r--src/service/hostlist/test_learning_adv_peer.conf45
-rw-r--r--src/service/hostlist/test_learning_learn_peer.conf44
-rw-r--r--src/service/hostlist/test_learning_learn_peer2.conf40
22 files changed, 4913 insertions, 0 deletions
diff --git a/src/service/hostlist/.gitignore b/src/service/hostlist/.gitignore
new file mode 100644
index 000000000..b16e3444a
--- /dev/null
+++ b/src/service/hostlist/.gitignore
@@ -0,0 +1,4 @@
1gnunet-daemon-hostlist
2test_gnunet_daemon_hostlist
3test_gnunet_daemon_hostlist_learning
4test_gnunet_daemon_hostlist_reconnect
diff --git a/src/service/hostlist/Makefile.am b/src/service/hostlist/Makefile.am
new file mode 100644
index 000000000..fc9952aa6
--- /dev/null
+++ b/src/service/hostlist/Makefile.am
@@ -0,0 +1,82 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include
3
4pkgcfgdir= $(pkgdatadir)/config.d/
5
6libexecdir= $(pkglibdir)/libexec/
7
8
9if USE_COVERAGE
10 AM_CFLAGS = --coverage -O0
11endif
12
13 HOSTLIST_SERVER_SOURCES = \
14 gnunet-daemon-hostlist_server.c gnunet-daemon-hostlist_server.h
15 GN_LIBMHD = $(MHD_LIBS)
16 GN_CPPMHD = $(MHD_CFLAGS)
17
18libexec_PROGRAMS = \
19 gnunet-daemon-hostlist
20dist_pkgcfg_DATA = \
21 hostlist.conf
22
23gnunet_daemon_hostlist_SOURCES = \
24 gnunet-daemon-hostlist.c gnunet-daemon-hostlist.h \
25 gnunet-daemon-hostlist_client.c gnunet-daemon-hostlist_client.h \
26 $(HOSTLIST_SERVER_SOURCES)
27
28gnunet_daemon_hostlist_LDADD = \
29 $(top_builddir)/src/service/core/libgnunetcore.la \
30 $(top_builddir)/src/lib/hello/libgnunethello.la \
31 $(top_builddir)/src/service/peerstore/libgnunetpeerstore.la \
32 $(top_builddir)/src/service/statistics/libgnunetstatistics.la \
33 $(top_builddir)/src/lib/util/libgnunetutil.la \
34 $(GN_LIBMHD) \
35 @LIBCURL@ \
36 $(GN_LIBINTL)
37
38gnunet_daemon_hostlist_CFLAGS = \
39 $(GN_CPPMHD) \
40 @LIBCURL_CPPFLAGS@ \
41 $(AM_CFLAGS)
42
43#check_PROGRAMS = \
44# test_gnunet_daemon_hostlist \
45# test_gnunet_daemon_hostlist_reconnect \
46# test_gnunet_daemon_hostlist_learning
47
48if ENABLE_TEST_RUN
49AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
50TESTS = \
51 $(check_PROGRAMS)
52endif
53
54#test_gnunet_daemon_hostlist_SOURCES = \
55# test_gnunet_daemon_hostlist.c
56#test_gnunet_daemon_hostlist_LDADD = \
57# $(top_builddir)/src/service/transport/libgnunettransport.la \
58# $(top_builddir)/src/lib/util/libgnunetutil.la
59#
60#test_gnunet_daemon_hostlist_reconnect_SOURCES = \
61# test_gnunet_daemon_hostlist_reconnect.c
62#test_gnunet_daemon_hostlist_reconnect_LDADD = \
63# $(top_builddir)/src/service/transport/libgnunettransport.la \
64# $(top_builddir)/src/lib/util/libgnunetutil.la
65#
66#test_gnunet_daemon_hostlist_learning_SOURCES = \
67# test_gnunet_daemon_hostlist_learning.c
68#test_gnunet_daemon_hostlist_learning_LDADD = \
69# $(top_builddir)/src/service/transport/libgnunettransport.la \
70# $(top_builddir)/src/service/core/libgnunetcore.la \
71# $(top_builddir)/src/service/statistics/libgnunetstatistics.la \
72# $(top_builddir)/src/lib/util/libgnunetutil.la
73
74EXTRA_DIST = \
75 test_hostlist_defaults.conf \
76 test_gnunet_daemon_hostlist_data.conf \
77 test_gnunet_daemon_hostlist_peer1.conf \
78 test_gnunet_daemon_hostlist_peer2.conf \
79 test_learning_adv_peer.conf \
80 test_learning_learn_peer.conf \
81 test_learning_learn_peer2.conf \
82 learning_data.conf
diff --git a/src/service/hostlist/gnunet-daemon-hostlist.c b/src/service/hostlist/gnunet-daemon-hostlist.c
new file mode 100644
index 000000000..54e070f89
--- /dev/null
+++ b/src/service/hostlist/gnunet-daemon-hostlist.c
@@ -0,0 +1,401 @@
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#include "gnunet-daemon-hostlist_server.h"
34
35/**
36 * Set if we are allowed to advertise our hostlist to others.
37 */
38static int advertising;
39
40/**
41 * Set if the user wants us to run a hostlist server.
42 */
43static int provide_hostlist;
44
45/**
46 * Handle to hostlist server's connect handler
47 */
48static GNUNET_CORE_ConnectEventHandler server_ch;
49
50/**
51 * Set if we are allowed to learn about peers by accessing
52 * hostlist servers.
53 */
54static int bootstrapping;
55
56/**
57 * Set if the user allows us to learn about new hostlists
58 * from the network.
59 */
60static int learning;
61
62/**
63 * Statistics handle.
64 */
65static struct GNUNET_STATISTICS_Handle *stats;
66
67/**
68 * Handle to the core service (NULL until we've connected to it).
69 */
70static struct GNUNET_CORE_Handle *core;
71
72/**
73 * Handle to the hostlist client's advertisement handler
74 */
75static GNUNET_HOSTLIST_UriHandler client_adv_handler;
76
77/**
78 * Handle to hostlist client's connect handler
79 */
80static GNUNET_CORE_ConnectEventHandler client_ch;
81
82/**
83 * Handle to hostlist client's disconnect handler
84 */
85static GNUNET_CORE_DisconnectEventHandler client_dh;
86
87GNUNET_NETWORK_STRUCT_BEGIN
88
89/**
90 * A HOSTLIST_ADV message is used to exchange information about
91 * hostlist advertisements. This struct is always
92 * followed by the actual url under which the hostlist can be obtained:
93 *
94 * 1) transport-name (0-terminated)
95 * 2) address-length (uint32_t, network byte order; possibly
96 * unaligned!)
97 * 3) address expiration (GNUNET_TIME_AbsoluteNBO); possibly
98 * unaligned!)
99 * 4) address (address-length bytes; possibly unaligned!)
100 */
101struct GNUNET_HOSTLIST_ADV_Message
102{
103 /**
104 * Type will be GNUNET_MESSAGE_TYPE_HOSTLIST_ADVERTISEMENT.
105 */
106 struct GNUNET_MessageHeader header;
107
108 /**
109 * Always zero (for alignment).
110 */
111 uint32_t reserved GNUNET_PACKED;
112};
113GNUNET_NETWORK_STRUCT_END
114
115
116/**
117 * Our own peer identity.
118 */
119static struct GNUNET_PeerIdentity me;
120
121
122/**
123 * Callback invoked once our connection to CORE service is up.
124 *
125 * @param cls NULL
126 * @param my_identity our peer's identity
127 */
128static void
129core_init (void *cls,
130 const struct GNUNET_PeerIdentity *my_identity)
131{
132 me = *my_identity;
133}
134
135
136/**
137 * Core handler for p2p hostlist advertisements
138 *
139 * @param cls closure
140 * @param message advertisement message we got
141 * @return #GNUNET_OK if message is well-formed
142 */
143static int
144check_advertisement (void *cls,
145 const struct GNUNET_MessageHeader *message)
146{
147 size_t size;
148 size_t uri_size;
149 const char *uri;
150
151 size = ntohs (message->size);
152 if (size <= sizeof(struct GNUNET_MessageHeader))
153 {
154 GNUNET_break_op (0);
155 return GNUNET_SYSERR;
156 }
157 uri = (const char *) &message[1];
158 uri_size = size - sizeof(struct GNUNET_MessageHeader);
159 if (uri[uri_size - 1] != '\0')
160 {
161 GNUNET_break_op (0);
162 return GNUNET_SYSERR;
163 }
164 return GNUNET_OK;
165}
166
167
168/**
169 * Core handler for p2p hostlist advertisements
170 *
171 * @param cls closure
172 * @param message advertisement message we got
173 * @return #GNUNET_OK on success
174 */
175static void
176handle_advertisement (void *cls,
177 const struct GNUNET_MessageHeader *message)
178{
179 const char *uri = (const char *) &message[1];
180
181 GNUNET_assert (NULL != client_adv_handler);
182 (void) (*client_adv_handler)(uri);
183}
184
185
186/**
187 * Method called whenever a given peer connects. Wrapper to call both
188 * client's and server's functions
189 *
190 * @param cls closure
191 * @param peer peer identity this notification is about
192 * @param mq queue for sending messages to @a peer
193 * @return peer
194 */
195static void *
196connect_handler (void *cls,
197 const struct GNUNET_PeerIdentity *peer,
198 struct GNUNET_MQ_Handle *mq)
199{
200 if (0 == GNUNET_memcmp (&me,
201 peer))
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 (NULL != server_ch)
211 GNUNET_assert (NULL ==
212 (*server_ch)(cls,
213 peer,
214 mq));
215 return (void *) peer;
216}
217
218
219/**
220 * Method called whenever a given peer disconnects. Wrapper to call
221 * both client's and server's functions
222 *
223 * @param cls closure
224 * @param peer peer identity this notification is about
225 */
226static void
227disconnect_handler (void *cls,
228 const struct GNUNET_PeerIdentity *peer,
229 void *internal_cls)
230{
231 if (0 == GNUNET_memcmp (&me,
232 peer))
233 return;
234 /* call hostlist client disconnect handler */
235 if (NULL != client_dh)
236 (*client_dh)(cls,
237 peer,
238 NULL);
239}
240
241
242/**
243 * Last task run during shutdown. Disconnects us from
244 * the other services.
245 *
246 * @param cls NULL
247 */
248static void
249cleaning_task (void *cls)
250{
251 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
252 "Hostlist daemon is shutting down\n");
253 if (NULL != core)
254 {
255 GNUNET_CORE_disconnect (core);
256 core = NULL;
257 }
258 if (bootstrapping)
259 {
260 GNUNET_HOSTLIST_client_stop ();
261 }
262 if (provide_hostlist)
263 {
264 GNUNET_HOSTLIST_server_stop ();
265 }
266 if (NULL != stats)
267 {
268 GNUNET_STATISTICS_destroy (stats,
269 GNUNET_NO);
270 stats = NULL;
271 }
272}
273
274
275/**
276 * Main function that will be run.
277 *
278 * @param cls closure
279 * @param args remaining command-line arguments
280 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
281 * @param cfg configuration
282 */
283static void
284run (void *cls,
285 char *const *args,
286 const char *cfgfile,
287 const struct GNUNET_CONFIGURATION_Handle *cfg)
288{
289 struct GNUNET_MQ_MessageHandler learn_handlers[] = {
290 GNUNET_MQ_hd_var_size (advertisement,
291 GNUNET_MESSAGE_TYPE_HOSTLIST_ADVERTISEMENT,
292 struct GNUNET_MessageHeader,
293 NULL),
294 GNUNET_MQ_handler_end ()
295 };
296 struct GNUNET_MQ_MessageHandler no_learn_handlers[] = {
297 GNUNET_MQ_handler_end ()
298 };
299
300 if ((! bootstrapping) && (! learning)
301 && (! provide_hostlist)
302 )
303 {
304 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
305 _ (
306 "None of the functions for the hostlist daemon were enabled. I have no reason to run!\n"));
307 return;
308 }
309 stats = GNUNET_STATISTICS_create ("hostlist", cfg);
310 if (NULL == stats)
311 {
312 GNUNET_break (0);
313 return;
314 }
315 if (bootstrapping)
316 GNUNET_HOSTLIST_client_start (cfg,
317 stats,
318 &client_ch,
319 &client_dh,
320 &client_adv_handler,
321 learning);
322 core =
323 GNUNET_CORE_connect (cfg,
324 NULL,
325 &core_init,
326 &connect_handler,
327 &disconnect_handler,
328 learning ? learn_handlers : no_learn_handlers);
329
330
331 if (provide_hostlist)
332 GNUNET_HOSTLIST_server_start (cfg,
333 stats,
334 core,
335 &server_ch,
336 advertising);
337 GNUNET_SCHEDULER_add_shutdown (&cleaning_task,
338 NULL);
339
340 if (NULL == core)
341 {
342 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
343 _ ("Failed to connect to `%s' service.\n"), "core");
344 GNUNET_SCHEDULER_shutdown ();
345 return;
346 }
347}
348
349
350/**
351 * The main function for the hostlist daemon.
352 *
353 * @param argc number of arguments from the command line
354 * @param argv command line arguments
355 * @return 0 ok, 1 on error
356 */
357int
358main (int argc, char *const *argv)
359{
360 struct GNUNET_GETOPT_CommandLineOption options[] = {
361 GNUNET_GETOPT_option_flag ('a',
362 "advertise",
363 gettext_noop (
364 "advertise our hostlist to other peers"),
365 &advertising),
366 GNUNET_GETOPT_option_flag ('b',
367 "bootstrap",
368 gettext_noop (
369 "bootstrap using hostlists (it is highly recommended that you always use this option)"),
370 &bootstrapping),
371 GNUNET_GETOPT_option_flag ('e',
372 "enable-learning",
373 gettext_noop (
374 "enable learning about hostlist servers from other peers"),
375 &learning),
376 GNUNET_GETOPT_option_flag ('p',
377 "provide-hostlist",
378 gettext_noop ("provide a hostlist server"),
379 &provide_hostlist),
380 GNUNET_GETOPT_OPTION_END
381 };
382
383 int ret;
384
385 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
386 return 2;
387
388 GNUNET_log_setup ("hostlist", "WARNING", NULL);
389 ret =
390 (GNUNET_OK ==
391 GNUNET_PROGRAM_run (argc, argv,
392 "hostlist",
393 _ ("GNUnet hostlist server and client"),
394 options,
395 &run, NULL)) ? 0 : 1;
396 GNUNET_free_nz ((void *) argv);
397 return ret;
398}
399
400
401/* end of gnunet-daemon-hostlist.c */
diff --git a/src/service/hostlist/gnunet-daemon-hostlist.h b/src/service/hostlist/gnunet-daemon-hostlist.h
new file mode 100644
index 000000000..aec413fe6
--- /dev/null
+++ b/src/service/hostlist/gnunet-daemon-hostlist.h
@@ -0,0 +1,43 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009 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.h
23 * @brief common internal definitions for hostlist daemon
24 * @author Matthias Wachs
25 */
26#include <stdlib.h>
27#include "platform.h"
28#include "gnunet_core_service.h"
29#include "gnunet_protocols.h"
30#include "gnunet_statistics_service.h"
31#include "gnunet_util_lib.h"
32
33/**
34 * How long can hostlist URLs be?
35 */
36#define MAX_URL_LEN 1000
37
38/**
39 * How many bytes do we download at most from a hostlist server?
40 */
41#define MAX_BYTES_PER_HOSTLISTS 500000
42
43/* end of gnunet-daemon-hostlist.h */
diff --git a/src/service/hostlist/gnunet-daemon-hostlist_client.c b/src/service/hostlist/gnunet-daemon-hostlist_client.c
new file mode 100644
index 000000000..95891a1ad
--- /dev/null
+++ b/src/service/hostlist/gnunet-daemon-hostlist_client.c
@@ -0,0 +1,1878 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2001-2010, 2014, 2016 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 * @file hostlist/gnunet-daemon-hostlist_client.c
22 * @brief hostlist support. Downloads HELLOs via HTTP.
23 * @author Christian Grothoff
24 * @author Matthias Wachs
25 */
26#include "platform.h"
27#include "gnunet-daemon-hostlist_client.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_statistics_service.h"
30#include "gnunet_peerstore_service.h"
31#include "gnunet-daemon-hostlist.h"
32/* Just included for the right curl.h */
33#include "gnunet_curl_lib.h"
34
35
36/**
37 * Number of connections that we must have to NOT download
38 * hostlists anymore.
39 */
40#define MIN_CONNECTIONS 4
41
42/**
43 * Maximum number of hostlist that are saved
44 */
45#define MAX_NUMBER_HOSTLISTS 30
46
47/**
48 * Time interval hostlists are saved to disk
49 */
50#define SAVING_INTERVAL \
51 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 30)
52
53/**
54 * Time interval between two hostlist tests
55 */
56#define TESTING_INTERVAL \
57 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 3)
58
59/**
60 * Time interval for download dispatcher before a download is re-scheduled
61 */
62#define WAITING_INTERVAL \
63 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
64
65/**
66 * Defines concerning the hostlist quality metric
67 */
68
69/**
70 * Initial quality of a new created hostlist
71 */
72#define HOSTLIST_INITIAL 10000
73
74/**
75 * Value subtracted each time a hostlist download fails
76 */
77#define HOSTLIST_FAILED_DOWNLOAD 100
78
79/**
80 * Value added each time a hostlist download is successful
81 */
82#define HOSTLIST_SUCCESSFUL_DOWNLOAD 100
83
84/**
85 * Value added for each valid HELLO received during a hostlist download
86 */
87#define HOSTLIST_SUCCESSFUL_HELLO 1
88
89
90/**
91 * A single hostlist obtained by hostlist advertisements
92 */
93struct Hostlist
94{
95 /**
96 * previous entry, used to manage entries in a double linked list
97 */
98 struct Hostlist *prev;
99
100 /**
101 * next entry, used to manage entries in a double linked list
102 */
103 struct Hostlist *next;
104
105 /**
106 * URI where hostlist can be obtained
107 */
108 const char *hostlist_uri;
109
110 /**
111 * Value describing the quality of the hostlist, the bigger the better but (should) never < 0
112 * used for deciding which hostlist is replaced if MAX_NUMBER_HOSTLISTS in data structure is reached
113 * initial value = HOSTLIST_INITIAL
114 * increased every successful download by HOSTLIST_SUCCESSFULL_DOWNLOAD
115 * increased every successful download by number of obtained HELLO messages
116 * decreased every failed download by HOSTLIST_SUCCESSFULL_DOWNLOAD
117 */
118 uint64_t quality;
119
120 /**
121 * Time the hostlist advertisement was received and the entry was created
122 */
123 struct GNUNET_TIME_Absolute time_creation;
124
125 /**
126 * Last time the hostlist was obtained
127 */
128 struct GNUNET_TIME_Absolute time_last_usage;
129
130 /**
131 * Number of HELLO messages obtained during last download
132 */
133 uint32_t hello_count;
134
135 /**
136 * Number of times the hostlist was successfully obtained
137 */
138 uint32_t times_used;
139};
140
141/**
142* Context for a add hello uri request.
143*/
144struct StoreHelloEntry
145{
146 /**
147 * Kept (also) in a DLL.
148 */
149 struct StoreHelloEntry *prev;
150
151 /**
152 * Kept (also) in a DLL.
153 */
154 struct StoreHelloEntry *next;
155
156 /**
157 * Store hello ctx
158 */
159 struct GNUNET_PEERSTORE_StoreHelloContext *sc;
160};
161
162/**
163 * Our configuration.
164 */
165static const struct GNUNET_CONFIGURATION_Handle *cfg;
166
167/**
168 * Statistics handle.
169 */
170static struct GNUNET_STATISTICS_Handle *stats;
171
172/**
173 * Proxy hostname or ip we are using (can be NULL).
174 */
175static char *proxy;
176
177/**
178 * Proxy username we are using (can be NULL).
179 */
180static char *proxy_username;
181
182/**
183 * Proxy password we are using (can be NULL).
184 */
185static char *proxy_password;
186
187/**
188 * Proxy type we are using (can be NULL).
189 */
190static curl_proxytype proxy_type;
191
192/**
193 * Number of bytes valid in 'download_buffer'.
194 */
195static size_t download_pos;
196
197/**
198 * Current URL that we are using.
199 */
200static char *current_url;
201
202/**
203 * Current CURL handle.
204 */
205static CURL *curl;
206
207/**
208 * Current multi-CURL handle.
209 */
210static CURLM *multi;
211
212/**
213 * How many bytes did we download from the current hostlist URL?
214 */
215static uint32_t stat_bytes_downloaded;
216
217/**
218 * Amount of time we wait between hostlist downloads.
219 */
220static struct GNUNET_TIME_Relative hostlist_delay;
221
222/**
223 * ID of the task, checking if hostlist download should take plate
224 */
225static struct GNUNET_SCHEDULER_Task *ti_check_download;
226
227/**
228 * ID of the task downloading the hostlist
229 */
230static struct GNUNET_SCHEDULER_Task *ti_download;
231
232/**
233 * ID of the task saving the hostlsit in a regular interval
234 */
235static struct GNUNET_SCHEDULER_Task *ti_saving_task;
236
237/**
238 * ID of the task called to initiate a download
239 */
240static struct GNUNET_SCHEDULER_Task *ti_download_dispatcher_task;
241
242/**
243 * ID of the task controlling the locking between two hostlist tests
244 */
245static struct GNUNET_SCHEDULER_Task *ti_testing_intervall_task;
246
247/**
248 * At what time MUST the current hostlist request be done?
249 */
250static struct GNUNET_TIME_Absolute end_time;
251
252/**
253 * Head of the linkd list to store the store context for hellos.
254 */
255static struct StoreHelloEntry *she_head;
256
257/**
258 * Tail of the linkd list to store the store context for hellos.
259 */
260static struct StoreHelloEntry *she_tail;
261
262/**
263 * Head of the linked list used to store hostlists
264 */
265static struct Hostlist *linked_list_head;
266
267/**
268 * Tail of the linked list used to store hostlists
269 */
270static struct Hostlist *linked_list_tail;
271
272/**
273 * Current hostlist used for downloading
274 */
275static struct Hostlist *current_hostlist;
276
277/**
278 * Size of the linked list used to store hostlists
279 */
280static unsigned int linked_list_size;
281
282/**
283 * Head of the linked list used to store hostlists
284 */
285static struct Hostlist *hostlist_to_test;
286
287/**
288 * Handle for our statistics GET operation.
289 */
290static struct GNUNET_STATISTICS_GetHandle *sget;
291
292/**
293 * Set to GNUNET_YES if the current URL had some problems.
294 */
295static int stat_bogus_url;
296
297/**
298 * Value controlling if a hostlist is tested at the moment
299 */
300static int stat_testing_hostlist;
301
302/**
303 * Value controlling if a hostlist testing is allowed at the moment
304 */
305static int stat_testing_allowed;
306
307/**
308 * Value controlling if a hostlist download is running at the moment
309 */
310static int stat_download_in_progress;
311
312/**
313 * Value saying if a preconfigured bootstrap server is used
314 */
315static unsigned int stat_use_bootstrap;
316
317/**
318 * Set if we are allowed to learn new hostlists and use them
319 */
320static int stat_learning;
321
322/**
323 * Value saying if hostlist download was successful
324 */
325static unsigned int stat_download_successful;
326
327/**
328 * Value saying how many valid HELLO messages were obtained during download
329 */
330static unsigned int stat_hellos_obtained;
331
332/**
333 * Number of active connections (according to core service).
334 */
335static unsigned int stat_connection_count;
336
337/**
338 * Handle to the PEERSTORE service.
339 */
340static struct GNUNET_PEERSTORE_Handle *peerstore;
341
342
343static void
344shc_cont (void *cls, int success)
345{
346 struct StoreHelloEntry *she = cls;
347
348 she->sc = NULL;
349 if (GNUNET_YES == success)
350 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
351 "Hostlist entry stored successfully!\n");
352 else
353 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
354 "Error storing hostlist entry!\n");
355 GNUNET_CONTAINER_DLL_remove (she_head, she_tail, she);
356 GNUNET_free (she);
357}
358
359
360/**
361 * Process downloaded bits by calling callback on each HELLO.
362 *
363 * @param ptr buffer with downloaded data
364 * @param size size of a record
365 * @param nmemb number of records downloaded
366 * @param ctx unused
367 * @return number of bytes that were processed (always size*nmemb)
368 */
369static size_t
370callback_download (void *ptr, size_t size, size_t nmemb, void *ctx)
371{
372 static char download_buffer[GNUNET_MAX_MESSAGE_SIZE - 1];
373 struct StoreHelloEntry *she;
374 const char *cbuf = ptr;
375 const struct GNUNET_MessageHeader *msg;
376 size_t total;
377 size_t cpy;
378 size_t left;
379 uint16_t msize;
380
381 total = size * nmemb;
382 stat_bytes_downloaded += total;
383 if ((total == 0) || (stat_bogus_url))
384 {
385 return total; /* ok, no data or bogus data */
386 }
387
388 GNUNET_STATISTICS_update (stats,
389 gettext_noop (
390 "# bytes downloaded from hostlist servers"),
391 (int64_t) total,
392 GNUNET_NO);
393 left = total;
394 while ((left > 0) || (download_pos > 0))
395 {
396 cpy = GNUNET_MIN (left, GNUNET_MAX_MESSAGE_SIZE - 1 - download_pos);
397 GNUNET_memcpy (&download_buffer[download_pos], cbuf, cpy);
398 cbuf += cpy;
399 download_pos += cpy;
400 left -= cpy;
401 if (download_pos < sizeof(struct GNUNET_MessageHeader))
402 {
403 GNUNET_assert (0 == left);
404 break;
405 }
406 msg = (const struct GNUNET_MessageHeader *) download_buffer;
407 msize = ntohs (msg->size);
408 if (msize < sizeof(struct GNUNET_MessageHeader))
409 {
410 GNUNET_STATISTICS_update (
411 stats,
412 gettext_noop ("# invalid HELLOs downloaded from hostlist servers"),
413 1,
414 GNUNET_NO);
415 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
416 _ ("Invalid `%s' message received from hostlist at `%s'\n"),
417 "HELLO",
418 current_url);
419 stat_hellos_obtained++;
420 stat_bogus_url = 1;
421 return total;
422 }
423 if (download_pos < msize)
424 {
425 GNUNET_assert (left == 0);
426 break;
427 }
428 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
429 "Received valid `%s' message from hostlist server.\n",
430 "HELLO");
431 GNUNET_STATISTICS_update (
432 stats,
433 gettext_noop ("# valid HELLOs downloaded from hostlist servers"),
434 1,
435 GNUNET_NO);
436 stat_hellos_obtained++;
437 she = GNUNET_new (struct StoreHelloEntry);
438 she->sc = GNUNET_PEERSTORE_hello_add (peerstore,
439 msg,
440 shc_cont,
441 she);
442 if (NULL != she->sc)
443 {
444 GNUNET_CONTAINER_DLL_insert (she_head, she_tail, she);
445 }
446 else
447 GNUNET_free (she);
448 memmove (download_buffer, &download_buffer[msize], download_pos - msize);
449 download_pos -= msize;
450 }
451 return total;
452}
453
454
455/**
456 * Obtain a hostlist URL that we should use.
457 *
458 * @return NULL if there is no URL available
459 */
460static char *
461get_bootstrap_server ()
462{
463 char *servers;
464 char *ret;
465 size_t urls;
466 size_t pos;
467
468 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg,
469 "HOSTLIST",
470 "SERVERS",
471 &servers))
472 {
473 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,
474 "hostlist",
475 "SERVERS");
476 return NULL;
477 }
478
479 urls = 0;
480 if (strlen (servers) > 0)
481 {
482 urls++;
483 pos = strlen (servers) - 1;
484 while (pos > 0)
485 {
486 if (servers[pos] == ' ')
487 urls++;
488 pos--;
489 }
490 }
491 if (urls == 0)
492 {
493 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,
494 "hostlist",
495 "SERVERS");
496 GNUNET_free (servers);
497 return NULL;
498 }
499
500 urls = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, urls) + 1;
501 pos = strlen (servers) - 1;
502 while (pos > 0)
503 {
504 if (servers[pos] == ' ')
505 {
506 urls--;
507 servers[pos] = '\0';
508 }
509 if (urls == 0)
510 {
511 pos++;
512 break;
513 }
514 pos--;
515 }
516 ret = GNUNET_strdup (&servers[pos]);
517 GNUNET_free (servers);
518 return ret;
519}
520
521
522/**
523 * Method deciding if a preconfigured or advertisied hostlist is used on a 50:50 ratio
524 * @return uri to use, NULL if there is no URL available
525 */
526static char *
527download_get_url ()
528{
529 uint32_t index;
530 unsigned int counter;
531 struct Hostlist *pos;
532
533 if (GNUNET_NO == stat_learning)
534 {
535 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
536 "Using preconfigured bootstrap server\n");
537 current_hostlist = NULL;
538 return get_bootstrap_server ();
539 }
540
541 if ((GNUNET_YES == stat_testing_hostlist) && (NULL != hostlist_to_test))
542 {
543 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
544 "Testing new advertised hostlist if it is obtainable\n");
545 current_hostlist = hostlist_to_test;
546 return GNUNET_strdup (hostlist_to_test->hostlist_uri);
547 }
548
549 if ((GNUNET_YES == stat_use_bootstrap) || (linked_list_size == 0))
550 {
551 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
552 "Using preconfigured bootstrap server\n");
553 current_hostlist = NULL;
554 return get_bootstrap_server ();
555 }
556 index =
557 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, linked_list_size);
558 counter = 0;
559 pos = linked_list_head;
560 while (counter < index)
561 {
562 pos = pos->next;
563 counter++;
564 }
565 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
566 "Using learned hostlist `%s'\n",
567 pos->hostlist_uri);
568 current_hostlist = pos;
569 return GNUNET_strdup (pos->hostlist_uri);
570}
571
572
573#define CURL_EASY_SETOPT(c, a, b) \
574 do \
575 { \
576 ret = curl_easy_setopt (c, a, b); \
577 if (CURLE_OK != ret) \
578 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, \
579 _ ("%s failed at %s:%d: `%s'\n"), \
580 "curl_easy_setopt", \
581 __FILE__, \
582 __LINE__, \
583 curl_easy_strerror (ret)); \
584 } while (0)
585
586
587/**
588 * Method to save hostlist to a file during hostlist client shutdown
589 *
590 * @param shutdown set if called because of shutdown, entries in linked list will be destroyed
591 */
592static void
593save_hostlist_file (int shutdown);
594
595
596/**
597 * Add val2 to val1 with overflow check
598 *
599 * @param val1 value 1
600 * @param val2 value 2
601 * @return result
602 */
603static uint64_t
604checked_add (uint64_t val1, uint64_t val2)
605{
606 static uint64_t temp;
607 static uint64_t maxv;
608
609 maxv = 0;
610 maxv--;
611
612 temp = val1 + val2;
613 if (temp < val1)
614 return maxv;
615 return temp;
616}
617
618
619/**
620 * Subtract val2 from val1 with underflow check
621 *
622 * @param val1 value 1
623 * @param val2 value 2
624 * @return result
625 */
626static uint64_t
627checked_sub (uint64_t val1, uint64_t val2)
628{
629 if (val1 <= val2)
630 return 0;
631 return(val1 - val2);
632}
633
634
635/**
636 * Method to check if a URI is in hostlist linked list
637 *
638 * @param uri uri to check
639 * @return #GNUNET_YES if existing in linked list, #GNUNET_NO if not
640 */
641static int
642linked_list_contains (const char *uri)
643{
644 struct Hostlist *pos;
645
646 pos = linked_list_head;
647 while (pos != NULL)
648 {
649 if (0 == strcmp (pos->hostlist_uri, uri))
650 return GNUNET_YES;
651 pos = pos->next;
652 }
653 return GNUNET_NO;
654}
655
656
657/**
658 * Method returning the hostlist element with the lowest quality in the datastore
659 * @return hostlist with lowest quality
660 */
661static struct Hostlist *
662linked_list_get_lowest_quality ()
663{
664 struct Hostlist *pos;
665 struct Hostlist *lowest;
666
667 if (linked_list_size == 0)
668 return NULL;
669 lowest = linked_list_head;
670 pos = linked_list_head->next;
671 while (pos != NULL)
672 {
673 if (pos->quality < lowest->quality)
674 lowest = pos;
675 pos = pos->next;
676 }
677 return lowest;
678}
679
680
681/**
682 * Method to insert a hostlist into the datastore. If datastore
683 * contains maximum number of elements, the elements with lowest
684 * quality is dismissed
685 */
686static void
687insert_hostlist ()
688{
689 struct Hostlist *lowest_quality;
690
691 if (MAX_NUMBER_HOSTLISTS <= linked_list_size)
692 {
693 /* No free entries available, replace existing entry */
694 lowest_quality = linked_list_get_lowest_quality ();
695 GNUNET_assert (lowest_quality != NULL);
696 GNUNET_log (
697 GNUNET_ERROR_TYPE_DEBUG,
698 "Removing hostlist with URI `%s' which has the worst quality of all (%llu)\n",
699 lowest_quality->hostlist_uri,
700 (unsigned long long) lowest_quality->quality);
701 GNUNET_CONTAINER_DLL_remove (linked_list_head,
702 linked_list_tail,
703 lowest_quality);
704 linked_list_size--;
705 GNUNET_free (lowest_quality);
706 }
707 GNUNET_CONTAINER_DLL_insert (linked_list_head,
708 linked_list_tail,
709 hostlist_to_test);
710 linked_list_size++;
711 GNUNET_STATISTICS_set (stats,
712 gettext_noop ("# advertised hostlist URIs"),
713 linked_list_size,
714 GNUNET_NO);
715 stat_testing_hostlist = GNUNET_NO;
716}
717
718
719/**
720 * Method updating hostlist statistics
721 */
722static void
723update_hostlist ()
724{
725 char *stat;
726
727 if (((stat_use_bootstrap == GNUNET_NO) && (NULL != current_hostlist)) ||
728 ((stat_testing_hostlist == GNUNET_YES) && (NULL != current_hostlist)))
729 {
730 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
731 "Updating hostlist statics for URI `%s'\n",
732 current_hostlist->hostlist_uri);
733 current_hostlist->hello_count = stat_hellos_obtained;
734 current_hostlist->time_last_usage = GNUNET_TIME_absolute_get ();
735 current_hostlist->quality =
736 checked_add (current_hostlist->quality,
737 (stat_hellos_obtained * HOSTLIST_SUCCESSFUL_HELLO));
738 if (GNUNET_YES == stat_download_successful)
739 {
740 current_hostlist->times_used++;
741 current_hostlist->quality =
742 checked_add (current_hostlist->quality, HOSTLIST_SUCCESSFUL_DOWNLOAD);
743 GNUNET_asprintf (&stat,
744 gettext_noop ("# advertised URI `%s' downloaded"),
745 current_hostlist->hostlist_uri);
746
747 GNUNET_STATISTICS_update (stats, stat, 1, GNUNET_YES);
748 GNUNET_free (stat);
749 }
750 else
751 current_hostlist->quality =
752 checked_sub (current_hostlist->quality, HOSTLIST_FAILED_DOWNLOAD);
753 }
754 current_hostlist = NULL;
755 /* Alternating the usage of preconfigured and learned hostlists */
756
757 if (stat_testing_hostlist == GNUNET_YES)
758 return;
759
760 if (GNUNET_YES == stat_learning)
761 {
762 if (stat_use_bootstrap == GNUNET_YES)
763 stat_use_bootstrap = GNUNET_NO;
764 else
765 stat_use_bootstrap = GNUNET_YES;
766 }
767 else
768 stat_use_bootstrap = GNUNET_YES;
769}
770
771
772/**
773 * Clean up the state from the task that downloaded the
774 * hostlist and schedule the next task.
775 */
776static void
777clean_up ()
778{
779 CURLMcode mret;
780
781 if ((stat_testing_hostlist == GNUNET_YES) &&
782 (GNUNET_NO == stat_download_successful) && (NULL != hostlist_to_test))
783 {
784 GNUNET_log (
785 GNUNET_ERROR_TYPE_INFO,
786 _ (
787 "Advertised hostlist with URI `%s' could not be downloaded. Advertised URI gets dismissed.\n"),
788 hostlist_to_test->hostlist_uri);
789 }
790
791 if (stat_testing_hostlist == GNUNET_YES)
792 {
793 stat_testing_hostlist = GNUNET_NO;
794 }
795 if (NULL != hostlist_to_test)
796 {
797 GNUNET_free (hostlist_to_test);
798 hostlist_to_test = NULL;
799 }
800
801 if (NULL != multi)
802 {
803 mret = curl_multi_remove_handle (multi, curl);
804 if (mret != CURLM_OK)
805 {
806 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
807 _ ("%s failed at %s:%d: `%s'\n"),
808 "curl_multi_remove_handle",
809 __FILE__,
810 __LINE__,
811 curl_multi_strerror (mret));
812 }
813 mret = curl_multi_cleanup (multi);
814 if (mret != CURLM_OK)
815 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
816 _ ("%s failed at %s:%d: `%s'\n"),
817 "curl_multi_cleanup",
818 __FILE__,
819 __LINE__,
820 curl_multi_strerror (mret));
821 multi = NULL;
822 }
823 if (NULL != curl)
824 {
825 curl_easy_cleanup (curl);
826 curl = NULL;
827 }
828 GNUNET_free (current_url);
829 current_url = NULL;
830 stat_bytes_downloaded = 0;
831 stat_download_in_progress = GNUNET_NO;
832}
833
834
835/**
836 * Task that is run when we are ready to receive more data from the hostlist
837 * server.
838 *
839 * @param cls closure, unused
840 */
841static void
842task_download (void *cls);
843
844
845/**
846 * Ask CURL for the select set and then schedule the
847 * receiving task with the scheduler.
848 */
849static void
850download_prepare ()
851{
852 CURLMcode mret;
853 fd_set rs;
854 fd_set ws;
855 fd_set es;
856 int max;
857 struct GNUNET_NETWORK_FDSet *grs;
858 struct GNUNET_NETWORK_FDSet *gws;
859 long timeout;
860 struct GNUNET_TIME_Relative rtime;
861
862 max = -1;
863 FD_ZERO (&rs);
864 FD_ZERO (&ws);
865 FD_ZERO (&es);
866 mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
867 if (mret != CURLM_OK)
868 {
869 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
870 _ ("%s failed at %s:%d: `%s'\n"),
871 "curl_multi_fdset",
872 __FILE__,
873 __LINE__,
874 curl_multi_strerror (mret));
875 clean_up ();
876 return;
877 }
878 mret = curl_multi_timeout (multi, &timeout);
879 if (mret != CURLM_OK)
880 {
881 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
882 _ ("%s failed at %s:%d: `%s'\n"),
883 "curl_multi_timeout",
884 __FILE__,
885 __LINE__,
886 curl_multi_strerror (mret));
887 clean_up ();
888 return;
889 }
890 rtime = GNUNET_TIME_relative_min (
891 GNUNET_TIME_absolute_get_remaining (end_time),
892 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, timeout));
893 grs = GNUNET_NETWORK_fdset_create ();
894 gws = GNUNET_NETWORK_fdset_create ();
895 GNUNET_NETWORK_fdset_copy_native (grs, &rs, max + 1);
896 GNUNET_NETWORK_fdset_copy_native (gws, &ws, max + 1);
897 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
898 "Scheduling task for hostlist download using cURL\n");
899 ti_download = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
900 rtime,
901 grs,
902 gws,
903 &task_download,
904 multi);
905 GNUNET_NETWORK_fdset_destroy (gws);
906 GNUNET_NETWORK_fdset_destroy (grs);
907}
908
909
910static void
911task_download (void *cls)
912{
913 int running;
914 struct CURLMsg *msg;
915 CURLMcode mret;
916
917 ti_download = NULL;
918 if (0 == GNUNET_TIME_absolute_get_remaining (end_time).rel_value_us)
919 {
920 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
921 _ ("Timeout trying to download hostlist from `%s'\n"),
922 current_url);
923 update_hostlist ();
924 clean_up ();
925 return;
926 }
927 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
928 "Ready for processing hostlist client request\n");
929 do
930 {
931 running = 0;
932 if (stat_bytes_downloaded > MAX_BYTES_PER_HOSTLISTS)
933 {
934 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
935 _ (
936 "Download limit of %u bytes exceeded, stopping download\n"),
937 MAX_BYTES_PER_HOSTLISTS);
938 clean_up ();
939 return;
940 }
941 mret = curl_multi_perform (multi, &running);
942 if (running == 0)
943 {
944 do
945 {
946 msg = curl_multi_info_read (multi, &running);
947 GNUNET_break (msg != NULL);
948 if (msg == NULL)
949 break;
950 switch (msg->msg)
951 {
952 case CURLMSG_DONE:
953 if ((msg->data.result != CURLE_OK) &&
954 (msg->data.result != CURLE_GOT_NOTHING))
955 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
956 _ ("Download of hostlist from `%s' failed: `%s'\n"),
957 current_url,
958 curl_easy_strerror (msg->data.result));
959 else
960 {
961 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
962 _ ("Download of hostlist `%s' completed.\n"),
963 current_url);
964 stat_download_successful = GNUNET_YES;
965 update_hostlist ();
966 if (GNUNET_YES == stat_testing_hostlist)
967 {
968 GNUNET_log (
969 GNUNET_ERROR_TYPE_INFO,
970 _ ("Adding successfully tested hostlist `%s' datastore.\n"),
971 current_url);
972 insert_hostlist ();
973 hostlist_to_test = NULL;
974 stat_testing_hostlist = GNUNET_NO;
975 }
976 }
977 clean_up ();
978 return;
979
980 default:
981 break;
982 }
983 }
984 while ((running > 0));
985 }
986 }
987 while (mret == CURLM_CALL_MULTI_PERFORM);
988
989 if (mret != CURLM_OK)
990 {
991 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
992 _ ("%s failed at %s:%d: `%s'\n"),
993 "curl_multi_perform",
994 __FILE__,
995 __LINE__,
996 curl_multi_strerror (mret));
997 clean_up ();
998 }
999 download_prepare ();
1000}
1001
1002
1003/**
1004 * Main function that will download a hostlist and process its
1005 * data.
1006 */
1007static void
1008download_hostlist ()
1009{
1010 CURLcode ret;
1011 CURLMcode mret;
1012
1013
1014 current_url = download_get_url ();
1015 if (current_url == NULL)
1016 return;
1017 curl = curl_easy_init ();
1018 multi = NULL;
1019 if (curl == NULL)
1020 {
1021 GNUNET_break (0);
1022 clean_up ();
1023 return;
1024 }
1025 GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
1026 _ ("Bootstrapping using hostlist at `%s'.\n"),
1027 current_url);
1028
1029 stat_download_in_progress = GNUNET_YES;
1030 stat_download_successful = GNUNET_NO;
1031 stat_hellos_obtained = 0;
1032 stat_bytes_downloaded = 0;
1033
1034 GNUNET_STATISTICS_update (stats,
1035 gettext_noop ("# hostlist downloads initiated"),
1036 1,
1037 GNUNET_NO);
1038 if (NULL != proxy)
1039 {
1040 CURL_EASY_SETOPT (curl, CURLOPT_PROXY, proxy);
1041 CURL_EASY_SETOPT (curl, CURLOPT_PROXYTYPE, proxy_type);
1042 if (NULL != proxy_username)
1043 CURL_EASY_SETOPT (curl, CURLOPT_PROXYUSERNAME, proxy_username);
1044 if (NULL != proxy_password)
1045 CURL_EASY_SETOPT (curl, CURLOPT_PROXYPASSWORD, proxy_password);
1046 }
1047 download_pos = 0;
1048 stat_bogus_url = 0;
1049 CURL_EASY_SETOPT (curl, CURLOPT_WRITEFUNCTION, &callback_download);
1050 if (ret != CURLE_OK)
1051 {
1052 clean_up ();
1053 return;
1054 }
1055 CURL_EASY_SETOPT (curl, CURLOPT_WRITEDATA, NULL);
1056 if (ret != CURLE_OK)
1057 {
1058 clean_up ();
1059 return;
1060 }
1061 CURL_EASY_SETOPT (curl, CURLOPT_FOLLOWLOCATION, 1);
1062#ifdef CURLOPT_REDIR_PROTOCOLS_STR
1063 if (0 == strncasecmp (current_url, "https://", strlen ("https://")))
1064 GNUNET_assert (CURLE_OK == curl_easy_setopt (curl,
1065 CURLOPT_REDIR_PROTOCOLS_STR,
1066 "https"));
1067 else
1068 GNUNET_assert (CURLE_OK == curl_easy_setopt (curl,
1069 CURLOPT_REDIR_PROTOCOLS_STR,
1070 "http,https"));
1071#else
1072#ifdef CURLOPT_REDIR_PROTOCOLS
1073 if (0 == strncasecmp (current_url, "https://", strlen ("https://")))
1074 GNUNET_assert (CURLE_OK == curl_easy_setopt (curl, CURLOPT_REDIR_PROTOCOLS,
1075 CURLPROTO_HTTPS));
1076 else
1077 GNUNET_assert (CURLE_OK == curl_easy_setopt (curl, CURLOPT_REDIR_PROTOCOLS,
1078 CURLPROTO_HTTP
1079 | CURLPROTO_HTTPS));
1080#endif
1081#endif
1082#ifdef CURLOPT_PROTOCOLS_STR
1083 if (0 == strncasecmp (current_url, "https://", strlen ("https://")))
1084 GNUNET_assert (CURLE_OK == curl_easy_setopt (curl, CURLOPT_PROTOCOLS_STR,
1085 "https"));
1086 else
1087 GNUNET_assert (CURLE_OK == curl_easy_setopt (curl, CURLOPT_PROTOCOLS_STR,
1088 "http,https"));
1089#else
1090#ifdef CURLOPT_PROTOCOLS
1091 if (0 == strncasecmp (current_url, "https://", strlen ("https://")))
1092 GNUNET_assert (CURLE_OK == curl_easy_setopt (curl, CURLOPT_PROTOCOLS,
1093 CURLPROTO_HTTPS));
1094 else
1095 GNUNET_assert (CURLE_OK == curl_easy_setopt (curl, CURLOPT_PROTOCOLS,
1096 CURLPROTO_HTTP
1097 | CURLPROTO_HTTPS));
1098#endif
1099#endif
1100 CURL_EASY_SETOPT (curl, CURLOPT_MAXREDIRS, 4);
1101 /* no need to abort if the above failed */
1102 CURL_EASY_SETOPT (curl, CURLOPT_URL, current_url);
1103 if (ret != CURLE_OK)
1104 {
1105 clean_up ();
1106 return;
1107 }
1108 CURL_EASY_SETOPT (curl, CURLOPT_FAILONERROR, 1);
1109#if 0
1110 CURL_EASY_SETOPT (curl, CURLOPT_VERBOSE, 1);
1111#endif
1112 CURL_EASY_SETOPT (curl, CURLOPT_BUFFERSIZE, GNUNET_MAX_MESSAGE_SIZE);
1113 if (0 == strncmp (current_url, "http", 4))
1114 CURL_EASY_SETOPT (curl, CURLOPT_USERAGENT, "GNUnet");
1115 CURL_EASY_SETOPT (curl, CURLOPT_CONNECTTIMEOUT, 60L);
1116 CURL_EASY_SETOPT (curl, CURLOPT_TIMEOUT, 60L);
1117 multi = curl_multi_init ();
1118 if (multi == NULL)
1119 {
1120 GNUNET_break (0);
1121 /* clean_up (); */
1122 return;
1123 }
1124 mret = curl_multi_add_handle (multi, curl);
1125 if (mret != CURLM_OK)
1126 {
1127 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1128 _ ("%s failed at %s:%d: `%s'\n"),
1129 "curl_multi_add_handle",
1130 __FILE__,
1131 __LINE__,
1132 curl_multi_strerror (mret));
1133 mret = curl_multi_cleanup (multi);
1134 if (mret != CURLM_OK)
1135 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1136 _ ("%s failed at %s:%d: `%s'\n"),
1137 "curl_multi_cleanup",
1138 __FILE__,
1139 __LINE__,
1140 curl_multi_strerror (mret));
1141 multi = NULL;
1142 clean_up ();
1143 return;
1144 }
1145 end_time = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_MINUTES);
1146 download_prepare ();
1147}
1148
1149
1150static void
1151task_download_dispatcher (void *cls)
1152{
1153 ti_download_dispatcher_task = NULL;
1154 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Download is initiated...\n");
1155 if (GNUNET_NO == stat_download_in_progress)
1156 {
1157 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Download can start immediately...\n");
1158 download_hostlist ();
1159 }
1160 else
1161 {
1162 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1163 "Download in progress, have to wait...\n");
1164 ti_download_dispatcher_task =
1165 GNUNET_SCHEDULER_add_delayed (WAITING_INTERVAL,
1166 &task_download_dispatcher,
1167 NULL);
1168 }
1169}
1170
1171
1172/**
1173 * Task that checks if we should try to download a hostlist.
1174 * If so, we initiate the download, otherwise we schedule
1175 * this task again for a later time.
1176 */
1177static void
1178task_check (void *cls)
1179{
1180 static int once;
1181 struct GNUNET_TIME_Relative delay;
1182
1183 ti_check_download = NULL;
1184 if (stats == NULL)
1185 {
1186 curl_global_cleanup ();
1187 return; /* in shutdown */
1188 }
1189 if ((stat_connection_count < MIN_CONNECTIONS) &&
1190 (NULL == ti_download_dispatcher_task))
1191 ti_download_dispatcher_task =
1192 GNUNET_SCHEDULER_add_now (&task_download_dispatcher, NULL);
1193
1194 delay = hostlist_delay;
1195 if (0 == hostlist_delay.rel_value_us)
1196 hostlist_delay = GNUNET_TIME_UNIT_SECONDS;
1197 else
1198 hostlist_delay = GNUNET_TIME_relative_multiply (hostlist_delay, 2);
1199 if (hostlist_delay.rel_value_us >
1200 GNUNET_TIME_UNIT_HOURS.rel_value_us * (1 + stat_connection_count))
1201 hostlist_delay =
1202 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS,
1203 (1 + stat_connection_count));
1204 GNUNET_STATISTICS_set (stats,
1205 gettext_noop (
1206 "# milliseconds between hostlist downloads"),
1207 hostlist_delay.rel_value_us / 1000LL,
1208 GNUNET_YES);
1209 if (0 == once)
1210 {
1211 delay = GNUNET_TIME_UNIT_ZERO;
1212 once = 1;
1213 }
1214 GNUNET_log (
1215 GNUNET_ERROR_TYPE_INFO,
1216 _ ("Have %u/%u connections. Will consider downloading hostlist in %s\n"),
1217 stat_connection_count,
1218 MIN_CONNECTIONS,
1219 GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES));
1220 ti_check_download = GNUNET_SCHEDULER_add_delayed (delay, &task_check, NULL);
1221}
1222
1223
1224/**
1225 * This tasks sets hostlist testing to allowed after interval between to testings is reached
1226 *
1227 * @param cls closure
1228 */
1229static void
1230task_testing_intervall_reset (void *cls)
1231{
1232 ti_testing_intervall_task = NULL;
1233 stat_testing_allowed = GNUNET_OK;
1234 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1235 "Testing new hostlist advertisements is allowed again\n");
1236}
1237
1238
1239/**
1240 * Task that writes hostlist entries to a file on a regular base
1241 *
1242 * @param cls closure
1243 */
1244static void
1245task_hostlist_saving (void *cls)
1246{
1247 ti_saving_task = NULL;
1248 save_hostlist_file (GNUNET_NO);
1249
1250 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1251 "Hostlists will be saved to file again in %s\n",
1252 GNUNET_STRINGS_relative_time_to_string (SAVING_INTERVAL,
1253 GNUNET_YES));
1254 ti_saving_task =
1255 GNUNET_SCHEDULER_add_delayed (SAVING_INTERVAL, &task_hostlist_saving, NULL);
1256}
1257
1258
1259/**
1260 * Method called whenever a given peer connects.
1261 *
1262 * @param cls closure
1263 * @param peer peer identity this notification is about
1264 * @param mq message queue for transmissions to @a peer
1265 */
1266static void *
1267handler_connect (void *cls,
1268 const struct GNUNET_PeerIdentity *peer,
1269 struct GNUNET_MQ_Handle *mq)
1270{
1271 GNUNET_assert (stat_connection_count < UINT_MAX);
1272 stat_connection_count++;
1273 GNUNET_STATISTICS_update (stats,
1274 gettext_noop ("# active connections"),
1275 1,
1276 GNUNET_NO);
1277 return NULL;
1278}
1279
1280
1281/**
1282 * Method called whenever a given peer disconnects.
1283 *
1284 * @param cls closure
1285 * @param peer peer identity this notification is about
1286 */
1287static void
1288handler_disconnect (void *cls,
1289 const struct GNUNET_PeerIdentity *peer,
1290 void *internal_cls)
1291{
1292 GNUNET_assert (stat_connection_count > 0);
1293 stat_connection_count--;
1294 GNUNET_STATISTICS_update (stats,
1295 gettext_noop ("# active connections"),
1296 -1,
1297 GNUNET_NO);
1298}
1299
1300
1301/**
1302 * Method called whenever an advertisement message arrives.
1303 *
1304 * @param uri the advertised URI
1305 */
1306static void
1307handler_advertisement (const char *uri)
1308{
1309 size_t uri_size;
1310 struct Hostlist *hostlist;
1311
1312 uri_size = strlen (uri) + 1;
1313 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1314 "Hostlist client received advertisement containing URI `%s'\n",
1315 uri);
1316 if (GNUNET_NO != linked_list_contains (uri))
1317 {
1318 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "URI `%s' is already known\n", uri);
1319 return;
1320 }
1321
1322 if (GNUNET_NO == stat_testing_allowed)
1323 {
1324 GNUNET_log (
1325 GNUNET_ERROR_TYPE_DEBUG,
1326 "Currently not accepting new advertisements: interval between to advertisements is not reached\n");
1327 return;
1328 }
1329 if (GNUNET_YES == stat_testing_hostlist)
1330 {
1331 GNUNET_log (
1332 GNUNET_ERROR_TYPE_DEBUG,
1333 "Currently not accepting new advertisements: we are already testing a hostlist\n");
1334 return;
1335 }
1336
1337 hostlist = GNUNET_malloc (sizeof(struct Hostlist) + uri_size);
1338 hostlist->hostlist_uri = (const char *) &hostlist[1];
1339 GNUNET_memcpy (&hostlist[1], uri, uri_size);
1340 hostlist->time_creation = GNUNET_TIME_absolute_get ();
1341 hostlist->quality = HOSTLIST_INITIAL;
1342 hostlist_to_test = hostlist;
1343
1344 stat_testing_hostlist = GNUNET_YES;
1345 stat_testing_allowed = GNUNET_NO;
1346 ti_testing_intervall_task =
1347 GNUNET_SCHEDULER_add_delayed (TESTING_INTERVAL,
1348 &task_testing_intervall_reset,
1349 NULL);
1350
1351 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1352 "Testing new hostlist advertisements is locked for the next %s\n",
1353 GNUNET_STRINGS_relative_time_to_string (TESTING_INTERVAL,
1354 GNUNET_YES));
1355
1356 ti_download_dispatcher_task =
1357 GNUNET_SCHEDULER_add_now (&task_download_dispatcher, NULL);
1358}
1359
1360
1361/**
1362 * Continuation called by the statistics code once
1363 * we go the stat. Initiates hostlist download scheduling.
1364 *
1365 * @param cls closure
1366 * @param success #GNUNET_OK if statistics were
1367 * successfully obtained, #GNUNET_SYSERR if not.
1368 */
1369static void
1370primary_task (void *cls, int success)
1371{
1372 if (NULL != ti_check_download)
1373 {
1374 GNUNET_SCHEDULER_cancel (ti_check_download);
1375 ti_check_download = NULL;
1376 }
1377 sget = NULL;
1378 GNUNET_assert (NULL != stats);
1379 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1380 "Statistics request done, scheduling hostlist download\n");
1381 ti_check_download = GNUNET_SCHEDULER_add_now (&task_check, NULL);
1382}
1383
1384
1385/**
1386 * Continuation called by the statistics code once
1387 * we go the stat. Initiates hostlist download scheduling.
1388 *
1389 * @param cls closure
1390 */
1391static void
1392stat_timeout_task (void *cls)
1393{
1394 GNUNET_STATISTICS_get_cancel (sget);
1395 sget = NULL;
1396 ti_check_download = GNUNET_SCHEDULER_add_now (&task_check, NULL);
1397}
1398
1399
1400/**
1401 * We've received the previous delay value from statistics. Remember it.
1402 *
1403 * @param cls NULL, unused
1404 * @param subsystem should be "hostlist", unused
1405 * @param name will be "milliseconds between hostlist downloads", unused
1406 * @param value previous delay value, in milliseconds (!)
1407 * @param is_persistent unused, will be #GNUNET_YES
1408 */
1409static int
1410process_stat (void *cls,
1411 const char *subsystem,
1412 const char *name,
1413 uint64_t value,
1414 int is_persistent)
1415{
1416 hostlist_delay.rel_value_us = value * 1000LL;
1417 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1418 "Initial time between hostlist downloads is %s\n",
1419 GNUNET_STRINGS_relative_time_to_string (hostlist_delay,
1420 GNUNET_YES));
1421 return GNUNET_OK;
1422}
1423
1424
1425/**
1426 * Method to load persistent hostlist file during hostlist client startup
1427 */
1428static void
1429load_hostlist_file ()
1430{
1431 char *filename;
1432 char *uri;
1433 char *emsg;
1434 struct Hostlist *hostlist;
1435 uint32_t times_used;
1436 uint32_t hellos_returned;
1437 uint64_t quality;
1438 uint64_t last_used;
1439 uint64_t created;
1440 uint32_t counter;
1441 struct GNUNET_BIO_ReadHandle *rh;
1442
1443 uri = NULL;
1444 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg,
1445 "HOSTLIST",
1446 "HOSTLISTFILE",
1447 &filename))
1448 {
1449 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,
1450 "hostlist",
1451 "HOSTLISTFILE");
1452 return;
1453 }
1454
1455 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1456 _ ("Loading saved hostlist entries from file `%s' \n"),
1457 filename);
1458 if (GNUNET_NO == GNUNET_DISK_file_test (filename))
1459 {
1460 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1461 _ ("Hostlist file `%s' does not exist\n"),
1462 filename);
1463 GNUNET_free (filename);
1464 return;
1465 }
1466
1467 rh = GNUNET_BIO_read_open_file (filename);
1468 if (NULL == rh)
1469 {
1470 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1471 _ (
1472 "Could not open file `%s' for reading to load hostlists: %s\n"),
1473 filename,
1474 strerror (errno));
1475 GNUNET_free (filename);
1476 return;
1477 }
1478
1479 counter = 0;
1480 struct GNUNET_BIO_ReadSpec rs[] = {
1481 GNUNET_BIO_read_spec_int32 ("times used", (int32_t *) &times_used),
1482 GNUNET_BIO_read_spec_int64 ("quality", (int64_t *) &quality),
1483 GNUNET_BIO_read_spec_int64 ("last used", (int64_t *) &last_used),
1484 GNUNET_BIO_read_spec_int64 ("created", (int64_t *) &created),
1485 GNUNET_BIO_read_spec_int32 ("hellos returned",
1486 (int32_t *) &hellos_returned),
1487 GNUNET_BIO_read_spec_end (),
1488 };
1489 while ((GNUNET_OK == GNUNET_BIO_read_string (rh, "url", &uri, MAX_URL_LEN)) &&
1490 (NULL != uri) &&
1491 (GNUNET_OK == GNUNET_BIO_read_spec_commit (rh, rs)))
1492 {
1493 hostlist = GNUNET_malloc (sizeof(struct Hostlist) + strlen (uri) + 1);
1494 hostlist->hello_count = hellos_returned;
1495 hostlist->hostlist_uri = (const char *) &hostlist[1];
1496 GNUNET_memcpy (&hostlist[1], uri, strlen (uri) + 1);
1497 hostlist->quality = quality;
1498 hostlist->time_creation.abs_value_us = created;
1499 hostlist->time_last_usage.abs_value_us = last_used;
1500 GNUNET_CONTAINER_DLL_insert (linked_list_head, linked_list_tail, hostlist);
1501 linked_list_size++;
1502 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1503 "Added hostlist entry with URI `%s' \n",
1504 hostlist->hostlist_uri);
1505 GNUNET_free (uri);
1506 uri = NULL;
1507 counter++;
1508 if (counter >= MAX_NUMBER_HOSTLISTS)
1509 break;
1510 }
1511
1512 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1513 _ ("%u hostlist URIs loaded from file\n"),
1514 counter);
1515 GNUNET_STATISTICS_set (stats,
1516 gettext_noop ("# hostlist URIs read from file"),
1517 counter,
1518 GNUNET_YES);
1519 GNUNET_STATISTICS_set (stats,
1520 gettext_noop ("# advertised hostlist URIs"),
1521 linked_list_size,
1522 GNUNET_NO);
1523
1524 GNUNET_free (uri);
1525 emsg = NULL;
1526 (void) GNUNET_BIO_read_close (rh, &emsg);
1527 if (emsg != NULL)
1528 GNUNET_free (emsg);
1529 GNUNET_free (filename);
1530}
1531
1532
1533/**
1534 * Method to save persistent hostlist file during hostlist client shutdown
1535 *
1536 * @param shutdown set if called because of shutdown, entries in linked list will be destroyed
1537 */
1538static void
1539save_hostlist_file (int shutdown)
1540{
1541 char *filename;
1542 struct Hostlist *pos;
1543 struct GNUNET_BIO_WriteHandle *wh;
1544 int ok;
1545 uint32_t counter;
1546
1547 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg,
1548 "HOSTLIST",
1549 "HOSTLISTFILE",
1550 &filename))
1551 {
1552 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,
1553 "hostlist",
1554 "HOSTLISTFILE");
1555 return;
1556 }
1557 if (GNUNET_SYSERR == GNUNET_DISK_directory_create_for_file (filename))
1558 {
1559 GNUNET_free (filename);
1560 return;
1561 }
1562 wh = GNUNET_BIO_write_open_file (filename);
1563 if (NULL == wh)
1564 {
1565 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1566 _ (
1567 "Could not open file `%s' for writing to save hostlists: %s\n"),
1568 filename,
1569 strerror (errno));
1570 GNUNET_free (filename);
1571 return;
1572 }
1573 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1574 _ ("Writing %u hostlist URIs to `%s'\n"),
1575 linked_list_size,
1576 filename);
1577 /* add code to write hostlists to file using bio */
1578 ok = GNUNET_YES;
1579 counter = 0;
1580 while (NULL != (pos = linked_list_head))
1581 {
1582 if (GNUNET_YES == shutdown)
1583 {
1584 GNUNET_CONTAINER_DLL_remove (linked_list_head, linked_list_tail, pos);
1585 linked_list_size--;
1586 }
1587 if (GNUNET_YES == ok)
1588 {
1589 struct GNUNET_BIO_WriteSpec ws[] = {
1590 GNUNET_BIO_write_spec_string ("hostlist uri", pos->hostlist_uri),
1591 GNUNET_BIO_write_spec_int32 ("times used",
1592 (int32_t *) &pos->times_used),
1593 GNUNET_BIO_write_spec_int64 ("quality", (int64_t *) &pos->quality),
1594 GNUNET_BIO_write_spec_int64 (
1595 "last usage",
1596 (int64_t *) &pos->time_last_usage.abs_value_us),
1597 GNUNET_BIO_write_spec_int64 (
1598 "creation time",
1599 (int64_t *) &pos->time_creation.abs_value_us),
1600 GNUNET_BIO_write_spec_int32 ("hellos count",
1601 (int32_t *) &pos->hello_count),
1602 GNUNET_BIO_write_spec_end (),
1603 };
1604 if ((GNUNET_OK != GNUNET_BIO_write_spec_commit (wh, ws)))
1605 {
1606 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1607 _ ("Error writing hostlist URIs to file `%s'\n"),
1608 filename);
1609 ok = GNUNET_NO;
1610 }
1611 }
1612
1613 if (GNUNET_YES == shutdown)
1614 GNUNET_free (pos);
1615 counter++;
1616 if (counter >= MAX_NUMBER_HOSTLISTS)
1617 break;
1618 }
1619 GNUNET_STATISTICS_set (stats,
1620 gettext_noop ("# hostlist URIs written to file"),
1621 counter,
1622 GNUNET_YES);
1623
1624 if (GNUNET_OK != GNUNET_BIO_write_close (wh, NULL))
1625 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1626 _ ("Error writing hostlist URIs to file `%s'\n"),
1627 filename);
1628 GNUNET_free (filename);
1629}
1630
1631
1632/**
1633 * Start downloading hostlists from hostlist servers as necessary.
1634 *
1635 * @param c configuration to use
1636 * @param st statistics handle to use
1637 * @param[out] ch set to handler for CORE connect events
1638 * @param[out] dh set to handler for CORE disconnect events
1639 * @param[out] msgh set to handler for CORE advertisement messages
1640 * @param learn should we learn hostlist URLs from CORE
1641 * @return #GNUNET_OK on success
1642 */
1643int
1644GNUNET_HOSTLIST_client_start (const struct GNUNET_CONFIGURATION_Handle *c,
1645 struct GNUNET_STATISTICS_Handle *st,
1646 GNUNET_CORE_ConnectEventHandler *ch,
1647 GNUNET_CORE_DisconnectEventHandler *dh,
1648 GNUNET_HOSTLIST_UriHandler *msgh,
1649 int learn)
1650{
1651 char *filename;
1652 char *proxytype_str;
1653 int result;
1654
1655 GNUNET_assert (NULL != st);
1656 if (0 != curl_global_init (CURL_GLOBAL_WIN32))
1657 {
1658 GNUNET_break (0);
1659 return GNUNET_SYSERR;
1660 }
1661 cfg = c;
1662 stats = st;
1663
1664 /* Read proxy configuration */
1665 peerstore = GNUNET_PEERSTORE_connect (c);
1666 if (GNUNET_OK ==
1667 GNUNET_CONFIGURATION_get_value_string (cfg, "HOSTLIST", "PROXY", &proxy))
1668 {
1669 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found proxy host: `%s'\n", proxy);
1670 /* proxy username */
1671 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg,
1672 "HOSTLIST",
1673 "PROXY_USERNAME",
1674 &proxy_username))
1675 {
1676 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1677 "Found proxy username name: `%s'\n",
1678 proxy_username);
1679 }
1680
1681 /* proxy password */
1682 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg,
1683 "HOSTLIST",
1684 "PROXY_PASSWORD",
1685 &proxy_password))
1686 {
1687 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1688 "Found proxy password name: `%s'\n",
1689 proxy_password);
1690 }
1691
1692 /* proxy type */
1693 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg,
1694 "HOSTLIST",
1695 "PROXY_TYPE",
1696 &proxytype_str))
1697 {
1698 if (GNUNET_OK != GNUNET_STRINGS_utf8_toupper (proxytype_str,
1699 proxytype_str))
1700 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1701 "Unable to convert `%s' to UTF-8 uppercase\n",
1702 proxytype_str);
1703 proxy_type = CURLPROXY_HTTP;
1704 if (0 == strcmp (proxytype_str, "HTTP"))
1705 proxy_type = CURLPROXY_HTTP;
1706 else if (0 == strcmp (proxytype_str, "HTTP_1_0"))
1707 proxy_type = CURLPROXY_HTTP_1_0;
1708 else if (0 == strcmp (proxytype_str, "SOCKS4"))
1709 proxy_type = CURLPROXY_SOCKS4;
1710 else if (0 == strcmp (proxytype_str, "SOCKS5"))
1711 proxy_type = CURLPROXY_SOCKS5;
1712 else if (0 == strcmp (proxytype_str, "SOCKS4A"))
1713 proxy_type = CURLPROXY_SOCKS4A;
1714 else if (0 == strcmp (proxytype_str, "SOCKS5_HOSTNAME"))
1715 proxy_type = CURLPROXY_SOCKS5_HOSTNAME;
1716 else
1717 {
1718 GNUNET_log (
1719 GNUNET_ERROR_TYPE_ERROR,
1720 _ (
1721 "Invalid proxy type: `%s', disabling proxy! Check configuration!\n"),
1722 proxytype_str);
1723 GNUNET_free (proxytype_str);
1724 GNUNET_free (proxy);
1725 proxy = NULL;
1726 GNUNET_free (proxy_username);
1727 proxy_username = NULL;
1728 GNUNET_free (proxy_password);
1729 proxy_password = NULL;
1730
1731 return GNUNET_SYSERR;
1732 }
1733 }
1734 GNUNET_free (proxytype_str);
1735 }
1736
1737 stat_learning = learn;
1738 *ch = &handler_connect;
1739 *dh = &handler_disconnect;
1740 linked_list_head = NULL;
1741 linked_list_tail = NULL;
1742 stat_use_bootstrap = GNUNET_YES;
1743 stat_testing_hostlist = GNUNET_NO;
1744 stat_testing_allowed = GNUNET_YES;
1745
1746 if (GNUNET_YES == stat_learning)
1747 {
1748 *msgh = &handler_advertisement;
1749 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1750 _ ("Learning is enabled on this peer\n"));
1751 load_hostlist_file ();
1752 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1753 "Hostlists will be saved to file again in %s\n",
1754 GNUNET_STRINGS_relative_time_to_string (SAVING_INTERVAL,
1755 GNUNET_YES));
1756 ti_saving_task = GNUNET_SCHEDULER_add_delayed (SAVING_INTERVAL,
1757 &task_hostlist_saving,
1758 NULL);
1759 }
1760 else
1761 {
1762 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1763 _ ("Learning is not enabled on this peer\n"));
1764 *msgh = NULL;
1765 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_filename (cfg,
1766 "HOSTLIST",
1767 "HOSTLISTFILE",
1768 &filename))
1769 {
1770 if (GNUNET_YES == GNUNET_DISK_file_test (filename))
1771 {
1772 result = remove (filename);
1773 if (0 == result)
1774 GNUNET_log (
1775 GNUNET_ERROR_TYPE_INFO,
1776 _ (
1777 "Since learning is not enabled on this peer, hostlist file `%s' was removed\n"),
1778 filename);
1779 else
1780 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
1781 "remove",
1782 filename);
1783 }
1784 }
1785 GNUNET_free (filename);
1786 }
1787 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1788 "Loading stats value on hostlist download frequency\n");
1789 sget = GNUNET_STATISTICS_get (stats,
1790 "hostlist",
1791 gettext_noop (
1792 "# milliseconds between hostlist downloads"),
1793 &primary_task,
1794 &process_stat,
1795 NULL);
1796 if (NULL == sget)
1797 {
1798 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1799 "Statistics request failed, scheduling hostlist download\n");
1800 ti_check_download = GNUNET_SCHEDULER_add_now (&task_check, NULL);
1801 }
1802 else
1803 {
1804 ti_check_download = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
1805 &stat_timeout_task,
1806 NULL);
1807 }
1808 return GNUNET_OK;
1809}
1810
1811
1812/**
1813 * Stop downloading hostlists from hostlist servers as necessary.
1814 */
1815void
1816GNUNET_HOSTLIST_client_stop ()
1817{
1818 struct StoreHelloEntry *pos;
1819
1820 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hostlist client shutdown\n");
1821 while (NULL != (pos = she_head))
1822 {
1823 GNUNET_CONTAINER_DLL_remove (she_head, she_tail, pos);
1824 GNUNET_PEERSTORE_hello_add_cancel (pos->sc);
1825 GNUNET_free (pos);
1826 }
1827 if (NULL != sget)
1828 {
1829 GNUNET_STATISTICS_get_cancel (sget);
1830 sget = NULL;
1831 }
1832 stats = NULL;
1833 if (GNUNET_YES == stat_learning)
1834 save_hostlist_file (GNUNET_YES);
1835 if (NULL != ti_saving_task)
1836 {
1837 GNUNET_SCHEDULER_cancel (ti_saving_task);
1838 ti_saving_task = NULL;
1839 }
1840 if (NULL != ti_download_dispatcher_task)
1841 {
1842 GNUNET_SCHEDULER_cancel (ti_download_dispatcher_task);
1843 ti_download_dispatcher_task = NULL;
1844 }
1845 if (NULL != ti_testing_intervall_task)
1846 {
1847 GNUNET_SCHEDULER_cancel (ti_testing_intervall_task);
1848 ti_testing_intervall_task = NULL;
1849 }
1850 if (NULL != ti_download)
1851 {
1852 GNUNET_SCHEDULER_cancel (ti_download);
1853 ti_download = NULL;
1854 update_hostlist ();
1855 clean_up ();
1856 }
1857 if (NULL != ti_check_download)
1858 {
1859 GNUNET_SCHEDULER_cancel (ti_check_download);
1860 ti_check_download = NULL;
1861 curl_global_cleanup ();
1862 }
1863 GNUNET_free (proxy);
1864 proxy = NULL;
1865 GNUNET_free (proxy_username);
1866 proxy_username = NULL;
1867 GNUNET_free (proxy_password);
1868 proxy_password = NULL;
1869 if (NULL != peerstore)
1870 {
1871 GNUNET_PEERSTORE_disconnect (peerstore);
1872 peerstore = NULL;
1873 }
1874 cfg = NULL;
1875}
1876
1877
1878/* end of gnunet-daemon-hostlist_client.c */
diff --git a/src/service/hostlist/gnunet-daemon-hostlist_client.h b/src/service/hostlist/gnunet-daemon-hostlist_client.h
new file mode 100644
index 000000000..2ee40d961
--- /dev/null
+++ b/src/service/hostlist/gnunet-daemon-hostlist_client.h
@@ -0,0 +1,70 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009 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 * @file hostlist/gnunet-daemon-hostlist_client.h
22 * @brief hostlist support. Downloads HELLOs via HTTP.
23 * @author Christian Grothoff
24 */
25#ifndef GNUNET_DAEMON_HOSTLIST_CLIENT_H
26#define GNUNET_DAEMON_HOSTLIST_CLIENT_H
27
28#include "gnunet_core_service.h"
29#include "gnunet_statistics_service.h"
30#include "gnunet_util_lib.h"
31
32
33/**
34 * Function that handles an advertised URI.
35 *
36 * @param uri 0-termianted URI of a hostlist
37 */
38typedef void
39(*GNUNET_HOSTLIST_UriHandler)(const char *uri);
40
41
42/**
43 * Start downloading hostlists from hostlist servers as necessary.
44 *
45 * @param c configuration to use
46 * @param st statistics handle to use
47 * @param[out] ch set to handler for CORE connect events
48 * @param[out] dh set to handler for CORE disconnect events
49 * @param[out] msgh set to handler for CORE advertisement messages
50 * @param learn should we learn hostlist URLs from CORE
51 * @return #GNUNET_OK on success
52 */
53int
54GNUNET_HOSTLIST_client_start (const struct GNUNET_CONFIGURATION_Handle *c,
55 struct GNUNET_STATISTICS_Handle *st,
56 GNUNET_CORE_ConnectEventHandler *ch,
57 GNUNET_CORE_DisconnectEventHandler *dh,
58 GNUNET_HOSTLIST_UriHandler *msgh,
59 int learn);
60
61
62/**
63 * Stop downloading hostlists from hostlist servers as necessary.
64 */
65void
66GNUNET_HOSTLIST_client_stop (void);
67
68
69#endif
70/* end of gnunet-daemon-hostlist_client.h */
diff --git a/src/service/hostlist/gnunet-daemon-hostlist_server.c b/src/service/hostlist/gnunet-daemon-hostlist_server.c
new file mode 100644
index 000000000..7cfeaec63
--- /dev/null
+++ b/src/service/hostlist/gnunet-daemon-hostlist_server.c
@@ -0,0 +1,915 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2008, 2009, 2010, 2014, 2016 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_server.c
23 * @author Christian Grothoff
24 * @author Matthias Wachs
25 * @author David Barksdale
26 * @brief application to provide an integrated hostlist HTTP server
27 */
28#include "platform.h"
29#include "gnunet_common.h"
30#include <microhttpd.h>
31#include "gnunet-daemon-hostlist_server.h"
32#include "gnunet_hello_uri_lib.h"
33#include "gnunet_peerstore_service.h"
34#include "gnunet-daemon-hostlist.h"
35#include "gnunet_resolver_service.h"
36#include "gnunet_mhd_compat.h"
37
38
39/**
40 * How long until our hostlist advertisement transmission via CORE should
41 * time out?
42 */
43#define GNUNET_ADV_TIMEOUT \
44 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
45
46/**
47 * Map with hellos we build the hostlist with.
48 */
49struct GNUNET_CONTAINER_MultiPeerMap *hellos;
50
51/**
52 * Handle to the HTTP server as provided by libmicrohttpd for IPv6.
53 */
54static struct MHD_Daemon *daemon_handle_v6;
55
56/**
57 * Handle to the HTTP server as provided by libmicrohttpd for IPv4.
58 */
59static struct MHD_Daemon *daemon_handle_v4;
60
61/**
62 * Our configuration.
63 */
64static const struct GNUNET_CONFIGURATION_Handle *cfg;
65
66/**
67 * For keeping statistics.
68 */
69static struct GNUNET_STATISTICS_Handle *stats;
70
71/**
72 * Handle to the core service (NULL until we've connected to it).
73 */
74static struct GNUNET_CORE_Handle *core;
75
76/**
77 * The task to delayed start the notification process intially.
78 * We like to give transport some time to give us our hello to distribute it.
79 */
80struct GNUNET_SCHEDULER_Task *peerstore_notify_task;
81
82/**
83 * Our peerstore notification context. We use notification
84 * to instantly learn about new peers as they are discovered.
85 */
86static struct GNUNET_PEERSTORE_Monitor *peerstore_notify;
87
88/**
89 * Our primary task for IPv4.
90 */
91static struct GNUNET_SCHEDULER_Task *hostlist_task_v4;
92
93/**
94 * Our primary task for IPv6.
95 */
96static struct GNUNET_SCHEDULER_Task *hostlist_task_v6;
97
98/**
99 * Our canonical response.
100 */
101static struct MHD_Response *response;
102
103/**
104 * Handle to the PEERSTORE service.
105 */
106static struct GNUNET_PEERSTORE_Handle *peerstore;
107
108/**
109 * Set if we are allowed to advertise our hostlist to others.
110 */
111static int advertising;
112
113/**
114 * Buffer for the hostlist address
115 */
116static char *hostlist_uri;
117
118
119/**
120 * Context for #host_processor().
121 */
122struct HostSet
123{
124 /**
125 * Place where we accumulate all of the HELLO messages.
126 */
127 char *data;
128
129 /**
130 * Number of bytes in @e data.
131 */
132 unsigned int size;
133};
134
135
136/**
137 * NULL if we are not currently iterating over peer information.
138 */
139static struct HostSet *builder;
140
141
142/**
143 * Add headers to a request indicating that we allow Cross-Origin Resource
144 * Sharing.
145 *
146 * @param response response to add headers to
147 */
148static void
149add_cors_headers (struct MHD_Response *response)
150{
151 MHD_add_response_header (response, "Access-Control-Allow-Origin", "*");
152 MHD_add_response_header (response,
153 "Access-Control-Allow-Methods",
154 "GET, OPTIONS");
155 MHD_add_response_header (response, "Access-Control-Max-Age", "86400");
156}
157
158
159/**
160 * Function that assembles our response.
161 */
162static void
163finish_response ()
164{
165 if (NULL != response)
166 MHD_destroy_response (response);
167 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
168 "Creating hostlist response with %u bytes\n",
169 (unsigned int) builder->size);
170 response = MHD_create_response_from_buffer (builder->size,
171 builder->data,
172 MHD_RESPMEM_MUST_FREE);
173 add_cors_headers (response);
174 if ((NULL == daemon_handle_v4) && (NULL == daemon_handle_v6))
175 {
176 MHD_destroy_response (response);
177 response = NULL;
178 }
179 GNUNET_STATISTICS_set (stats,
180 gettext_noop ("bytes in hostlist"),
181 builder->size,
182 GNUNET_YES);
183 GNUNET_free (builder);
184 builder = NULL;
185}
186
187
188/**
189 * Callback that processes each of the known HELLOs for the
190 * hostlist response construction.
191 *
192 * @param cls closure, NULL
193 * @param peer id of the peer, NULL for last call
194 * @param hello hello message for the peer (can be NULL)
195 * @param err_msg message
196 */
197static enum GNUNET_GenericReturnValue
198host_processor (void *cls,
199 const struct GNUNET_PeerIdentity *peer,
200 void *value)
201{
202 (void) cls;
203 size_t old;
204 size_t s;
205 struct GNUNET_MessageHeader *hello = value;
206
207 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
208 "host_processor\n");
209 old = builder->size;
210 s = ntohs (hello->size);
211 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
212 "Received %u bytes of `%s' from peer `%s' for hostlist.\n",
213 (unsigned int) s,
214 "HELLO",
215 GNUNET_i2s (peer));
216 if ((old + s >= GNUNET_MAX_MALLOC_CHECKED) ||
217 (old + s >= MAX_BYTES_PER_HOSTLISTS))
218 {
219 /* too large, skip! */
220 GNUNET_STATISTICS_update (stats,
221 gettext_noop (
222 "bytes not included in hostlist (size limit)"),
223 s,
224 GNUNET_NO);
225 return GNUNET_YES;
226 }
227 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
228 "Adding peer `%s' to hostlist (%u bytes)\n",
229 GNUNET_i2s (peer),
230 (unsigned int) s);
231 GNUNET_array_grow (builder->data, builder->size, old + s);
232 GNUNET_memcpy (&builder->data[old], hello, s);
233
234 return GNUNET_YES;
235}
236
237
238/**
239 * Hostlist access policy (very permissive, allows everything).
240 * Returns #MHD_NO only if we are not yet ready to serve.
241 *
242 * @param cls closure
243 * @param addr address information from the client
244 * @param addrlen length of @a addr
245 * @return #MHD_YES if connection is allowed, #MHD_NO if not (we are not ready)
246 */
247static MHD_RESULT
248accept_policy_callback (void *cls,
249 const struct sockaddr *addr,
250 socklen_t addrlen)
251{
252 if (NULL == response)
253 {
254 GNUNET_log (
255 GNUNET_ERROR_TYPE_DEBUG,
256 "Received request for hostlist, but I am not yet ready; rejecting!\n");
257 return MHD_NO;
258 }
259 return MHD_YES; /* accept all */
260}
261
262
263/**
264 * Main request handler.
265 *
266 * @param cls argument given together with the function
267 * pointer when the handler was registered with MHD
268 * @param connection
269 * @param url the requested url
270 * @param method the HTTP method used (#MHD_HTTP_METHOD_GET,
271 * #MHD_HTTP_METHOD_PUT, etc.)
272 * @param version the HTTP version string (e.g.
273 * #MHD_HTTP_VERSION_1_1)
274 * @param upload_data the data being uploaded (excluding HEADERS,
275 * for a POST that fits into memory and that is encoded
276 * with a supported encoding, the POST data will NOT be
277 * given in upload_data and is instead available as
278 * part of #MHD_get_connection_values; very large POST
279 * data *will* be made available incrementally in
280 * @a upload_data)
281 * @param upload_data_size set initially to the size of the
282 * @a upload_data provided; the method must update this
283 * value to the number of bytes NOT processed;
284 * @param con_cls pointer that the callback can set to some
285 * address and that will be preserved by MHD for future
286 * calls for this request; since the access handler may
287 * be called many times (e.g. for a PUT/POST operation
288 * with plenty of upload data) this allows the application
289 * to easily associate some request-specific state.
290 * If necessary, this state can be cleaned up in the
291 * global #MHD_RequestCompletedCallback (which
292 * can be set with the #MHD_OPTION_NOTIFY_COMPLETED).
293 * Initially, `*con_cls` will be NULL.
294 * @return #MHD_YES if the connection was handled successfully,
295 * #MHD_NO if the socket must be closed due to a serious
296 * error while handling the request
297 */
298static MHD_RESULT
299access_handler_callback (void *cls,
300 struct MHD_Connection *connection,
301 const char *url,
302 const char *method,
303 const char *version,
304 const char *upload_data,
305 size_t *upload_data_size,
306 void **con_cls)
307{
308 static int dummy;
309
310 /* CORS pre-flight request */
311 if (0 == strcmp (MHD_HTTP_METHOD_OPTIONS, method))
312 {
313 struct MHD_Response *options_response;
314 int rc;
315
316 options_response =
317 MHD_create_response_from_buffer (0, NULL, MHD_RESPMEM_PERSISTENT);
318 add_cors_headers (options_response);
319 rc = MHD_queue_response (connection, MHD_HTTP_OK, options_response);
320 MHD_destroy_response (options_response);
321 return rc;
322 }
323 if (0 != strcmp (method, MHD_HTTP_METHOD_GET))
324 {
325 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
326 _ ("Refusing `%s' request to hostlist server\n"),
327 method);
328 GNUNET_STATISTICS_update (stats,
329 gettext_noop (
330 "hostlist requests refused (not HTTP GET)"),
331 1,
332 GNUNET_YES);
333 return MHD_NO;
334 }
335 if (NULL == *con_cls)
336 {
337 (*con_cls) = &dummy;
338 return MHD_YES;
339 }
340 if (0 != *upload_data_size)
341 {
342 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
343 _ ("Refusing `%s' request with %llu bytes of upload data\n"),
344 method,
345 (unsigned long long) *upload_data_size);
346 GNUNET_STATISTICS_update (stats,
347 gettext_noop (
348 "hostlist requests refused (upload data)"),
349 1,
350 GNUNET_YES);
351 return MHD_NO; /* do not support upload data */
352 }
353 if (NULL == response)
354 {
355 GNUNET_log (
356 GNUNET_ERROR_TYPE_WARNING,
357 _ (
358 "Could not handle hostlist request since I do not have a response yet\n"));
359 GNUNET_STATISTICS_update (stats,
360 gettext_noop (
361 "hostlist requests refused (not ready)"),
362 1,
363 GNUNET_YES);
364 return MHD_NO; /* internal error, no response yet */
365 }
366 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
367 _ ("Received request for our hostlist\n"));
368 GNUNET_STATISTICS_update (stats,
369 gettext_noop ("hostlist requests processed"),
370 1,
371 GNUNET_YES);
372 return MHD_queue_response (connection, MHD_HTTP_OK, response);
373}
374
375
376/**
377 * Handler called by CORE when CORE is ready to transmit message
378 *
379 * @param cls closure with the `const struct GNUNET_PeerIdentity *` of
380 * the peer we are sending to
381 * @param size size of buffer to copy message to
382 * @param buf buffer to copy message to
383 * @return number of bytes copied to @a buf
384 */
385static void
386adv_transmit (struct GNUNET_MQ_Handle *mq)
387{
388 static uint64_t hostlist_adv_count;
389 size_t uri_size; /* Including \0 termination! */
390 struct GNUNET_MessageHeader *header;
391 struct GNUNET_MQ_Envelope *env;
392
393 uri_size = strlen (hostlist_uri) + 1;
394 env = GNUNET_MQ_msg_extra (header,
395 uri_size,
396 GNUNET_MESSAGE_TYPE_HOSTLIST_ADVERTISEMENT);
397 GNUNET_memcpy (&header[1], hostlist_uri, uri_size);
398 GNUNET_MQ_env_set_options (env,
399 GNUNET_MQ_PREF_CORK_ALLOWED
400 | GNUNET_MQ_PREF_UNRELIABLE);
401 GNUNET_MQ_send (mq, env);
402 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
403 "Sent advertisement message: Copied %u bytes into buffer!\n",
404 (unsigned int) uri_size);
405 hostlist_adv_count++;
406 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
407 " # Sent advertisement message: %llu\n",
408 (unsigned long long) hostlist_adv_count);
409 GNUNET_STATISTICS_update (stats,
410 gettext_noop ("# hostlist advertisements send"),
411 1,
412 GNUNET_NO);
413}
414
415
416/**
417 * Method called whenever a given peer connects.
418 *
419 * @param cls closure
420 * @param peer peer identity this notification is about
421 * @param mq queue for transmission to @a peer
422 * @return NULL (must!)
423 */
424static void *
425connect_handler (void *cls,
426 const struct GNUNET_PeerIdentity *peer,
427 struct GNUNET_MQ_Handle *mq)
428{
429 size_t size;
430
431 if (! advertising)
432 return NULL;
433 if (NULL == hostlist_uri)
434 return NULL;
435 size = strlen (hostlist_uri) + 1;
436 if (size + sizeof(struct GNUNET_MessageHeader) >= GNUNET_MAX_MESSAGE_SIZE)
437 {
438 GNUNET_break (0);
439 return NULL;
440 }
441 size += sizeof(struct GNUNET_MessageHeader);
442 if (NULL == core)
443 {
444 GNUNET_break (0);
445 return NULL;
446 }
447 GNUNET_log (
448 GNUNET_ERROR_TYPE_DEBUG,
449 "Asked CORE to transmit advertisement message with a size of %u bytes to peer `%s'\n",
450 (unsigned int) size,
451 GNUNET_i2s (peer));
452 adv_transmit (mq);
453 return NULL;
454}
455
456
457/**
458 * PEERSTORE calls this function to let us know about a possible peer
459 * that we might want to connect to.
460 *
461 * @param cls closure (not used)
462 * @param peer potential peer to connect to
463 * @param hello HELLO for this peer (or NULL)
464 * @param err_msg NULL if successful, otherwise contains error message
465 */
466static void
467process_notify (void *cls,
468 const struct GNUNET_PEERSTORE_Record *record,
469 const char *err_msg)
470{
471 unsigned int map_size;
472 struct GNUNET_MessageHeader *hello_cpy;
473 struct GNUNET_PeerIdentity *peer_cpy;
474 struct GNUNET_MessageHeader *hello;
475
476 map_size = GNUNET_CONTAINER_multipeermap_size (hellos);
477 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
478 "Peerstore is notifying us to rebuild our hostlist map size %u\n",
479 map_size);
480 if (NULL != err_msg)
481 {
482 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
483 _ ("Error in communication with PEERSTORE service: %s\n"),
484 err_msg);
485 return;
486 }
487 hello = record->value;
488 if (NULL != builder)
489 {
490 GNUNET_free (builder->data);
491 builder->size = 0;
492 builder->data = NULL;
493 }
494 else
495 {
496 builder = GNUNET_new (struct HostSet);
497 }
498
499 peer_cpy = GNUNET_malloc (sizeof (struct GNUNET_PeerIdentity));
500 GNUNET_memcpy (peer_cpy, &record->peer, sizeof (struct GNUNET_PeerIdentity));
501 hello_cpy = GNUNET_malloc (ntohs (hello->size));
502 GNUNET_memcpy (hello_cpy, hello, ntohs (hello->size));
503 GNUNET_assert (GNUNET_YES ==
504 GNUNET_CONTAINER_multipeermap_put (hellos,
505 peer_cpy,
506 (struct
507 GNUNET_MessageHeader *)
508 hello_cpy,
509 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
510 if (0 != GNUNET_CONTAINER_multipeermap_iterate (hellos,
511 &host_processor,
512 NULL))
513 finish_response ();
514 map_size = GNUNET_CONTAINER_multipeermap_size (hellos);
515 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
516 "1 Peerstore is notifying us to rebuild our hostlist map size %u peer %s\n",
517 map_size,
518 GNUNET_i2s (&record->peer));
519 GNUNET_PEERSTORE_monitor_next (peerstore_notify, 1);
520}
521
522
523/**
524 * Function that queries MHD's select sets and
525 * starts the task waiting for them.
526 */
527static struct GNUNET_SCHEDULER_Task *
528prepare_daemon (struct MHD_Daemon *daemon_handle);
529
530
531/**
532 * Call MHD to process pending requests and then go back
533 * and schedule the next run.
534 *
535 * @param cls the `struct MHD_Daemon` of the HTTP server to run
536 */
537static void
538run_daemon (void *cls)
539{
540 struct MHD_Daemon *daemon_handle = cls;
541
542 if (daemon_handle == daemon_handle_v4)
543 hostlist_task_v4 = NULL;
544 else
545 hostlist_task_v6 = NULL;
546 GNUNET_assert (MHD_YES == MHD_run (daemon_handle));
547 if (daemon_handle == daemon_handle_v4)
548 hostlist_task_v4 = prepare_daemon (daemon_handle);
549 else
550 hostlist_task_v6 = prepare_daemon (daemon_handle);
551}
552
553
554/**
555 * Function that queries MHD's select sets and
556 * starts the task waiting for them.
557 *
558 * @param daemon_handle HTTP server to prepare to run
559 */
560static struct GNUNET_SCHEDULER_Task *
561prepare_daemon (struct MHD_Daemon *daemon_handle)
562{
563 struct GNUNET_SCHEDULER_Task *ret;
564 fd_set rs;
565 fd_set ws;
566 fd_set es;
567 struct GNUNET_NETWORK_FDSet *wrs;
568 struct GNUNET_NETWORK_FDSet *wws;
569 int max;
570 MHD_UNSIGNED_LONG_LONG timeout;
571 int haveto;
572 struct GNUNET_TIME_Relative tv;
573
574 FD_ZERO (&rs);
575 FD_ZERO (&ws);
576 FD_ZERO (&es);
577 wrs = GNUNET_NETWORK_fdset_create ();
578 wws = GNUNET_NETWORK_fdset_create ();
579 max = -1;
580 GNUNET_assert (MHD_YES == MHD_get_fdset (daemon_handle, &rs, &ws, &es, &max));
581 haveto = MHD_get_timeout (daemon_handle, &timeout);
582 if (haveto == MHD_YES)
583 tv.rel_value_us = (uint64_t) timeout * 1000LL;
584 else
585 tv = GNUNET_TIME_UNIT_FOREVER_REL;
586 GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1);
587 GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1);
588 ret = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH,
589 tv,
590 wrs,
591 wws,
592 &run_daemon,
593 daemon_handle);
594 GNUNET_NETWORK_fdset_destroy (wrs);
595 GNUNET_NETWORK_fdset_destroy (wws);
596 return ret;
597}
598
599
600static void
601error_cb (void *cls)
602{
603 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
604 "Error in PEERSTORE monitoring\n");
605}
606
607
608static void
609sync_cb (void *cls)
610{
611 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
612 "Done with initial PEERSTORE iteration during monitoring\n");
613}
614
615
616static void
617start_notify (void *cls)
618{
619 (void) cls;
620
621 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
622 "Starting to process new hellos to add to hostlist.\n");
623 peerstore_notify = GNUNET_PEERSTORE_monitor_start (cfg,
624 GNUNET_YES,
625 "peerstore",
626 NULL,
627 GNUNET_PEERSTORE_HELLO_KEY,
628 &error_cb,
629 NULL,
630 &sync_cb,
631 NULL,
632 &process_notify, NULL);
633}
634
635
636/**
637 * Start server offering our hostlist.
638 *
639 * @param c configuration to use
640 * @param st statistics handle to use
641 * @param co core handle to use
642 * @param[out] server_ch set to handler for CORE connect events
643 * @param advertise #GNUNET_YES if we should advertise our hostlist
644 * @return #GNUNET_OK on success
645 */
646int
647GNUNET_HOSTLIST_server_start (const struct GNUNET_CONFIGURATION_Handle *c,
648 struct GNUNET_STATISTICS_Handle *st,
649 struct GNUNET_CORE_Handle *co,
650 GNUNET_CORE_ConnectEventHandler *server_ch,
651 int advertise)
652{
653 unsigned long long port;
654 char *hostname;
655 char *ipv4;
656 char *ipv6;
657 size_t size;
658 struct in_addr i4;
659 struct in6_addr i6;
660 struct sockaddr_in v4;
661 struct sockaddr_in6 v6;
662 const struct sockaddr *sa4;
663 const struct sockaddr *sa6;
664
665 hellos = GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
666 advertising = advertise;
667 if (! advertising)
668 {
669 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
670 "Advertising not enabled on this hostlist server\n");
671 }
672 else
673 {
674 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
675 "Advertising enabled on this hostlist server\n");
676 }
677 cfg = c;
678 stats = st;
679 peerstore = GNUNET_PEERSTORE_connect (cfg);
680 if (NULL == peerstore)
681 {
682 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
683 _ ("Could not access PEERSTORE service. Exiting.\n"));
684 return GNUNET_SYSERR;
685 }
686 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg,
687 "HOSTLIST",
688 "HTTPPORT",
689 &port))
690 return GNUNET_SYSERR;
691 if ((0 == port) || (port > UINT16_MAX))
692 {
693 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
694 _ ("Invalid port number %llu. Exiting.\n"),
695 port);
696 return GNUNET_SYSERR;
697 }
698
699 if (GNUNET_SYSERR ==
700 GNUNET_CONFIGURATION_get_value_string (cfg,
701 "HOSTLIST",
702 "EXTERNAL_DNS_NAME",
703 &hostname))
704 hostname = GNUNET_RESOLVER_local_fqdn_get ();
705 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
706 _ ("Hostlist service starts on %s:%llu\n"),
707 hostname,
708 port);
709 if (NULL != hostname)
710 {
711 size = strlen (hostname);
712 if (size + 15 > MAX_URL_LEN)
713 {
714 GNUNET_break (0);
715 }
716 else
717 {
718 GNUNET_asprintf (&hostlist_uri,
719 "http://%s:%u/",
720 hostname,
721 (unsigned int) port);
722 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
723 _ ("Address to obtain hostlist: `%s'\n"),
724 hostlist_uri);
725 }
726 GNUNET_free (hostname);
727 }
728
729 if (GNUNET_CONFIGURATION_have_value (cfg, "HOSTLIST", "BINDTOIPV4"))
730 {
731 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg,
732 "HOSTLIST",
733 "BINDTOIP",
734 &ipv4))
735 {
736 GNUNET_log (
737 GNUNET_ERROR_TYPE_WARNING,
738 _ ("BINDTOIP does not a valid IPv4 address! Ignoring BINDTOIPV4.\n"));
739 }
740 }
741 else
742 ipv4 = NULL;
743 if (GNUNET_CONFIGURATION_have_value (cfg, "HOSTLIST", "BINDTOIPV6"))
744 {
745 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg,
746 "HOSTLIST",
747 "BINDTOIP",
748 &ipv6))
749 {
750 GNUNET_log (
751 GNUNET_ERROR_TYPE_WARNING,
752 _ ("BINDTOIP does not a valid IPv4 address! Ignoring BINDTOIPV6.\n"));
753 }
754 }
755 else
756 ipv6 = NULL;
757 sa4 = NULL;
758 if (NULL != ipv4)
759 {
760 if (1 == inet_pton (AF_INET, ipv4, &i4))
761 {
762 memset (&v4, 0, sizeof(v4));
763 v4.sin_family = AF_INET;
764 v4.sin_addr = i4;
765 v4.sin_port = htons (port);
766#if HAVE_SOCKADDR_IN_SIN_LEN
767 v4.sin_len = sizeof(v4);
768#endif
769 sa4 = (const struct sockaddr *) &v4;
770 }
771 else
772 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
773 _ (
774 "`%s' is not a valid IPv4 address! Ignoring BINDTOIPV4.\n"),
775 ipv4);
776 GNUNET_free (ipv4);
777 }
778 sa6 = NULL;
779 if (NULL != ipv6)
780 {
781 if (1 == inet_pton (AF_INET6, ipv6, &i6))
782 {
783 memset (&v6, 0, sizeof(v6));
784 v6.sin6_family = AF_INET6;
785 v6.sin6_addr = i6;
786 v6.sin6_port = htons (port);
787#if HAVE_SOCKADDR_IN_SIN_LEN
788 v6.sin6_len = sizeof(v6);
789#endif
790 sa6 = (const struct sockaddr *) &v6;
791 }
792 else
793 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
794 _ (
795 "`%s' is not a valid IPv6 address! Ignoring BINDTOIPV6.\n"),
796 ipv6);
797 GNUNET_free (ipv6);
798 }
799
800 daemon_handle_v6 = MHD_start_daemon (MHD_USE_IPv6 | MHD_USE_DEBUG,
801 (uint16_t) port,
802 &accept_policy_callback,
803 NULL,
804 &access_handler_callback,
805 NULL,
806 MHD_OPTION_CONNECTION_LIMIT,
807 (unsigned int) 128,
808 MHD_OPTION_PER_IP_CONNECTION_LIMIT,
809 (unsigned int) 32,
810 MHD_OPTION_CONNECTION_TIMEOUT,
811 (unsigned int) 16,
812 MHD_OPTION_CONNECTION_MEMORY_LIMIT,
813 (size_t) (16 * 1024),
814 MHD_OPTION_SOCK_ADDR,
815 sa6,
816 MHD_OPTION_END);
817 daemon_handle_v4 = MHD_start_daemon (MHD_NO_FLAG | MHD_USE_DEBUG,
818 (uint16_t) port,
819 &accept_policy_callback,
820 NULL,
821 &access_handler_callback,
822 NULL,
823 MHD_OPTION_CONNECTION_LIMIT,
824 (unsigned int) 128,
825 MHD_OPTION_PER_IP_CONNECTION_LIMIT,
826 (unsigned int) 32,
827 MHD_OPTION_CONNECTION_TIMEOUT,
828 (unsigned int) 16,
829 MHD_OPTION_CONNECTION_MEMORY_LIMIT,
830 (size_t) (16 * 1024),
831 MHD_OPTION_SOCK_ADDR,
832 sa4,
833 MHD_OPTION_END);
834
835 if ((NULL == daemon_handle_v6) && (NULL == daemon_handle_v4))
836 {
837 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
838 _ ("Could not start hostlist HTTP server on port %u\n"),
839 (unsigned short) port);
840 return GNUNET_SYSERR;
841 }
842
843 core = co;
844 *server_ch = &connect_handler;
845 if (NULL != daemon_handle_v4)
846 hostlist_task_v4 = prepare_daemon (daemon_handle_v4);
847 if (NULL != daemon_handle_v6)
848 hostlist_task_v6 = prepare_daemon (daemon_handle_v6);
849 peerstore_notify_task = GNUNET_SCHEDULER_add_delayed (
850 GNUNET_TIME_UNIT_MINUTES,
851 start_notify,
852 NULL);
853 return GNUNET_OK;
854}
855
856
857/**
858 * Stop server offering our hostlist.
859 */
860void
861GNUNET_HOSTLIST_server_stop ()
862{
863 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hostlist server shutdown\n");
864 if (NULL != hostlist_task_v6)
865 {
866 GNUNET_SCHEDULER_cancel (hostlist_task_v6);
867 hostlist_task_v6 = NULL;
868 }
869 if (NULL != hostlist_task_v4)
870 {
871 GNUNET_SCHEDULER_cancel (hostlist_task_v4);
872 hostlist_task_v4 = NULL;
873 }
874 if (NULL != daemon_handle_v4)
875 {
876 MHD_stop_daemon (daemon_handle_v4);
877 daemon_handle_v4 = NULL;
878 }
879 if (NULL != daemon_handle_v6)
880 {
881 MHD_stop_daemon (daemon_handle_v6);
882 daemon_handle_v6 = NULL;
883 }
884 if (NULL != response)
885 {
886 MHD_destroy_response (response);
887 response = NULL;
888 }
889 if (NULL != peerstore_notify)
890 {
891 GNUNET_PEERSTORE_monitor_stop (peerstore_notify);
892 peerstore_notify = NULL;
893 }
894 else if (NULL != peerstore_notify_task)
895 {
896 GNUNET_SCHEDULER_cancel (peerstore_notify_task);
897 }
898 if (NULL != builder)
899 {
900 GNUNET_free (builder->data);
901 GNUNET_free (builder);
902 builder = NULL;
903 }
904 if (NULL != peerstore)
905 {
906 GNUNET_PEERSTORE_disconnect (peerstore);
907 peerstore = NULL;
908 }
909 cfg = NULL;
910 stats = NULL;
911 core = NULL;
912}
913
914
915/* end of gnunet-daemon-hostlist_server.c */
diff --git a/src/service/hostlist/gnunet-daemon-hostlist_server.h b/src/service/hostlist/gnunet-daemon-hostlist_server.h
new file mode 100644
index 000000000..13ba21e82
--- /dev/null
+++ b/src/service/hostlist/gnunet-daemon-hostlist_server.h
@@ -0,0 +1,61 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009 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_server.h
23 * @brief hostlist support. Downloads HELLOs via HTTP.
24 * @author Christian Grothoff
25 */
26
27#ifndef GNUNET_DAEMON_HOSTLIST_SERVER_H
28#define GNUNET_DAEMON_HOSTLIST_SERVER_H
29
30#include "gnunet_core_service.h"
31#include "gnunet_statistics_service.h"
32#include "gnunet_util_lib.h"
33
34
35/**
36 * Start server offering our hostlist.
37 *
38 * @param c configuration to use
39 * @param st statistics handle to use
40 * @param co core handle to use
41 * @param[out] server_ch set to handler for CORE connect events
42 * @param advertise #GNUNET_YES if we should advertise our hostlist
43 * @return #GNUNET_OK on success
44 */
45int
46GNUNET_HOSTLIST_server_start (const struct GNUNET_CONFIGURATION_Handle *c,
47 struct GNUNET_STATISTICS_Handle *st,
48 struct GNUNET_CORE_Handle *core,
49 GNUNET_CORE_ConnectEventHandler *server_ch,
50 int advertise);
51
52
53/**
54 * Stop server offering our hostlist.
55 */
56void
57GNUNET_HOSTLIST_server_stop (void);
58
59
60#endif
61/* end of gnunet-daemon-hostlist_server.h */
diff --git a/src/service/hostlist/hostlist.conf b/src/service/hostlist/hostlist.conf
new file mode 100644
index 000000000..306d83c78
--- /dev/null
+++ b/src/service/hostlist/hostlist.conf
@@ -0,0 +1,45 @@
1[hostlist]
2IMMEDIATE_START = YES
3NOARMBIND = YES
4BINARY = gnunet-daemon-hostlist
5
6# port for hostlist http server
7HTTPPORT = 8080
8
9# External DNS name other peers should use to access this hostlist
10# EXTERNAL_DNS_NAME =
11
12# Where do we store URLs of other hostlists we have learned?
13HOSTLISTFILE = $GNUNET_CONFIG_HOME/hostlist/learned.txt
14
15# Options:
16# -p : provide a hostlist as a hostlist servers
17# -b : bootstrap using configured hostlist servers
18# -e : enable learning advertised hostlists
19# -a : advertise hostlist to other servers
20OPTIONS = -b
21
22# Default list of hostlist servers for bootstrapping
23SERVERS = https://v21.gnunet.org/hostlist
24# http://silent.0xdeadc0de.eu:8080/
25
26# bind hostlist http server to a specific IPv4
27# BINDTOIPV4 =
28
29# bind hostlist http server to a specific IPv6
30# BINDTOIPV6 =
31
32# Hostname or IP of proxy server for downloading hostlists
33# PROXY =
34
35# User name for proxy server
36# PROXY_USERNAME =
37# User password for proxy server
38# PROXY_PASSWORD =
39
40# Type of proxy server,
41# Valid values: HTTP, HTTP_1_0, SOCKS4, SOCKS5, SOCKS4A, SOCKS5_HOSTNAME
42# Default: HTTP
43# PROXY_TYPE = HTTP
44
45
diff --git a/src/service/hostlist/hostlists_learn_peer2.file b/src/service/hostlist/hostlists_learn_peer2.file
new file mode 100644
index 000000000..19d031c3e
--- /dev/null
+++ b/src/service/hostlist/hostlists_learn_peer2.file
Binary files differ
diff --git a/src/service/hostlist/learning_data.conf b/src/service/hostlist/learning_data.conf
new file mode 100644
index 000000000..4252f2524
--- /dev/null
+++ b/src/service/hostlist/learning_data.conf
@@ -0,0 +1,8 @@
1@INLINE@ test_hostlist_defaults.conf
2[hostlist]
3HTTPPORT = 28080
4OPTIONS = -b -e
5SERVERS = http://gnunet.org:8080/
6PORT = 23354
7HOSTNAME = localhost
8
diff --git a/src/service/hostlist/meson.build b/src/service/hostlist/meson.build
new file mode 100644
index 000000000..01e7ecc01
--- /dev/null
+++ b/src/service/hostlist/meson.build
@@ -0,0 +1,23 @@
1gnunetdaemonhostlist_src = ['gnunet-daemon-hostlist.c',
2 'gnunet-daemon-hostlist_server.c',
3 'gnunet-daemon-hostlist_client.c']
4
5configure_file(input : 'hostlist.conf',
6 output : 'hostlist.conf',
7 configuration : cdata,
8 install: true,
9 install_dir: pkgcfgdir)
10
11
12executable ('gnunet-daemon-hostlist',
13 gnunetdaemonhostlist_src,
14 dependencies: [libgnunetutil_dep,
15 libgnunetcore_dep,
16 libgnunethello_dep,
17 libgnunetpeerstore_dep,
18 libgnunetstatistics_dep,
19 mhd_dep,
20 curl_dep],
21 include_directories: [incdir, configuration_inc],
22 install:true,
23 install_dir: get_option('libdir')/'gnunet'/'libexec')
diff --git a/src/service/hostlist/test_gnunet_daemon_hostlist.c b/src/service/hostlist/test_gnunet_daemon_hostlist.c
new file mode 100644
index 000000000..063db2f99
--- /dev/null
+++ b/src/service/hostlist/test_gnunet_daemon_hostlist.c
@@ -0,0 +1,264 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2009, 2016 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 * @file hostlist/test_gnunet_daemon_hostlist.c
22 * @brief test for gnunet_daemon_hostslist.c
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "gnunet_util_lib.h"
27#include "gnunet_arm_service.h"
28#include "gnunet_transport_service.h"
29#include "gnunet_transport_hello_service.h"
30
31
32/**
33 * How long until we give up on transmitting the message?
34 */
35#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 150)
36
37static int ok;
38
39static struct GNUNET_SCHEDULER_Task *timeout_task;
40
41struct PeerContext
42{
43 struct GNUNET_CONFIGURATION_Handle *cfg;
44 struct GNUNET_TRANSPORT_CoreHandle *th;
45 struct GNUNET_MessageHeader *hello;
46 struct GNUNET_TRANSPORT_HelloGetHandle *ghh;
47 struct GNUNET_OS_Process *arm_proc;
48};
49
50static struct PeerContext p1;
51
52static struct PeerContext p2;
53
54
55static void
56clean_up (void *cls)
57{
58 if (NULL != p1.th)
59 {
60 if (NULL != p1.ghh)
61 {
62 GNUNET_TRANSPORT_hello_get_cancel (p1.ghh);
63 p1.ghh = NULL;
64 }
65 GNUNET_TRANSPORT_core_disconnect (p1.th);
66 p1.th = NULL;
67 }
68 if (NULL != p2.th)
69 {
70 if (NULL != p2.ghh)
71 {
72 GNUNET_TRANSPORT_hello_get_cancel (p2.ghh);
73 p2.ghh = NULL;
74 }
75 GNUNET_TRANSPORT_core_disconnect (p2.th);
76 p2.th = NULL;
77 }
78 GNUNET_SCHEDULER_shutdown ();
79}
80
81
82/**
83 * Timeout, give up.
84 */
85static void
86timeout_error (void *cls)
87{
88 timeout_task = NULL;
89 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
90 "Timeout trying to connect peers, test failed.\n");
91 clean_up (NULL);
92}
93
94
95/**
96 * Function called to notify transport users that another
97 * peer connected to us.
98 *
99 * @param cls closure
100 * @param peer the peer that connected
101 * @param mq message queue to send messages to the peer
102 */
103static void *
104notify_connect (void *cls,
105 const struct GNUNET_PeerIdentity *peer,
106 struct GNUNET_MQ_Handle *mq)
107{
108 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peers connected, shutting down.\n");
109 ok = 0;
110 if (NULL != timeout_task)
111 {
112 GNUNET_SCHEDULER_cancel (timeout_task);
113 timeout_task = NULL;
114 }
115 GNUNET_SCHEDULER_add_now (&clean_up, NULL);
116 return NULL;
117}
118
119
120static void
121process_hello (void *cls, const struct GNUNET_MessageHeader *message)
122{
123 struct PeerContext *p = cls;
124
125 GNUNET_TRANSPORT_hello_get_cancel (p->ghh);
126 p->ghh = NULL;
127 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
128 "Received HELLO, starting hostlist service.\n");
129}
130
131
132static void
133setup_peer (struct PeerContext *p, const char *cfgname)
134{
135 char *binary;
136
137 binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-arm");
138 p->cfg = GNUNET_CONFIGURATION_create ();
139 p->arm_proc = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_OUT_AND_ERR
140 | GNUNET_OS_USE_PIPE_CONTROL,
141 NULL,
142 NULL,
143 NULL,
144 binary,
145 "gnunet-service-arm",
146 "-c",
147 cfgname,
148 NULL);
149 GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname));
150 p->th = GNUNET_TRANSPORT_core_connect (p->cfg,
151 NULL,
152 NULL,
153 p,
154 &notify_connect,
155 NULL,
156 NULL);
157 GNUNET_assert (NULL != p->th);
158 p->ghh = GNUNET_TRANSPORT_hello_get (p->cfg,
159 GNUNET_TRANSPORT_AC_ANY,
160 &process_hello,
161 p);
162 GNUNET_free (binary);
163}
164
165
166static void
167waitpid_task (void *cls)
168{
169 struct PeerContext *p = cls;
170
171 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Killing ARM process.\n");
172 if (0 != GNUNET_OS_process_kill (p->arm_proc, GNUNET_TERM_SIG))
173 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
174 if (GNUNET_OK != GNUNET_OS_process_wait (p->arm_proc))
175 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid");
176 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
177 "ARM process %u stopped\n",
178 GNUNET_OS_process_get_pid (p->arm_proc));
179 GNUNET_OS_process_destroy (p->arm_proc);
180 p->arm_proc = NULL;
181 GNUNET_CONFIGURATION_destroy (p->cfg);
182}
183
184
185static void
186stop_arm (struct PeerContext *p)
187{
188 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Asking ARM to stop core service\n");
189 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &waitpid_task, p);
190}
191
192
193/**
194 * Try again to connect to transport service.
195 */
196static void
197shutdown_task (void *cls)
198{
199 stop_arm (&p1);
200 stop_arm (&p2);
201}
202
203
204static void
205run (void *cls,
206 char *const *args,
207 const char *cfgfile,
208 const struct GNUNET_CONFIGURATION_Handle *cfg)
209{
210 GNUNET_assert (ok == 1);
211 ok++;
212 timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &timeout_error, NULL);
213 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
214 setup_peer (&p1, "test_gnunet_daemon_hostlist_peer1.conf");
215 setup_peer (&p2, "test_gnunet_daemon_hostlist_peer2.conf");
216}
217
218
219static int
220check ()
221{
222 char *const argv[] = { "test-gnunet-daemon-hostlist",
223 "-c",
224 "test_gnunet_daemon_hostlist_data.conf",
225 NULL };
226 struct GNUNET_GETOPT_CommandLineOption options[] =
227 { GNUNET_GETOPT_OPTION_END };
228
229 ok = 1;
230 GNUNET_PROGRAM_run ((sizeof(argv) / sizeof(char *)) - 1,
231 argv,
232 "test-gnunet-daemon-hostlist",
233 "nohelp",
234 options,
235 &run,
236 &ok);
237 return ok;
238}
239
240
241int
242main (int argc, char *argv[])
243{
244 int ret;
245
246 GNUNET_DISK_purge_cfg_dir ("test_gnunet_daemon_hostlist_peer1.conf",
247 "GNUNET_TEST_HOME");
248 GNUNET_DISK_purge_cfg_dir ("test_gnunet_daemon_hostlist_peer2.conf",
249 "GNUNET_TEST_HOME");
250 GNUNET_DISK_purge_cfg_dir ("test_gnunet_daemon_hostlist_data.conf",
251 "GNUNET_TEST_HOME");
252 GNUNET_log_setup ("test-gnunet-daemon-hostlist", "WARNING", NULL);
253 ret = check ();
254 GNUNET_DISK_purge_cfg_dir ("test_gnunet_daemon_hostlist_peer1.conf",
255 "GNUNET_TEST_HOME");
256 GNUNET_DISK_purge_cfg_dir ("test_gnunet_daemon_hostlist_peer2.conf",
257 "GNUNET_TEST_HOME");
258 GNUNET_DISK_purge_cfg_dir ("test_gnunet_daemon_hostlist_data.conf",
259 "GNUNET_TEST_HOME");
260 return ret;
261}
262
263
264/* end of test_gnunet_daemon_hostlist.c */
diff --git a/src/service/hostlist/test_gnunet_daemon_hostlist_data.conf b/src/service/hostlist/test_gnunet_daemon_hostlist_data.conf
new file mode 100644
index 000000000..9f853c244
--- /dev/null
+++ b/src/service/hostlist/test_gnunet_daemon_hostlist_data.conf
@@ -0,0 +1,28 @@
1@INLINE@ test_hostlist_defaults.conf
2[transport-tcp]
3PORT = 12968
4
5[arm]
6PORT = 12966
7
8[statistics]
9PORT = 12967
10
11[resolver]
12PORT = 12964
13
14[peerinfo]
15PORT = 12969
16
17[transport]
18PORT = 12965
19
20[core]
21PORT = 12970
22
23[hostlist]
24HTTPPORT = 28080
25SERVERS = http://gnunet.org:8080/
26PORT = 23354
27HOSTNAME = localhost
28
diff --git a/src/service/hostlist/test_gnunet_daemon_hostlist_learning.c b/src/service/hostlist/test_gnunet_daemon_hostlist_learning.c
new file mode 100644
index 000000000..a0656f770
--- /dev/null
+++ b/src/service/hostlist/test_gnunet_daemon_hostlist_learning.c
@@ -0,0 +1,593 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2009, 2010, 2011, 2012, 2016 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 * @file hostlist/test_gnunet_daemon_hostlist_learning.c
22 * @brief test for gnunet_daemon_hostslist.c
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "gnunet_util_lib.h"
27#include "gnunet_arm_service.h"
28#include "gnunet_core_service.h"
29#include "gnunet_transport_service.h"
30#include "gnunet_resolver_service.h"
31#include "gnunet_statistics_service.h"
32
33#define MAX_URL_LEN 1000
34
35/**
36 * How long until wait until testcases fails
37 */
38#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 180)
39
40#define CHECK_INTERVAL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, \
41 1)
42
43
44struct PeerContext
45{
46 struct GNUNET_CONFIGURATION_Handle *cfg;
47 struct GNUNET_MessageHeader *hello;
48 struct GNUNET_CORE_Handle *core;
49 struct GNUNET_STATISTICS_Handle *stats;
50 struct GNUNET_OS_Process *arm_proc;
51};
52
53static int timeout;
54
55static int adv_sent;
56
57static int adv_arrived;
58
59static int learned_hostlist_saved;
60
61static int learned_hostlist_downloaded;
62
63static char *current_adv_uri;
64
65static const struct GNUNET_CONFIGURATION_Handle *cfg;
66
67static struct GNUNET_SCHEDULER_Task *timeout_task;
68
69static struct GNUNET_SCHEDULER_Task *check_task;
70
71static struct PeerContext adv_peer;
72
73static struct PeerContext learn_peer;
74
75static struct GNUNET_STATISTICS_GetHandle *download_stats;
76
77static struct GNUNET_STATISTICS_GetHandle *urisrecv_stat;
78
79static struct GNUNET_STATISTICS_GetHandle *advsent_stat;
80
81
82static void
83shutdown_testcase ()
84{
85 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
86 "Shutdown testcase....\n");
87 if (NULL != timeout_task)
88 {
89 GNUNET_SCHEDULER_cancel (timeout_task);
90 timeout_task = NULL;
91 }
92 if (NULL != download_stats)
93 {
94 GNUNET_STATISTICS_get_cancel (download_stats);
95 download_stats = NULL;
96 }
97 if (NULL != urisrecv_stat)
98 {
99 GNUNET_STATISTICS_get_cancel (urisrecv_stat);
100 urisrecv_stat = NULL;
101 }
102 if (NULL != advsent_stat)
103 {
104 GNUNET_STATISTICS_get_cancel (advsent_stat);
105 advsent_stat = NULL;
106 }
107 if (NULL != adv_peer.stats)
108 {
109 GNUNET_STATISTICS_destroy (adv_peer.stats, GNUNET_NO);
110 adv_peer.stats = NULL;
111 }
112 if (NULL != learn_peer.stats)
113 {
114 GNUNET_STATISTICS_destroy (learn_peer.stats, GNUNET_NO);
115 learn_peer.stats = NULL;
116 }
117 if (NULL != check_task)
118 {
119 GNUNET_SCHEDULER_cancel (check_task);
120 check_task = NULL;
121 }
122 if (NULL != current_adv_uri)
123 {
124 GNUNET_free (current_adv_uri);
125 current_adv_uri = NULL;
126 }
127 if (NULL != adv_peer.core)
128 {
129 GNUNET_CORE_disconnect (adv_peer.core);
130 adv_peer.core = NULL;
131 }
132 if (NULL != learn_peer.core)
133 {
134 GNUNET_CORE_disconnect (learn_peer.core);
135 learn_peer.core = NULL;
136 }
137 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
138 "Killing hostlist server ARM process.\n");
139 if (0 != GNUNET_OS_process_kill (adv_peer.arm_proc,
140 GNUNET_TERM_SIG))
141 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
142 "kill");
143 if (GNUNET_OK !=
144 GNUNET_OS_process_wait (adv_peer.arm_proc))
145 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
146 "waitpid");
147 GNUNET_OS_process_destroy (adv_peer.arm_proc);
148 adv_peer.arm_proc = NULL;
149 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
150 "Killing hostlist client ARM process.\n");
151 if (0 != GNUNET_OS_process_kill (learn_peer.arm_proc,
152 GNUNET_TERM_SIG))
153 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
154 "kill");
155 if (GNUNET_OK !=
156 GNUNET_OS_process_wait (learn_peer.arm_proc))
157 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
158 "waitpid");
159 GNUNET_OS_process_destroy (learn_peer.arm_proc);
160 learn_peer.arm_proc = NULL;
161 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
162 "Shutdown complete....\n");
163}
164
165
166/**
167 * Timeout, give up.
168 */
169static void
170timeout_error (void *cls)
171{
172 timeout_task = NULL;
173 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
174 "Timeout while executing testcase, test failed.\n");
175 timeout = GNUNET_YES;
176 shutdown_testcase ();
177}
178
179
180static void
181process_downloads_done (void *cls, int success)
182{
183 download_stats = NULL;
184}
185
186
187static void
188do_shutdown (void *cls)
189{
190 shutdown_testcase ();
191}
192
193
194static int
195process_downloads (void *cls,
196 const char *subsystem,
197 const char *name,
198 uint64_t value,
199 int is_persistent)
200{
201 if ((value >= 2) &&
202 (GNUNET_NO == learned_hostlist_downloaded))
203 {
204 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
205 "Peer has successfully downloaded advertised URI\n");
206 learned_hostlist_downloaded = GNUNET_YES;
207 if ((learned_hostlist_saved == GNUNET_YES) && (adv_sent == GNUNET_YES))
208 {
209 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
210 }
211 }
212 return GNUNET_OK;
213}
214
215
216static void
217process_uris_recv_done (void *cls, int success)
218{
219 urisrecv_stat = NULL;
220}
221
222
223static int
224process_uris_recv (void *cls,
225 const char *subsystem,
226 const char *name,
227 uint64_t value,
228 int is_persistent)
229{
230 struct PeerContext *pc = cls;
231
232 if ((pc == &learn_peer) &&
233 (value == 1) &&
234 (learned_hostlist_saved == GNUNET_NO))
235 {
236 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
237 "Peer has successfully saved advertised URI\n");
238 learned_hostlist_saved = GNUNET_YES;
239 if ((learned_hostlist_downloaded == GNUNET_YES) &&
240 (adv_sent == GNUNET_YES))
241 {
242 GNUNET_SCHEDULER_add_now (&do_shutdown,
243 NULL);
244 }
245 }
246 return GNUNET_OK;
247}
248
249
250static void
251process_adv_sent_done (void *cls, int success)
252{
253 advsent_stat = NULL;
254}
255
256
257static int
258process_adv_sent (void *cls,
259 const char *subsystem,
260 const char *name,
261 uint64_t value,
262 int is_persistent)
263{
264 if ((value >= 1) && (adv_sent == GNUNET_NO))
265 {
266 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
267 "Server has successfully sent advertisement\n");
268 adv_sent = GNUNET_YES;
269 if ((learned_hostlist_downloaded == GNUNET_YES) &&
270 (learned_hostlist_saved == GNUNET_YES))
271 {
272 GNUNET_SCHEDULER_add_now (&do_shutdown,
273 NULL);
274 }
275 }
276 return GNUNET_OK;
277}
278
279
280/**
281 * Check the server statistics regularly
282 */
283static void
284check_statistics (void *cls)
285{
286 char *stat;
287
288 check_task = NULL;
289 GNUNET_asprintf (&stat,
290 gettext_noop ("# advertised URI `%s' downloaded"),
291 current_adv_uri);
292 if (NULL != learn_peer.stats)
293 {
294 if (NULL != download_stats)
295 GNUNET_STATISTICS_get_cancel (download_stats);
296 download_stats =
297 GNUNET_STATISTICS_get (learn_peer.stats,
298 "hostlist",
299 stat,
300 &process_downloads_done,
301 &process_downloads,
302 &learn_peer);
303 if (NULL != urisrecv_stat)
304 GNUNET_STATISTICS_get_cancel (urisrecv_stat);
305 urisrecv_stat =
306 GNUNET_STATISTICS_get (learn_peer.stats, "hostlist",
307 gettext_noop ("# advertised hostlist URIs"),
308 &process_uris_recv_done, &process_uris_recv,
309 &learn_peer);
310 }
311 GNUNET_free (stat);
312 if (NULL != adv_peer.stats)
313 {
314 if (NULL != advsent_stat)
315 GNUNET_STATISTICS_get_cancel (advsent_stat);
316 advsent_stat =
317 GNUNET_STATISTICS_get (adv_peer.stats, "hostlist",
318 gettext_noop ("# hostlist advertisements send"),
319 &process_adv_sent_done,
320 &process_adv_sent,
321 NULL);
322 }
323 check_task =
324 GNUNET_SCHEDULER_add_delayed (CHECK_INTERVAL,
325 &check_statistics,
326 NULL);
327}
328
329
330static int
331check_ad_arrive (void *cls,
332 const struct GNUNET_MessageHeader *message)
333{
334 const char *end = (const char *) &message[1];
335
336 if ('\0' != end[ntohs (message->size) - sizeof(struct GNUNET_MessageHeader)
337 - 1])
338 {
339 GNUNET_break (0);
340 return GNUNET_SYSERR;
341 }
342 return GNUNET_OK;
343}
344
345
346static void
347handle_ad_arrive (void *cls,
348 const struct GNUNET_MessageHeader *message)
349{
350 char *hostname;
351 char *expected_uri;
352 unsigned long long port;
353 const char *end;
354
355 if (GNUNET_SYSERR ==
356 GNUNET_CONFIGURATION_get_value_number (adv_peer.cfg,
357 "HOSTLIST",
358 "HTTPPORT",
359 &port))
360 {
361 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
362 "Could not read advertising server's configuration\n");
363 return;
364 }
365
366 if (GNUNET_SYSERR ==
367 GNUNET_CONFIGURATION_get_value_string (adv_peer.cfg,
368 "HOSTLIST",
369 "EXTERNAL_DNS_NAME",
370 &hostname))
371 hostname = GNUNET_RESOLVER_local_fqdn_get ();
372 GNUNET_asprintf (&expected_uri,
373 "http://%s:%u/",
374 hostname != NULL ? hostname : "localhost",
375 (unsigned int) port);
376 end = (const char *) &message[1];
377 current_adv_uri = GNUNET_strdup (end);
378 if (0 == strcmp (expected_uri,
379 current_adv_uri))
380 {
381 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
382 "Received hostlist advertisement with URI `%s' as expected\n",
383 current_adv_uri);
384 adv_arrived = GNUNET_YES;
385 adv_sent = GNUNET_YES;
386 }
387 else
388 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
389 "Expected URI `%s' and received URI `%s' differ\n",
390 expected_uri,
391 current_adv_uri);
392 GNUNET_free (expected_uri);
393 GNUNET_free (hostname);
394}
395
396
397static void
398setup_learn_peer (struct PeerContext *p,
399 const char *cfgname)
400{
401 struct GNUNET_MQ_MessageHandler learn_handlers[] = {
402 GNUNET_MQ_hd_var_size (ad_arrive,
403 GNUNET_MESSAGE_TYPE_HOSTLIST_ADVERTISEMENT,
404 struct GNUNET_MessageHeader,
405 NULL),
406 GNUNET_MQ_handler_end ()
407 };
408 char *filename;
409 unsigned int result;
410 char *binary;
411
412 binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-arm");
413 p->cfg = GNUNET_CONFIGURATION_create ();
414 p->arm_proc =
415 GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_OUT_AND_ERR
416 | GNUNET_OS_USE_PIPE_CONTROL,
417 NULL, NULL, NULL,
418 binary,
419 "gnunet-service-arm",
420 "-c", cfgname, NULL);
421 GNUNET_assert (GNUNET_OK ==
422 GNUNET_CONFIGURATION_load (p->cfg,
423 cfgname));
424 if (GNUNET_OK ==
425 GNUNET_CONFIGURATION_get_value_string (p->cfg,
426 "HOSTLIST",
427 "HOSTLISTFILE",
428 &filename))
429 {
430 if (GNUNET_YES == GNUNET_DISK_file_test (filename))
431 {
432 result = unlink (filename);
433 if (result == 0)
434 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
435 _ ("Hostlist file `%s' was removed\n"),
436 filename);
437 }
438 GNUNET_free (filename);
439 }
440 p->core = GNUNET_CORE_connect (p->cfg,
441 NULL,
442 NULL,
443 NULL,
444 NULL,
445 learn_handlers);
446 GNUNET_assert (NULL != p->core);
447 p->stats = GNUNET_STATISTICS_create ("hostlist",
448 p->cfg);
449 GNUNET_assert (NULL != p->stats);
450 GNUNET_free (binary);
451}
452
453
454static void
455setup_adv_peer (struct PeerContext *p,
456 const char *cfgname)
457{
458 char *binary;
459
460 binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-arm");
461 p->cfg = GNUNET_CONFIGURATION_create ();
462 p->arm_proc =
463 GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_OUT_AND_ERR
464 | GNUNET_OS_USE_PIPE_CONTROL,
465 NULL, NULL, NULL,
466 binary,
467 "gnunet-service-arm",
468 "-c", cfgname, NULL);
469 GNUNET_assert (GNUNET_OK ==
470 GNUNET_CONFIGURATION_load (p->cfg,
471 cfgname));
472 p->stats = GNUNET_STATISTICS_create ("hostlist", p->cfg);
473 GNUNET_assert (NULL != p->stats);
474 GNUNET_free (binary);
475}
476
477
478static void
479run (void *cls,
480 char *const *args,
481 const char *cfgfile,
482 const struct GNUNET_CONFIGURATION_Handle *c)
483{
484 timeout = GNUNET_NO;
485 adv_sent = GNUNET_NO;
486
487 adv_arrived = 0;
488 learned_hostlist_saved = GNUNET_NO;
489 learned_hostlist_downloaded = GNUNET_NO;
490
491 cfg = c;
492
493 setup_adv_peer (&adv_peer,
494 "test_learning_adv_peer.conf");
495 setup_learn_peer (&learn_peer,
496 "test_learning_learn_peer.conf");
497 timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
498 &timeout_error,
499 NULL);
500 check_task =
501 GNUNET_SCHEDULER_add_delayed (CHECK_INTERVAL,
502 &check_statistics,
503 NULL);
504}
505
506
507static int
508check ()
509{
510 unsigned int failed;
511
512 char *const argv[] = {
513 "test-gnunet-daemon-hostlist-learning",
514 "-c", "learning_data.conf",
515 NULL
516 };
517 struct GNUNET_GETOPT_CommandLineOption options[] = {
518 GNUNET_GETOPT_OPTION_END
519 };
520
521 GNUNET_PROGRAM_run ((sizeof(argv) / sizeof(char *)) - 1,
522 argv,
523 "test-gnunet-daemon-hostlist-learning",
524 "nohelp",
525 options,
526 &run,
527 NULL);
528 failed = GNUNET_NO;
529 if (timeout == GNUNET_YES)
530 {
531 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
532 "Testcase timeout\n");
533 failed = GNUNET_YES;
534 }
535 if (adv_arrived != GNUNET_YES)
536 {
537 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
538 "Learning peer did not receive advertisement from server\n");
539 failed = GNUNET_YES;
540 }
541 if (learned_hostlist_saved == GNUNET_NO)
542 {
543 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
544 "Advertised hostlist was not saved in datastore\n");
545 failed = GNUNET_YES;
546 }
547 if (learned_hostlist_downloaded == GNUNET_NO)
548 {
549 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
550 "Advertised hostlist could not be downloaded from server\n");
551 failed = GNUNET_YES;
552 }
553 if (adv_sent == GNUNET_NO)
554 {
555 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
556 "Advertised was not sent from server to client\n");
557 failed = GNUNET_YES;
558 }
559 if (GNUNET_YES == failed)
560 return GNUNET_YES;
561 return GNUNET_NO;
562}
563
564
565int
566main (int argc, char *argv[])
567{
568 int ret;
569
570 GNUNET_DISK_purge_cfg_dir ("test_learning_learn_peer.conf",
571 "GNUNET_TEST_HOME");
572 GNUNET_DISK_purge_cfg_dir ("test_learning_adv_peer.conf",
573 "GNUNET_TEST_HOME");
574 GNUNET_log_setup ("test-gnunet-daemon-hostlist",
575 "WARNING",
576 NULL);
577 ret = check ();
578 GNUNET_DISK_purge_cfg_dir ("test_learning_learn_peer.conf",
579 "GNUNET_TEST_HOME");
580 GNUNET_DISK_purge_cfg_dir ("test_learning_adv_peer.conf",
581 "GNUNET_TEST_HOME");
582 if (GNUNET_YES ==
583 GNUNET_DISK_file_test ("hostlists_learn_peer.file"))
584 {
585 if (0 == unlink ("hostlists_learn_peer.file"))
586 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
587 "Hostlist file hostlists_learn_peer.file was removed\n");
588 }
589 return ret;
590}
591
592
593/* end of test_gnunet_daemon_hostlist_learning.c */
diff --git a/src/service/hostlist/test_gnunet_daemon_hostlist_peer1.conf b/src/service/hostlist/test_gnunet_daemon_hostlist_peer1.conf
new file mode 100644
index 000000000..00c57c1e5
--- /dev/null
+++ b/src/service/hostlist/test_gnunet_daemon_hostlist_peer1.conf
@@ -0,0 +1,44 @@
1@INLINE@ test_hostlist_defaults.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-hostlist-peer-1/
4
5[transport-tcp]
6PORT = 12968
7
8[arm]
9PORT = 12966
10UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
11
12[statistics]
13PORT = 12967
14UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
15
16[resolver]
17PORT = 12964
18UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
19
20[peerinfo]
21PORT = 12969
22UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
23
24[transport]
25PORT = 12965
26UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
27
28[core]
29PORT = 12970
30UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-core.sock
31
32[hostlist]
33HTTPPORT = 12980
34HOSTLISTFILE = hostlists_peer1.file
35OPTIONS = -b -p
36SERVERS = http://localhost:22981/
37IMMEDIATE_START = YES
38
39[ats]
40PORT = 12971
41UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-ats.sock
42
43[topology]
44IMMEDIATE_START = YES
diff --git a/src/service/hostlist/test_gnunet_daemon_hostlist_peer2.conf b/src/service/hostlist/test_gnunet_daemon_hostlist_peer2.conf
new file mode 100644
index 000000000..6bcd63fe7
--- /dev/null
+++ b/src/service/hostlist/test_gnunet_daemon_hostlist_peer2.conf
@@ -0,0 +1,44 @@
1@INLINE@ test_hostlist_defaults.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-hostlist-peer-2/
4
5[transport-tcp]
6PORT = 22968
7
8[arm]
9PORT = 22966
10UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
11
12[statistics]
13PORT = 22967
14UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
15
16[resolver]
17PORT = 22964
18UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
19
20[peerinfo]
21PORT = 22969
22UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
23
24[transport]
25PORT = 22965
26UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
27
28[core]
29PORT = 22970
30UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-core.sock
31
32[hostlist]
33HTTPPORT = 22981
34HOSTLISTFILE = hostlists_peer2.file
35OPTIONS = -b -p
36SERVERS = http://localhost:12980/
37IMMEDIATE_START = YES
38
39[ats]
40PORT = 22971
41UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-ats.sock
42
43[topology]
44IMMEDIATE_START = YES
diff --git a/src/service/hostlist/test_gnunet_daemon_hostlist_reconnect.c b/src/service/hostlist/test_gnunet_daemon_hostlist_reconnect.c
new file mode 100644
index 000000000..321f96f3d
--- /dev/null
+++ b/src/service/hostlist/test_gnunet_daemon_hostlist_reconnect.c
@@ -0,0 +1,263 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2010, 2016 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 * @file hostlist/test_gnunet_daemon_hostlist_reconnect.c
22 * @brief test for gnunet-daemon-hostslist.c; tries to re-start the peers
23 * and connect a second time
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_arm_service.h"
29#include "gnunet_transport_service.h"
30#include "gnunet_transport_hello_service.h"
31
32/**
33 * How long until we give up on transmitting the message?
34 */
35#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 150)
36
37static int ok;
38
39static struct GNUNET_SCHEDULER_Task *timeout_task;
40
41struct PeerContext
42{
43 struct GNUNET_CONFIGURATION_Handle *cfg;
44 struct GNUNET_TRANSPORT_CoreHandle *th;
45 struct GNUNET_MessageHeader *hello;
46 struct GNUNET_TRANSPORT_HelloGetHandle *ghh;
47 struct GNUNET_OS_Process *arm_proc;
48};
49
50static struct PeerContext p1;
51
52static struct PeerContext p2;
53
54
55/**
56 * Timeout, give up.
57 */
58static void
59timeout_error (void *cls)
60{
61 timeout_task = NULL;
62 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
63 "Timeout trying to connect peers, test failed.\n");
64 GNUNET_SCHEDULER_shutdown ();
65}
66
67
68/**
69 * Function called to notify transport users that another
70 * peer connected to us.
71 *
72 * @param cls closure
73 * @param peer the peer that connected
74 * @param mq message queue to send to @a peer
75 * @return NULL
76 */
77static void *
78notify_connect (void *cls,
79 const struct GNUNET_PeerIdentity *peer,
80 struct GNUNET_MQ_Handle *mq)
81{
82 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peers connected, shutting down.\n");
83 ok = 0;
84 GNUNET_SCHEDULER_shutdown ();
85 return NULL;
86}
87
88
89static void
90process_hello (void *cls, const struct GNUNET_MessageHeader *message)
91{
92 struct PeerContext *p = cls;
93
94 GNUNET_TRANSPORT_hello_get_cancel (p->ghh);
95 p->ghh = NULL;
96 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
97 "Received HELLO, starting hostlist service.\n");
98}
99
100
101static void
102setup_peer (struct PeerContext *p, const char *cfgname)
103{
104 char *binary;
105
106 binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-arm");
107 p->cfg = GNUNET_CONFIGURATION_create ();
108 p->arm_proc = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_OUT_AND_ERR
109 | GNUNET_OS_USE_PIPE_CONTROL,
110 NULL,
111 NULL,
112 NULL,
113 binary,
114 "gnunet-service-arm",
115 "-c",
116 cfgname,
117 NULL);
118 GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname));
119 p->th = GNUNET_TRANSPORT_core_connect (p->cfg,
120 NULL,
121 NULL,
122 p,
123 &notify_connect,
124 NULL,
125 NULL);
126 GNUNET_assert (NULL != p->th);
127 p->ghh = GNUNET_TRANSPORT_hello_get (p->cfg,
128 GNUNET_TRANSPORT_AC_ANY,
129 &process_hello,
130 p);
131 GNUNET_free (binary);
132}
133
134
135static void
136waitpid_task (void *cls)
137{
138 struct PeerContext *p = cls;
139
140 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Killing ARM process.\n");
141 if (0 != GNUNET_OS_process_kill (p->arm_proc, GNUNET_TERM_SIG))
142 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
143 if (GNUNET_OK != GNUNET_OS_process_wait (p->arm_proc))
144 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid");
145 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
146 "ARM process %u stopped\n",
147 GNUNET_OS_process_get_pid (p->arm_proc));
148 GNUNET_OS_process_destroy (p->arm_proc);
149 p->arm_proc = NULL;
150 GNUNET_CONFIGURATION_destroy (p->cfg);
151}
152
153
154static void
155stop_arm (struct PeerContext *p)
156{
157 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Asking ARM to stop core service\n");
158 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &waitpid_task, p);
159}
160
161
162/**
163 * Try again to connect to transport service.
164 */
165static void
166shutdown_task (void *cls)
167{
168 if (NULL != timeout_task)
169 {
170 GNUNET_SCHEDULER_cancel (timeout_task);
171 timeout_task = NULL;
172 }
173 if (NULL != p1.ghh)
174 {
175 GNUNET_TRANSPORT_hello_get_cancel (p1.ghh);
176 p1.ghh = NULL;
177 }
178 if (NULL != p1.th)
179 {
180 GNUNET_TRANSPORT_core_disconnect (p1.th);
181 p1.th = NULL;
182 }
183 if (NULL != p2.ghh)
184 {
185 GNUNET_TRANSPORT_hello_get_cancel (p2.ghh);
186 p2.ghh = NULL;
187 }
188 if (NULL != p2.th)
189 {
190 GNUNET_TRANSPORT_core_disconnect (p2.th);
191 p2.th = NULL;
192 }
193 stop_arm (&p1);
194 stop_arm (&p2);
195}
196
197
198static void
199run (void *cls,
200 char *const *args,
201 const char *cfgfile,
202 const struct GNUNET_CONFIGURATION_Handle *cfg)
203{
204 GNUNET_assert (ok == 1);
205 ok++;
206 timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &timeout_error, NULL);
207 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
208 setup_peer (&p1, "test_gnunet_daemon_hostlist_peer1.conf");
209 setup_peer (&p2, "test_gnunet_daemon_hostlist_peer2.conf");
210}
211
212
213int
214main (int argcx, char *argvx[])
215{
216 static char *const argv[] = { "test-gnunet-daemon-hostlist",
217 "-c",
218 "test_gnunet_daemon_hostlist_data.conf",
219 NULL };
220 static struct GNUNET_GETOPT_CommandLineOption options[] = {
221 GNUNET_GETOPT_OPTION_END
222 };
223
224 GNUNET_DISK_purge_cfg_dir ("test_gnunet_daemon_hostlist_peer1.conf",
225 "GNUNET_TEST_HOME");
226 GNUNET_DISK_purge_cfg_dir ("test_gnunet_daemon_hostlist_peer2.conf",
227 "GNUNET_TEST_HOME");
228 GNUNET_DISK_purge_cfg_dir ("test_gnunet_daemon_hostlist_data.conf",
229 "GNUNET_TEST_HOME");
230 GNUNET_log_setup ("test-gnunet-daemon-hostlist", "WARNING", NULL);
231 ok = 1;
232 GNUNET_PROGRAM_run ((sizeof(argv) / sizeof(char *)) - 1,
233 argv,
234 "test-gnunet-daemon-hostlist",
235 "nohelp",
236 options,
237 &run,
238 &ok);
239 if (0 == ok)
240 {
241 fprintf (stderr, "%s", ".");
242 /* now do it again */
243 ok = 1;
244 GNUNET_PROGRAM_run ((sizeof(argv) / sizeof(char *)) - 1,
245 argv,
246 "test-gnunet-daemon-hostlist",
247 "nohelp",
248 options,
249 &run,
250 &ok);
251 fprintf (stderr, "%s", ".\n");
252 }
253 GNUNET_DISK_purge_cfg_dir ("test_gnunet_daemon_hostlist_peer1.conf",
254 "GNUNET_TEST_HOME");
255 GNUNET_DISK_purge_cfg_dir ("test_gnunet_daemon_hostlist_peer2.conf",
256 "GNUNET_TEST_HOME");
257 GNUNET_DISK_purge_cfg_dir ("test_gnunet_daemon_hostlist_data.conf",
258 "GNUNET_TEST_HOME");
259 return ok;
260}
261
262
263/* end of test_gnunet_daemon_hostlist_reconnect.c */
diff --git a/src/service/hostlist/test_hostlist_defaults.conf b/src/service/hostlist/test_hostlist_defaults.conf
new file mode 100644
index 000000000..ed6c6b014
--- /dev/null
+++ b/src/service/hostlist/test_hostlist_defaults.conf
@@ -0,0 +1,18 @@
1@INLINE@ ../../../contrib/conf/gnunet/no_forcestart.conf
2@INLINE@ ../../../contrib/conf/gnunet/no_autostart_above_core.conf
3
4[PATHS]
5GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-hostlist/
6
7[transport]
8PLUGINS = tcp
9
10[peerinfo]
11NO_IO = YES
12
13[core]
14PORT = 12470
15
16[nat]
17RETURN_LOCAL_ADDRESSES = YES
18
diff --git a/src/service/hostlist/test_learning_adv_peer.conf b/src/service/hostlist/test_learning_adv_peer.conf
new file mode 100644
index 000000000..3bee3c0c7
--- /dev/null
+++ b/src/service/hostlist/test_learning_adv_peer.conf
@@ -0,0 +1,45 @@
1@INLINE@ test_hostlist_defaults.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-hostlist-peer-1/
4
5[transport-tcp]
6PORT = 22968
7
8[arm]
9PORT = 22966
10UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-hostlist-p2-service-arm.sock
11
12[statistics]
13PORT = 22967
14UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-hostlist-p2-service-statistics.sock
15
16[resolver]
17PORT = 22964
18UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-hostlist-p2-service-resolver.sock
19
20[peerinfo]
21PORT = 22969
22UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-hostlist-p2-service-peerinfo.sock
23
24[transport]
25PORT = 22965
26UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-hostlist-p2-service-transport.sock
27
28[core]
29PORT = 22970
30UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-hostlist-p2-service-core.sock
31
32[hostlist]
33HTTPPORT = 12981
34HOSTLISTFILE = hostlists_adv_peer.file
35OPTIONS = -p -a
36SERVERS = http://localhost:12981/
37EXTERNAL_DNS_NAME = localhost
38IMMEDIATE_START = YES
39
40[ats]
41PORT = 22971
42UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-ats-p2-service-core.sock
43
44[topology]
45IMMEDIATE_START = YES
diff --git a/src/service/hostlist/test_learning_learn_peer.conf b/src/service/hostlist/test_learning_learn_peer.conf
new file mode 100644
index 000000000..0dafe6302
--- /dev/null
+++ b/src/service/hostlist/test_learning_learn_peer.conf
@@ -0,0 +1,44 @@
1@INLINE@ test_hostlist_defaults.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-hostlist-peer-2/
4
5[transport-tcp]
6PORT = 12968
7
8[arm]
9PORT = 12966
10UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-hostlist-p1-service-arm.sock
11
12[statistics]
13PORT = 12967
14UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-hostlist-p1-service-statistics.sock
15
16[resolver]
17PORT = 12964
18UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-hostlist-p1-service-resolver.sock
19
20[peerinfo]
21PORT = 12969
22UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-hostlist-p1-service-peerinfo.sock
23
24[transport]
25PORT = 12965
26UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-hostlist-p1-service-transport.sock
27
28[core]
29PORT = 12970
30UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-hostlist-p1-service-core.sock
31
32[hostlist]
33HTTPPORT = 12980
34HOSTLISTFILE = hostlists_learn_peer.file
35OPTIONS = -b -e
36SERVERS = http://localhost:12981/
37IMMEDIATE_START = YES
38
39[ats]
40PORT = 12971
41UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-ats-p1-service-core.sock
42
43[topology]
44IMMEDIATE_START = YES
diff --git a/src/service/hostlist/test_learning_learn_peer2.conf b/src/service/hostlist/test_learning_learn_peer2.conf
new file mode 100644
index 000000000..dc2956dcc
--- /dev/null
+++ b/src/service/hostlist/test_learning_learn_peer2.conf
@@ -0,0 +1,40 @@
1@INLINE@ test_hostlist_defaults.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-hostlist-peer-3/
4
5[transport-tcp]
6PORT = 32968
7
8[arm]
9PORT = 32966
10UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p3-service-arm.sock
11
12[statistics]
13PORT = 32967
14UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p3-service-statistics.sock
15
16[resolver]
17PORT = 32964
18UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p3-service-resolver.sock
19
20[peerinfo]
21PORT = 32969
22UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p3-service-peerinfo.sock
23
24[transport]
25PORT = 32965
26UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p3-service-transport.sock
27
28[core]
29PORT = 32970
30UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p3-service-core.sock
31
32[hostlist]
33HTTPPORT = 32980
34HOSTLISTFILE = hostlists_learn_peer2.file
35OPTIONS = -b -e
36SERVERS = http://localhost:12981/
37IMMEDIATE_START = YES
38
39[topology]
40IMMEDIATE_START = YES