debug output
[oweals/gnunet.git] / src / nse / gnunet-service-nse.c
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  */
62 struct 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  */
83 static const struct GNUNET_CONFIGURATION_Handle *cfg;
84
85 /**
86  * Handle to the core service.
87  */
88 struct GNUNET_CORE_Handle *coreAPI;
89
90 /**
91  * Copy of this peer's identity.
92  */
93 static struct GNUNET_PeerIdentity my_identity;
94
95 /**
96  * Head of global list of clients.
97  */
98 static struct ClientListEntry *cle_head;
99
100 /**
101  * Tail of global list of clients.
102  */
103 static struct ClientListEntry *cle_tail;
104
105 /**
106  * The current network size estimate.
107  */
108 static double current_size_estimate;
109
110 /**
111  * The standard deviation of the last
112  * DEFAULT_HISTORY_SIZE network size estimates.
113  */
114 static 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  */
125 static GNUNET_SCHEDULER_TaskIdentifier flood_task;
126
127 /**
128  * Notification context, simplifies client broadcasts.
129  */
130 static struct GNUNET_SERVER_NotificationContext *nc;
131
132 /**
133  * The previous major time.
134  */
135 struct GNUNET_TIME_Absolute previous_timestamp;
136
137 /**
138  * The next major time.
139  */
140 static struct GNUNET_TIME_Absolute next_timestamp;
141
142 /**
143  * Base increment of time to add to send time.
144  */
145 static struct GNUNET_TIME_Relative increment;
146
147 /**
148  * The current network size estimate message.
149  */
150 static 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  */
162 static void
163 handle_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  */
190 static int
191 handle_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  */
206 static void
207 send_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  */
221 static void
222 handle_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  */
251 static void
252 shutdown_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  */
283 static 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  */
319 void
320 core_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  */
354 static void
355 run (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  */
423 int
424 main (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