aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/include/gnunet_nse_service.h115
-rw-r--r--src/nse/Makefile.am65
-rw-r--r--src/nse/gnunet-service-nse.c435
-rw-r--r--src/nse/nse.h119
-rw-r--r--src/nse/nse_api.c299
-rw-r--r--src/nse/test_nse.conf37
-rw-r--r--src/nse/test_nse_api.c182
7 files changed, 1252 insertions, 0 deletions
diff --git a/src/include/gnunet_nse_service.h b/src/include/gnunet_nse_service.h
new file mode 100644
index 000000000..012a61c22
--- /dev/null
+++ b/src/include/gnunet_nse_service.h
@@ -0,0 +1,115 @@
1/*
2 This file is part of GNUnet
3 (C) 2009, 2010 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19 */
20
21#ifndef GNUNET_NSE_SERVICE_H_
22#define GNUNET_NSE_SERVICE_H_
23
24/**
25 * @file include/gnunet_nse_service.h
26 * @brief API to retrieve the current network size estimate,
27 * also to register for notifications whenever a new
28 * network size estimate is calculated.
29 *
30 * @author Nathan Evans
31 */
32
33#ifdef __cplusplus
34extern "C"
35{
36#if 0 /* keep Emacsens' auto-indent happy */
37}
38#endif
39#endif
40
41#include "gnunet_common.h"
42#include "gnunet_configuration_lib.h"
43#include "gnunet_scheduler_lib.h"
44
45/**
46 * Version of the network size estimation API.
47 */
48#define GNUNET_NSE_VERSION 0x00000000
49
50/**
51 * Interval for sending network size estimation flood requests.
52 * Number is in milliseconds.
53 * This needs to be a factor of the number milliseconds in
54 * a day, as the base time used is midnight each day offset
55 * by this amount.
56 *
57 * There are 86400000 milliseconds in a day.
58 */
59#define GNUNET_NSE_INTERVAL 3600000 /* Once per hour */
60
61/**
62 * Number of bits
63 */
64#define GNUNET_NSE_BITS
65
66/**
67 * Handle for the network size estimation service.
68 */
69struct GNUNET_NSE_Handle;
70
71
72/**
73 * Callback to call when network size estimate is updated.
74 *
75 * @param cls closure
76 * @param estimate the value of the current network size estimate
77 * @param std_dev standard deviation (rounded down to nearest integer)
78 * of the size estimation values seen
79 * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration
80 */
81typedef int
82(*GNUNET_NSE_Callback) (void *cls, double estimate, double std_dev);
83
84/**
85 * Connect to the network size estimation service.
86 *
87 * @param cfg the configuration to use
88 * @param func funtion to call with network size estimate
89 * @param func_cls closure to pass for network size estimate callback
90 *
91 * @return handle to use
92 */
93struct GNUNET_NSE_Handle *
94GNUNET_NSE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
95 GNUNET_NSE_Callback func, void *func_cls);
96
97
98/**
99 * Disconnect from network size estimation service
100 *
101 * @param h handle to destroy
102 *
103 */
104void
105GNUNET_NSE_disconnect (struct GNUNET_NSE_Handle *h);
106
107
108#if 0 /* keep Emacsens' auto-indent happy */
109{
110#endif
111#ifdef __cplusplus
112}
113#endif
114
115#endif /* GNUNET_NSE_SERVICE_H_ */
diff --git a/src/nse/Makefile.am b/src/nse/Makefile.am
new file mode 100644
index 000000000..bb8e5f509
--- /dev/null
+++ b/src/nse/Makefile.am
@@ -0,0 +1,65 @@
1INCLUDES = -I$(top_srcdir)/src/include
2
3if MINGW
4 WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols
5endif
6
7if USE_COVERAGE
8 AM_CFLAGS = --coverage -O0
9 XLIB = -lgcov
10endif
11
12
13lib_LTLIBRARIES = libgnunetnse.la
14
15libgnunetnse_la_SOURCES = \
16 nse_api.c nse.h
17libgnunetnse_la_LIBADD = \
18 $(top_builddir)/src/util/libgnunetutil.la \
19 $(GN_LIBINTL) $(XLIB)
20libgnunetnse_la_LDFLAGS = \
21 $(GN_LIB_LDFLAGS) $(WINFLAGS) \
22 -version-info 0:0:0
23
24
25bin_PROGRAMS = \
26 gnunet-service-nse
27
28# gnunet_nse_SOURCES = \
29# gnunet-nse.c
30# gnunet_nse_LDADD = \
31# $(top_builddir)/src/nse/libgnunetnse.la \
32# $(top_builddir)/src/util/libgnunetutil.la \
33# $(GN_LIBINTL)
34# gnunet_nse_DEPENDENCIES = \
35# libgnunetnse.la
36
37gnunet_service_nse_SOURCES = \
38 gnunet-service-nse.c
39gnunet_service_nse_LDADD = \
40 $(top_builddir)/src/nse/libgnunetnse.la \
41 $(top_builddir)/src/util/libgnunetutil.la \
42 $(top_builddir)/src/core/libgnunetcore.la \
43 $(GN_LIBINTL)
44gnunet_service_nse_DEPENDENCIES = \
45 libgnunetnse.la
46
47check_PROGRAMS = \
48 test_nse_api
49
50if ENABLE_TEST_RUN
51TESTS = $(check_PROGRAMS) $(check_SCRIPTS)
52endif
53
54test_nse_api_SOURCES = \
55 test_nse_api.c
56test_nse_api_LDADD = \
57 $(top_builddir)/src/nse/libgnunetnse.la \
58 $(top_builddir)/src/util/libgnunetutil.la
59
60
61EXTRA_DIST = \
62 test_nse_api_data.conf \
63 $(check_SCRIPTS)
64
65
diff --git a/src/nse/gnunet-service-nse.c b/src/nse/gnunet-service-nse.c
new file mode 100644
index 000000000..6c4466bc7
--- /dev/null
+++ b/src/nse/gnunet-service-nse.c
@@ -0,0 +1,435 @@
1/*
2 This file is part of GNUnet.
3 (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file nse/gnunet-service-nse.c
23 * @brief network size estimation service
24 * @author Nathan Evans
25 *
26 * The purpose of this service is to estimate the size of the network.
27 * Given a specified interval, each peer hashes the most recent
28 * timestamp which is evenly divisible by that interval. This hash
29 * is compared in distance to the peer identity to choose an offset.
30 * The closer the peer identity to the hashed timestamp, the earlier
31 * the peer sends out a "nearest peer" message. The closest peer's
32 * message should thus be received before any others, which stops
33 * those peer from sending their messages at a later duration. So
34 * every peer should receive the same nearest peer message, and
35 * from this can calculate the expected number of peers in the
36 * network.
37 *
38 */
39#include "platform.h"
40#include "gnunet_client_lib.h"
41#include "gnunet_constants.h"
42#include "gnunet_container_lib.h"
43#include "gnunet_protocols.h"
44#include "gnunet_service_lib.h"
45#include "gnunet_server_lib.h"
46#include "gnunet_core_service.h"
47#include "gnunet_time_lib.h"
48#include "gnunet_nse_service.h"
49#include "nse.h"
50
51#define DEFAULT_HISTORY_SIZE 10
52
53#define DEFAULT_CORE_QUEUE_SIZE 32
54
55#define MILLISECONDS_PER_DAY 86400000
56
57/**
58 * Entry in the list of clients which
59 * should be notified upon a new network
60 * size estimate calculation.
61 */
62struct ClientListEntry
63{
64 /**
65 * Pointer to previous entry
66 */
67 struct ClientListEntry *prev;
68
69 /**
70 * Pointer to next entry
71 */
72 struct ClientListEntry *next;
73
74 /**
75 * Client to notify.
76 */
77 struct GNUNET_SERVER_Client *client;
78};
79
80/**
81 * Handle to our current configuration.
82 */
83static const struct GNUNET_CONFIGURATION_Handle *cfg;
84
85/**
86 * Handle to the core service.
87 */
88struct GNUNET_CORE_Handle *coreAPI;
89
90/**
91 * Copy of this peer's identity.
92 */
93static struct GNUNET_PeerIdentity my_identity;
94
95/**
96 * Head of global list of clients.
97 */
98static struct ClientListEntry *cle_head;
99
100/**
101 * Tail of global list of clients.
102 */
103static struct ClientListEntry *cle_tail;
104
105/**
106 * The current network size estimate.
107 */
108static double current_size_estimate;
109
110/**
111 * The standard deviation of the last
112 * DEFAULT_HISTORY_SIZE network size estimates.
113 */
114static double current_std_dev;
115
116/**
117 * Array of the last DEFAULT_HISTORY_SIZE
118 * network size estimates.
119 */
120//static double *size_estimates[DEFAULT_HISTORY_SIZE];
121
122/**
123 * Task scheduled to send flood message.
124 */
125static GNUNET_SCHEDULER_TaskIdentifier flood_task;
126
127/**
128 * Notification context, simplifies client broadcasts.
129 */
130static struct GNUNET_SERVER_NotificationContext *nc;
131
132/**
133 * The previous major time.
134 */
135struct GNUNET_TIME_Absolute previous_timestamp;
136
137/**
138 * The next major time.
139 */
140static struct GNUNET_TIME_Absolute next_timestamp;
141
142/**
143 * Base increment of time to add to send time.
144 */
145static struct GNUNET_TIME_Relative increment;
146
147/**
148 * The current network size estimate message.
149 */
150static struct GNUNET_NSE_ClientMessage current_estimate_message;
151
152/**
153 * Handler for START message from client, triggers an
154 * immediate current network estimate notification.
155 * Also, we remember the client for updates upon future
156 * estimate measurements.
157 *
158 * @param cls unused
159 * @param client who sent the message
160 * @param message the message received
161 */
162static void
163handle_start_message (void *cls,
164 struct GNUNET_SERVER_Client *client,
165 const struct GNUNET_MessageHeader *message)
166{
167 if ((ntohs (message->size) != sizeof(struct GNUNET_MessageHeader))
168 || (ntohs (message->type) != GNUNET_MESSAGE_TYPE_NSE_START))
169 return;
170
171#if DEBUG_NSE
172 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "NSE", "Received START message from client\n");
173#endif
174 GNUNET_SERVER_notification_context_add (nc, client);
175 GNUNET_SERVER_notification_context_unicast (nc, client,
176 &current_estimate_message.header,
177 GNUNET_NO);
178 GNUNET_SERVER_receive_done(client, GNUNET_OK);
179}
180
181/**
182 * Core handler for size estimate flooding messages.
183 *
184 * @param cls closure
185 * @param message message
186 * @param peer peer identity this notification is about
187 * @param atsi performance data
188 *
189 */
190static int
191handle_p2p_size_estimate (void *cls,
192 const struct GNUNET_PeerIdentity *peer,
193 const struct GNUNET_MessageHeader *message,
194 const struct GNUNET_TRANSPORT_ATS_Information
195 *atsi)
196{
197
198 return GNUNET_OK;
199}
200
201
202/**
203 * Send a flood message containing our peer's public key
204 * and the hashed current timestamp.
205 */
206static void
207send_flood_message (void *cls,
208 const struct GNUNET_SCHEDULER_TaskContext * tc)
209{
210 if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
211 return;
212}
213
214/**
215 * A client disconnected. Remove it from the
216 * global DLL of clients.
217 *
218 * @param cls closure, NULL
219 * @param client identification of the client
220 */
221static void
222handle_client_disconnect (void *cls,
223 struct GNUNET_SERVER_Client* client)
224{
225 struct ClientListEntry *cle;
226
227 while (NULL != (cle = cle_head))
228 cle = cle->next;
229
230 if (cle != NULL)
231 {
232 GNUNET_SERVER_client_drop(cle->client);
233 GNUNET_CONTAINER_DLL_remove(cle_head,
234 cle_tail,
235 cle);
236 GNUNET_free(cle);
237 }
238 if (coreAPI != NULL)
239 {
240 GNUNET_CORE_disconnect(coreAPI);
241 coreAPI = NULL;
242 }
243}
244
245/**
246 * Task run during shutdown.
247 *
248 * @param cls unused
249 * @param tc unused
250 */
251static void
252shutdown_task (void *cls,
253 const struct GNUNET_SCHEDULER_TaskContext *tc)
254{
255 struct ClientListEntry *cle;
256
257 GNUNET_SERVER_notification_context_destroy (nc);
258 nc = NULL;
259 while (NULL != (cle = cle_head))
260 {
261 GNUNET_SERVER_client_drop (cle->client);
262 GNUNET_CONTAINER_DLL_remove (cle_head,
263 cle_tail,
264 cle);
265 GNUNET_free (cle);
266 }
267
268 if (coreAPI != NULL)
269 {
270 GNUNET_CORE_disconnect(coreAPI);
271 coreAPI = NULL;
272 }
273
274}
275
276
277/**
278 * Task to schedule a flood message to be sent.
279 *
280 * @param cls closure
281 * @param tc context information (why was this task triggered now)
282 */
283static void schedule_flood_message (void *cls,
284 const struct
285 GNUNET_SCHEDULER_TaskContext * tc)
286{
287 GNUNET_HashCode timestamp_hash;
288 struct GNUNET_TIME_Absolute curr_time;
289 unsigned int matching_bits;
290
291 /* Get the current UTC time */
292 curr_time = GNUNET_TIME_absolute_get();
293 /* Find the previous interval start time */
294 previous_timestamp.abs_value = (curr_time.abs_value / GNUNET_NSE_INTERVAL) * GNUNET_NSE_INTERVAL;
295 /* Find the next interval start time */
296 next_timestamp.abs_value = (curr_time.abs_value / GNUNET_NSE_INTERVAL) * (GNUNET_NSE_INTERVAL + 1);
297
298 GNUNET_CRYPTO_hash(&next_timestamp.abs_value, sizeof(uint64_t), &timestamp_hash);
299 matching_bits = GNUNET_CRYPTO_hash_matching_bits(&timestamp_hash, &my_identity.hashPubKey);
300
301 GNUNET_SCHEDULER_add_delayed (
302 GNUNET_TIME_relative_add (
303 GNUNET_TIME_relative_multiply (
304 increment,
305 matching_bits),
306 GNUNET_TIME_absolute_get_remaining (
307 next_timestamp)),
308 &send_flood_message, NULL);
309}
310
311/**
312 * Called on core init/fail.
313 *
314 * @param cls service closure
315 * @param server handle to the server for this service
316 * @param identity the public identity of this peer
317 * @param publicKey the public key of this peer
318 */
319void
320core_init (void *cls,
321 struct GNUNET_CORE_Handle *server,
322 const struct GNUNET_PeerIdentity *identity,
323 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *publicKey)
324{
325 if (server == NULL)
326 {
327#if DEBUG_NSE
328 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
329 "%s: Connection to core FAILED!\n", "nse",
330 GNUNET_i2s (identity));
331#endif
332 GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
333 return;
334 }
335#if DEBUG_NSE
336 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
337 "%s: Core connection initialized, I am peer: %s\n", "nse",
338 GNUNET_i2s (identity));
339#endif
340
341 /* Copy our identity so we can use it */
342 memcpy (&my_identity, identity, sizeof (struct GNUNET_PeerIdentity));
343
344 flood_task = GNUNET_SCHEDULER_add_now(&schedule_flood_message, NULL);
345}
346
347/**
348 * Handle network size estimate clients.
349 *
350 * @param cls closure
351 * @param server the initialized server
352 * @param c configuration to use
353 */
354static void
355run (void *cls,
356 struct GNUNET_SERVER_Handle *server,
357 const struct GNUNET_CONFIGURATION_Handle *c)
358{
359 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
360 {&handle_start_message, NULL, GNUNET_MESSAGE_TYPE_NSE_START, 0},
361 {NULL, NULL, 0, 0}
362 };
363
364 static const struct GNUNET_CORE_MessageHandler core_handlers[] = {
365 {&handle_p2p_size_estimate, GNUNET_MESSAGE_TYPE_NSE_P2P_FLOOD, 0},
366 {NULL, 0, 0}
367 };
368
369 cfg = c;
370 GNUNET_SERVER_add_handlers (server, handlers);
371 nc = GNUNET_SERVER_notification_context_create (server, 16);
372 GNUNET_SERVER_disconnect_notify (server,
373 &handle_client_disconnect,
374 NULL);
375
376 /** Connect to core service and register core handlers */
377 coreAPI = GNUNET_CORE_connect (cfg, /* Main configuration */
378 DEFAULT_CORE_QUEUE_SIZE, /* queue size */
379 NULL, /* Closure passed to functions */
380 &core_init, /* Call core_init once connected */
381 NULL, /* Handle connects */
382 NULL, /* Handle disconnects */
383 NULL, /* Do we care about "status" updates? */
384 NULL, /* Don't want notified about all incoming messages */
385 GNUNET_NO, /* For header only inbound notification */
386 NULL, /* Don't want notified about all outbound messages */
387 GNUNET_NO, /* For header only outbound notification */
388 core_handlers); /* Register these handlers */
389
390 if (coreAPI == NULL)
391 {
392 GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
393 return;
394 }
395
396 increment
397 = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
398 GNUNET_NSE_INTERVAL
399 / (sizeof(GNUNET_HashCode)
400 * 8));
401 /* Set we have no idea defaults for network size estimate */
402 current_size_estimate = NAN;
403 current_std_dev = NAN;
404
405 current_estimate_message.header.size = htons(sizeof(struct GNUNET_NSE_ClientMessage));
406 current_estimate_message.header.type = htons(GNUNET_MESSAGE_TYPE_NSE_ESTIMATE);
407 current_estimate_message.size_estimate = current_size_estimate;
408 current_estimate_message.std_deviation = current_std_dev;
409
410 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
411 &shutdown_task,
412 NULL);
413}
414
415
416/**
417 * The main function for the statistics service.
418 *
419 * @param argc number of arguments from the command line
420 * @param argv command line arguments
421 * @return 0 ok, 1 on error
422 */
423int
424main (int argc, char *const *argv)
425{
426 return (GNUNET_OK ==
427 GNUNET_SERVICE_run (argc,
428 argv,
429 "nse",
430 GNUNET_SERVICE_OPTION_NONE,
431 &run, NULL)) ? 0 : 1;
432}
433
434/* End of gnunet-service-nse.c */
435
diff --git a/src/nse/nse.h b/src/nse/nse.h
new file mode 100644
index 000000000..ee9832dc6
--- /dev/null
+++ b/src/nse/nse.h
@@ -0,0 +1,119 @@
1/*
2 This file is part of GNUnet.
3 (C) 2001-2011 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @author Nathan Evans
23 * @file nse/nse.h
24 *
25 * @brief Common type definitions for the network size estimation
26 * service and API.
27 */
28#ifndef NSE_H
29#define NSE_H
30
31#include "gnunet_common.h"
32
33#define DEBUG_NSE GNUNET_YES
34
35#define SIGNED_TIMESTAMP_SIZE sizeof(struct GNUNET_TIME_Absolute)
36
37/** FIXME: define NSE message types here. */
38
39struct GNUNET_Signed_Timestamp
40{
41 char data[SIGNED_TIMESTAMP_SIZE];
42};
43
44/**
45 * Network size estimate sent from the service
46 * to clients. Contains the current size estimate
47 * (or 0 if none has been calculated) and the
48 * standard deviation of known estimates.
49 *
50 */
51struct GNUNET_NSE_ClientMessage
52{
53 /**
54 * Type: GNUNET_MESSAGE_TYPE_NSE_UPDATE
55 */
56 struct GNUNET_MessageHeader header;
57
58 /*
59 * The current estimated network size.
60 */
61 double size_estimate;
62
63 /**
64 * The standard deviation (rounded down
65 * to the nearest integer) of size
66 * estimations.
67 */
68 double std_deviation;
69};
70
71/**
72 * Network size estimate reply; sent when "this"
73 * peer's timer has run out before receiving a
74 * valid reply from another peer.
75 *
76 * FIXME: Is this the right way to do this?
77 * I think we need to include both the public
78 * key and the timestamp signed by the private
79 * key. This way a recipient
80 * can verify that the peer at least generated
81 * the public/private key pair, and that the
82 * timestamp matches what the current peer
83 * believes it should be. The receiving peer
84 * would then check whether the XOR of the peer
85 * identity and the timestamp is within a
86 * reasonable range of the current time
87 * (+/- N seconds). If a closer message which
88 * also verifies hasn't been received (or this
89 * message is a duplicate), the peer
90 * calculates the size estimate and forwards
91 * the request to all other peers.
92 *
93 * Hmm... Is it enought to *just* send the peer
94 * identity? Obviously this is smaller, but it
95 * doesn't allow us to verify that the
96 * public/private key pair were generated, right?
97 */
98struct GNUNET_NSE_ReplyMessage
99{
100 /**
101 * Type: GNUNET_MESSAGE_TYPE_NSE_REPLY
102 */
103 struct GNUNET_MessageHeader header;
104
105 /**
106 * The current timestamp value (which all
107 * peers should agree on) signed by the
108 * private key of the initiating peer.
109 */
110 struct GNUNET_Signed_Timestamp timestamp;
111
112 /**
113 * Public key of the originator, signed timestamp
114 * is decrypted by this.
115 */
116 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey;
117};
118
119#endif
diff --git a/src/nse/nse_api.c b/src/nse/nse_api.c
new file mode 100644
index 000000000..20c28e94f
--- /dev/null
+++ b/src/nse/nse_api.c
@@ -0,0 +1,299 @@
1/*
2 This file is part of GNUnet.
3 (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file nse/nse_api.c
23 * @brief api to get information from the network size estimation service
24 * @author Nathan Evans
25 *
26 * TODO:
27 */
28#include "platform.h"
29#include "gnunet_client_lib.h"
30#include "gnunet_constants.h"
31#include "gnunet_container_lib.h"
32#include "gnunet_arm_service.h"
33#include "gnunet_hello_lib.h"
34#include "gnunet_protocols.h"
35#include "gnunet_server_lib.h"
36#include "gnunet_time_lib.h"
37#include "gnunet_nse_service.h"
38#include "nse.h"
39
40
41/**
42 * Handle for the service.
43 */
44struct GNUNET_NSE_Handle
45{
46 /**
47 * Configuration to use.
48 */
49 const struct GNUNET_CONFIGURATION_Handle *cfg;
50
51 /**
52 * Socket (if available).
53 */
54 struct GNUNET_CLIENT_Connection *client;
55
56 /**
57 * Currently pending transmission request.
58 */
59 struct GNUNET_CLIENT_TransmitHandle *th;
60
61 /**
62 * Task doing exponential back-off trying to reconnect.
63 */
64 GNUNET_SCHEDULER_TaskIdentifier reconnect_task;
65
66 /**
67 * Time for next connect retry.
68 */
69 struct GNUNET_TIME_Relative reconnect_delay;
70
71 /**
72 * Should this handle auto-destruct once all actions have
73 * been processed?
74 */
75 int do_destroy;
76
77 /**
78 * Are we currently receiving from the service?
79 */
80 int receiving;
81
82 /**
83 * Callback function to call when message is received.
84 */
85 GNUNET_NSE_Callback recv_cb;
86
87 /**
88 * Closure to pass to callback.
89 */
90 void *recv_cb_cls;
91
92};
93
94
95/**
96 * Type of a function to call when we receive a message
97 * from the service.
98 *
99 * @param cls closure
100 * @param msg message received, NULL on timeout or fatal error
101 */
102void message_handler (void *cls,
103 const struct GNUNET_MessageHeader * msg)
104{
105 struct GNUNET_NSE_Handle *h = cls;
106 struct GNUNET_NSE_ClientMessage *client_msg;
107
108 if ((ntohs (msg->size) < sizeof(struct GNUNET_NSE_ClientMessage))
109 || (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_NSE_ESTIMATE))
110 {
111#if DEBUG_NSE
112 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
113 "%s: received incorrect message (size %d < %d) from service!",
114 "NSE API", ntohs (msg->size),
115 sizeof(struct GNUNET_NSE_ClientMessage));
116#endif
117 return;
118 }
119
120 client_msg = (struct GNUNET_NSE_ClientMessage *)msg;
121
122 h->recv_cb (h->recv_cb_cls, client_msg->size_estimate,
123 client_msg->std_deviation);
124
125 GNUNET_CLIENT_receive (h->client,
126 &message_handler, h, GNUNET_TIME_UNIT_FOREVER_REL);
127}
128
129static void
130reconnect (void *cls,
131 const struct GNUNET_SCHEDULER_TaskContext *tc);
132
133/**
134 * Reschedule a connect attempt to the service.
135 *
136 * @param h transport service to reconnect
137 */
138static void
139reschedule_connect (struct GNUNET_NSE_Handle *h)
140{
141 GNUNET_assert (h->reconnect_task == GNUNET_SCHEDULER_NO_TASK);
142
143 if (NULL != h->th)
144 {
145 GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
146 h->th = NULL;
147 }
148 if (NULL != h->client)
149 {
150 GNUNET_CLIENT_disconnect (h->client, GNUNET_NO);
151 h->client = NULL;
152 }
153
154#if DEBUG_NSE
155 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
156 "Scheduling task to reconnect to nse service in %llu ms.\n",
157 h->reconnect_delay.rel_value);
158#endif
159 h->reconnect_task
160 = GNUNET_SCHEDULER_add_delayed (h->reconnect_delay,
161 &reconnect, h);
162 if (h->reconnect_delay.rel_value == 0)
163 {
164 h->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS;
165 }
166 else
167 {
168 h->reconnect_delay = GNUNET_TIME_relative_multiply (h->reconnect_delay, 2);
169 h->reconnect_delay = GNUNET_TIME_relative_min (GNUNET_TIME_UNIT_SECONDS,
170 h->reconnect_delay);
171 }
172}
173
174/**
175 * Transmit START message to service.
176 *
177 * @param cls unused
178 * @param size number of bytes available in buf
179 * @param buf where to copy the message
180 * @return number of bytes copied to buf
181 */
182static size_t
183send_start (void *cls, size_t size, void *buf)
184{
185 struct GNUNET_NSE_Handle *h = cls;
186 struct GNUNET_MessageHeader *msg;
187
188 h->th = NULL;
189 if (buf == NULL)
190 {
191 /* Connect error... */
192#if DEBUG_NSE
193 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
194 "Shutdown while trying to transmit `%s' request.\n",
195 "START");
196#endif
197 reschedule_connect(h);
198 return 0;
199 }
200#if DEBUG_NSE
201 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
202 "Transmitting `%s' request.\n", "START");
203#endif
204 GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader));
205
206 msg = (struct GNUNET_MessageHeader *)buf;
207 msg->size = htons (sizeof (struct GNUNET_MessageHeader));
208 msg->type = htons (GNUNET_MESSAGE_TYPE_NSE_START);
209 GNUNET_CLIENT_receive (h->client,
210 &message_handler, h, GNUNET_TIME_UNIT_FOREVER_REL);
211 return sizeof (struct GNUNET_MessageHeader);
212}
213
214/**
215 * Try again to connect to network size estimation service.
216 *
217 * @param cls the handle to the transport service
218 * @param tc scheduler context
219 */
220static void
221reconnect (void *cls,
222 const struct GNUNET_SCHEDULER_TaskContext *tc)
223{
224 struct GNUNET_NSE_Handle *h = cls;
225
226 h->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
227 if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
228 {
229 /* shutdown, just give up */
230 return;
231 }
232#if DEBUG_NSE
233 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
234 "Connecting to network size estimation service.\n");
235#endif
236 GNUNET_assert (h->client == NULL);
237 h->client = GNUNET_CLIENT_connect ("nse", h->cfg);
238 GNUNET_assert (h->client != NULL);
239
240 h->th =
241 GNUNET_CLIENT_notify_transmit_ready (h->client,
242 sizeof(struct GNUNET_MessageHeader),
243 GNUNET_TIME_UNIT_FOREVER_REL,
244 GNUNET_NO,
245 &send_start,
246 h);
247 GNUNET_assert(h->th != NULL);
248}
249
250/**
251 * Connect to the network size estimation service.
252 *
253 * @param cfg the configuration to use
254 * @param func funtion to call with network size estimate
255 * @param func_cls closure to pass for network size estimate callback
256 *
257 * @return handle to use
258 */
259struct GNUNET_NSE_Handle *
260GNUNET_NSE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
261 GNUNET_NSE_Callback func, void *func_cls)
262{
263 struct GNUNET_NSE_Handle *ret;
264
265 ret = GNUNET_malloc (sizeof (struct GNUNET_NSE_Handle));
266
267 if (func == NULL)
268 return NULL;
269
270 ret->cfg = cfg;
271 ret->recv_cb = func;
272 ret->recv_cb_cls = func_cls;
273 ret->reconnect_delay = GNUNET_TIME_UNIT_ZERO;
274 ret->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect, ret);
275 return ret;
276}
277
278/**
279 * Disconnect from network size estimation service
280 *
281 * @param h handle to destroy
282 *
283 */
284void
285GNUNET_NSE_disconnect (struct GNUNET_NSE_Handle *h)
286{
287 GNUNET_assert(h != NULL);
288 if (h->reconnect_task != GNUNET_SCHEDULER_NO_TASK)
289 {
290 GNUNET_SCHEDULER_cancel(h->reconnect_task);
291 h->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
292 }
293 if (h->th != NULL)
294 GNUNET_CLIENT_notify_transmit_ready_cancel(h->th);
295 if (h->client != NULL)
296 GNUNET_CLIENT_disconnect(h->client, GNUNET_NO);
297
298 GNUNET_free(h);
299}
diff --git a/src/nse/test_nse.conf b/src/nse/test_nse.conf
new file mode 100644
index 000000000..554cc4c0f
--- /dev/null
+++ b/src/nse/test_nse.conf
@@ -0,0 +1,37 @@
1[PATHS]
2SERVICEHOME = /tmp/test-gnunetd-nse/
3DEFAULTCONFIG = test_nse.conf
4
5[nse]
6PORT = 22353
7UNIXPATH = /tmp/test-nse-service-nse.unix
8AUTOSTART = YES
9DEBUG = YES
10
11[arm]
12PORT = 22354
13DEFAULTSERVICES = nse
14UNIXPATH = /tmp/test-nse-service-arm.unix
15#DEBUG = YES
16
17[fs]
18AUTOSTART = NO
19
20[datastore]
21AUTOSTART = NO
22
23[dht]
24AUTOSTART = NO
25
26[transport]
27AUTOSTART = NO
28
29[core]
30AUTOSTART = YES
31
32[peerinfo]
33AUTOSTART = NO
34
35[dns]
36AUTOSTART = NO
37
diff --git a/src/nse/test_nse_api.c b/src/nse/test_nse_api.c
new file mode 100644
index 000000000..f7274640a
--- /dev/null
+++ b/src/nse/test_nse_api.c
@@ -0,0 +1,182 @@
1/*
2 This file is part of GNUnet.
3 (C) 2009 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20/**
21 * @file nse/test_nse_api.c
22 * @brief testcase for nse_api.c
23 */
24#include "platform.h"
25#include "gnunet_common.h"
26#include "gnunet_getopt_lib.h"
27#include "gnunet_os_lib.h"
28#include "gnunet_program_lib.h"
29#include "gnunet_scheduler_lib.h"
30#include "gnunet_nse_service.h"
31
32#define DEBUG_NSE GNUNET_YES
33
34#define START_ARM GNUNET_YES
35
36static struct GNUNET_NSE_Handle *h;
37
38GNUNET_SCHEDULER_TaskIdentifier die_task;
39
40struct PeerContext
41{
42 struct GNUNET_CONFIGURATION_Handle *cfg;
43#if START_ARM
44 struct GNUNET_OS_Process *arm_proc;
45#endif
46};
47
48static struct PeerContext p1;
49
50/**
51 * Signature of the main function of a task.
52 *
53 * @param cls closure
54 * @param tc context information (why was this task triggered now)
55 */
56static void end_test (void *cls,
57 const struct GNUNET_SCHEDULER_TaskContext * tc)
58{
59 if (h != NULL)
60 {
61 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
62 "Disconnecting from NSE service.\n");
63 GNUNET_NSE_disconnect (h);
64 }
65}
66
67/**
68 * Callback to call when network size estimate is updated.
69 *
70 * @param cls unused
71 * @param estimate the value of the current network size estimate
72 * @param std_dev standard deviation (rounded down to nearest integer)
73 * of the size estimation values seen
74 * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration
75 */
76static int
77check_nse_message (void *cls, double estimate, double std_dev)
78{
79 int *ok = cls;
80
81 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
82 "Received NSE message, estimate %f, standard deviation %f.\n");
83 /* Fantastic check below. Expect NaN, the only thing not equal to itself. */
84 if ((estimate != estimate) && (std_dev != std_dev))
85 (*ok) = 0;
86
87 if (die_task != GNUNET_SCHEDULER_NO_TASK)
88 GNUNET_SCHEDULER_cancel(die_task);
89 GNUNET_SCHEDULER_add_now(&end_test, NULL);
90 return GNUNET_OK;
91}
92
93static void
94setup_peer (struct PeerContext *p, const char *cfgname)
95{
96 p->cfg = GNUNET_CONFIGURATION_create ();
97#if START_ARM
98 p->arm_proc = GNUNET_OS_start_process (NULL, NULL, "gnunet-service-arm",
99 "gnunet-service-arm",
100#if VERBOSE_ARM
101 "-L", "DEBUG",
102#endif
103 "-c", cfgname, NULL);
104#endif
105 GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname));
106
107}
108
109static void
110stop_arm (struct PeerContext *p)
111{
112#if START_ARM
113 if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM))
114 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
115 GNUNET_OS_process_wait (p->arm_proc);
116 GNUNET_OS_process_close (p->arm_proc);
117 p->arm_proc = NULL;
118#endif
119 GNUNET_CONFIGURATION_destroy (p->cfg);
120}
121
122static void
123run (void *cls,
124 char *const *args,
125 const char *cfgfile,
126 const struct GNUNET_CONFIGURATION_Handle *cfg)
127{
128 die_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
129 (GNUNET_TIME_UNIT_MINUTES, 1),
130 &end_test, NULL);
131
132 setup_peer (&p1, cfgfile);
133 h = GNUNET_NSE_connect (cfg, &check_nse_message, cls);
134 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
135 "Connecting to NSE service.\n");
136 GNUNET_assert (h != NULL);
137}
138
139static int
140check ()
141{
142 int ok = 1;
143 char *const argv[] = { "test-nse-api",
144 "-c",
145 "test_nse.conf",
146#if DEBUG_NSE
147 "-L", "DEBUG",
148#else
149 "-L", "WARNING",
150#endif
151 NULL
152 };
153 struct GNUNET_GETOPT_CommandLineOption options[] = {
154 GNUNET_GETOPT_OPTION_END
155 };
156
157 GNUNET_PROGRAM_run (5, argv, "test-nse-api", "nohelp",
158 options, &run, &ok);
159 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
160 "Stopping arm.\n");
161 stop_arm (&p1);
162 return ok;
163}
164
165int
166main (int argc, char *argv[])
167{
168 int ret;
169
170 GNUNET_log_setup ("test_nse_api",
171#if DEBUG_NSE
172 "DEBUG",
173#else
174 "WARNING",
175#endif
176 NULL);
177 ret = check ();
178
179 return ret;
180}
181
182/* end of test_nse_api.c */