aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2011-07-23 13:23:40 +0000
committerChristian Grothoff <christian@grothoff.org>2011-07-23 13:23:40 +0000
commitf53e991a59f4befa47b0ce90d8b68318dcd23864 (patch)
tree89dae5aaf3c8bef1fa1412133fe9d22d4f4e232d
parentc1ed03a28d6de09d7d0ac2025af9f8067e6bb0fd (diff)
downloadgnunet-f53e991a59f4befa47b0ce90d8b68318dcd23864.tar.gz
gnunet-f53e991a59f4befa47b0ce90d8b68318dcd23864.zip
nse hacking
-rw-r--r--configure.ac1
-rw-r--r--src/Makefile.am1
-rw-r--r--src/include/gnunet_nse_service.h56
-rw-r--r--src/nse/Makefile.am2
-rw-r--r--src/nse/gnunet-service-nse.c1413
-rw-r--r--src/nse/nse.h54
-rw-r--r--src/nse/nse_api.c94
-rw-r--r--src/nse/test_nse_api.c14
8 files changed, 827 insertions, 808 deletions
diff --git a/configure.ac b/configure.ac
index 8f7bbac4f..fe414b31e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -755,6 +755,7 @@ src/include/gnunet_directories.h
755src/hostlist/Makefile 755src/hostlist/Makefile
756src/mesh/Makefile 756src/mesh/Makefile
757src/nat/Makefile 757src/nat/Makefile
758src/nse/Makefile
758src/peerinfo/Makefile 759src/peerinfo/Makefile
759src/peerinfo-tool/Makefile 760src/peerinfo-tool/Makefile
760src/statistics/Makefile 761src/statistics/Makefile
diff --git a/src/Makefile.am b/src/Makefile.am
index 1442854ff..c3cf0836a 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -23,6 +23,7 @@ SUBDIRS = \
23 peerinfo-tool \ 23 peerinfo-tool \
24 core \ 24 core \
25 testing \ 25 testing \
26 nse \
26 dv \ 27 dv \
27 dht \ 28 dht \
28 hostlist \ 29 hostlist \
diff --git a/src/include/gnunet_nse_service.h b/src/include/gnunet_nse_service.h
index 27cce9bd0..7a670a584 100644
--- a/src/include/gnunet_nse_service.h
+++ b/src/include/gnunet_nse_service.h
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet 2 This file is part of GNUnet
3 (C) 2009, 2010 Christian Grothoff (and other contributing authors) 3 (C) 2011 Christian Grothoff (and other contributing authors)
4 4
5 GNUnet is free software; you can redistribute it and/or modify 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 6 it under the terms of the GNU General Public License as published
@@ -48,55 +48,31 @@ extern "C"
48#define GNUNET_NSE_VERSION 0x00000000 48#define GNUNET_NSE_VERSION 0x00000000
49 49
50/** 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#if 0
60#define GNUNET_NSE_INTERVAL 60000 /* Every minute */
61#define GNUNET_NSE_INTERVAL 180000 /* Every three minutes */
62#define GNUNET_NSE_INTERVAL 360000 /* Every six minutes */
63#define GNUNET_NSE_INTERVAL 600000 /* Every ten minutes */
64#define GNUNET_NSE_INTERVAL 1200000 /* Every twenty minutes */
65#endif
66#define GNUNET_NSE_INTERVAL 360000 /* Every ten minutes */
67/**
68 * How much clock skew (in milliseconds) will we allow
69 * for received messages. We check our current time
70 * with the timestamp received as part of the message
71 * and if the difference is greater than this tolerance
72 * we will discard the message as invalid.
73 *
74 * There are 86400000 milliseconds in a day.
75 */
76#define GNUNET_NSE_DRIFT_TOLERANCE 600000 /* Ten minutes. */
77
78/**
79 * Number of bits
80 */
81#define GNUNET_NSE_BITS
82
83/**
84 * Handle for the network size estimation service. 51 * Handle for the network size estimation service.
85 */ 52 */
86struct GNUNET_NSE_Handle; 53struct GNUNET_NSE_Handle;
87 54
88
89/** 55/**
90 * Callback to call when network size estimate is updated. 56 * Callback to call when network size estimate is updated.
91 * 57 *
92 * @param cls closure 58 * @param cls closure
93 * @param estimate the value of the current network size estimate 59 * @param logestimate the log(Base 2) value of the current network size estimate
94 * @param std_dev standard deviation (rounded down to nearest integer) 60 * @param std_dev standard deviation for the estimate
95 * of the size estimation values seen 61 *
62 */
63typedef void (*GNUNET_NSE_Callback) (void *cls,
64 double logestimate,
65 double std_dev);
66
67
68/**
69 * Convert the logarithmic estimated returned to the 'GNUNET_NSE_Callback'
70 * into an absolute estimate in terms of the number of peers in the network.
96 * 71 *
72 * @param loge logarithmic estimate
73 * @return absolute number of peers in the network (estimated)
97 */ 74 */
98typedef void 75#define GNUNET_NSE_log_estimate_to_n(loge) pow(2.0, (loge))
99(*GNUNET_NSE_Callback) (void *cls, double estimate, double std_dev);
100 76
101/** 77/**
102 * Connect to the network size estimation service. 78 * Connect to the network size estimation service.
diff --git a/src/nse/Makefile.am b/src/nse/Makefile.am
index 0718a9d51..a58dd3692 100644
--- a/src/nse/Makefile.am
+++ b/src/nse/Makefile.am
@@ -31,7 +31,7 @@ nse_profiler_SOURCES = \
31nse_profiler_LDADD = \ 31nse_profiler_LDADD = \
32 $(top_builddir)/src/nse/libgnunetnse.la \ 32 $(top_builddir)/src/nse/libgnunetnse.la \
33 $(top_builddir)/src/util/libgnunetutil.la \ 33 $(top_builddir)/src/util/libgnunetutil.la \
34 $(top_builddir)/src/testing/libgnunettesting.la 34 $(top_builddir)/src/testing/libgnunettesting.la \
35 $(GN_LIBINTL) 35 $(GN_LIBINTL)
36nse_profiler_DEPENDENCIES = \ 36nse_profiler_DEPENDENCIES = \
37 libgnunetnse.la 37 libgnunetnse.la
diff --git a/src/nse/gnunet-service-nse.c b/src/nse/gnunet-service-nse.c
index 25d020caa..6128300dd 100644
--- a/src/nse/gnunet-service-nse.c
+++ b/src/nse/gnunet-service-nse.c
@@ -1,40 +1,43 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) 3 (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors)
4 4
5 GNUnet is free software; you can redistribute it and/or modify 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 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 7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version. 8 option) any later version.
9 9
10 GNUnet is distributed in the hope that it will be useful, but 10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details. 13 General Public License for more details.
14 14
15 You should have received a copy of the GNU General Public License 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 16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330, 17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA. 18 Boston, MA 02111-1307, USA.
19 */ 19 */
20 20
21/** 21/**
22 * @file nse/gnunet-service-nse.c 22 * @file nse/gnunet-service-nse.c
23 * @brief network size estimation service 23 * @brief network size estimation service
24 * @author Nathan Evans 24 * @author Nathan Evans
25 * @author Christian Grothoff
25 * 26 *
26 * The purpose of this service is to estimate the size of the network. 27 * 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 * Given a specified interval, each peer hashes the most recent
28 * timestamp which is evenly divisible by that interval. This hash 29 * timestamp which is evenly divisible by that interval. This hash is
29 * is compared in distance to the peer identity to choose an offset. 30 * compared in distance to the peer identity to choose an offset. The
30 * The closer the peer identity to the hashed timestamp, the earlier 31 * closer the peer identity to the hashed timestamp, the earlier the
31 * the peer sends out a "nearest peer" message. The closest peer's 32 * peer sends out a "nearest peer" message. The closest peer's
32 * message should thus be received before any others, which stops 33 * message should thus be received before any others, which stops
33 * those peer from sending their messages at a later duration. So 34 * those peer from sending their messages at a later duration. So
34 * every peer should receive the same nearest peer message, and 35 * every peer should receive the same nearest peer message, and from
35 * from this can calculate the expected number of peers in the 36 * this can calculate the expected number of peers in the network.
36 * network.
37 * 37 *
38 * TODO:
39 * - generate proof-of-work asynchronously, store it on disk & load it back
40 * - handle messages for future round (one into the future, see FIXME)
38 */ 41 */
39#include "platform.h" 42#include "platform.h"
40#include "gnunet_client_lib.h" 43#include "gnunet_client_lib.h"
@@ -50,68 +53,118 @@
50#include "gnunet_nse_service.h" 53#include "gnunet_nse_service.h"
51#include "nse.h" 54#include "nse.h"
52 55
53#define DEFAULT_HISTORY_SIZE 20 56/**
57 * Over how many values do we calculate the weighted average?
58 */
59#define HISTORY_SIZE 8
54 60
55#define DEFAULT_CORE_QUEUE_SIZE 32 61/**
62 * Size of the queue to core.
63 */
64#define CORE_QUEUE_SIZE 2
56 65
57#define DEFAULT_NSE_PRIORITY 5 66/**
67 * Message priority to use.
68 */
69#define NSE_PRIORITY 5
58 70
59#define DO_FORWARD GNUNET_YES 71/**
72 * Amount of work required (W-bit collisions) for NSE proofs, in collision-bits.
73 */
74#define NSE_WORK_REQUIRED 0
60 75
61/** 76/**
62 * Entry in the list of clients which 77 * Interval for sending network size estimation flood requests.
63 * should be notified upon a new network
64 * size estimate calculation.
65 */ 78 */
66struct ClientListEntry 79#define GNUNET_NSE_INTERVAL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
80
81
82/**
83 * Per-peer information.
84 */
85struct NSEPeerEntry
67{ 86{
87
68 /** 88 /**
69 * Pointer to previous entry 89 * Pending message for this peer.
70 */ 90 */
71 struct ClientListEntry *prev; 91 struct GNUNET_MessageHeader *pending_message;
72 92
73 /** 93 /**
74 * Pointer to next entry 94 * Core handle for sending messages to this peer.
75 */ 95 */
76 struct ClientListEntry *next; 96 struct GNUNET_CORE_TransmitHandle *th;
77 97
78 /** 98 /**
79 * Client to notify. 99 * What is the identity of the peer?
80 */ 100 */
81 struct GNUNET_SERVER_Client *client; 101 struct GNUNET_PeerIdentity id;
102
103 /**
104 * Task scheduled to send message to this peer.
105 */
106 GNUNET_SCHEDULER_TaskIdentifier transmit_task;
107
108 /**
109 * Did we receive or send a message about the previous round
110 * to this peer yet?
111 */
112 int previous_round;
82}; 113};
83 114
115
84/** 116/**
85 * Per-peer information. 117 * Network size estimate reply; sent when "this"
118 * peer's timer has run out before receiving a
119 * valid reply from another peer.
86 */ 120 */
87struct NSEPeerEntry 121struct GNUNET_NSE_FloodMessage
88{ 122{
89 /** 123 /**
90 * Next peer entry (DLL) 124 * Type: GNUNET_MESSAGE_TYPE_NSE_P2P_FLOOD
91 */ 125 */
92 struct NSEPeerEntry *next; 126 struct GNUNET_MessageHeader header;
93 127
94 /** 128 /**
95 * Prev peer entry (DLL) 129 * Number of hops this message has taken so far.
96 */ 130 */
97 struct NSEPeerEntry *prev; 131 uint32_t hop_count;
98 132
99 /** 133 /**
100 * Pending message for this peer. 134 * Purpose.
101 */ 135 */
102 struct GNUNET_MessageHeader *pending_message; 136 struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
103 137
104 /** 138 /**
105 * Core handle for sending messages to this peer. 139 * The current timestamp value (which all
140 * peers should agree on).
106 */ 141 */
107 struct GNUNET_CORE_TransmitHandle *th; 142 struct GNUNET_TIME_AbsoluteNBO timestamp;
108 143
109 /** 144 /**
110 * What is the identity of the peer? 145 * Number of matching bits between the hash
146 * of timestamp and the initiator's public
147 * key.
111 */ 148 */
112 struct GNUNET_PeerIdentity id; 149 uint32_t matching_bits;
150
151 /**
152 * Public key of the originator.
153 */
154 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey;
155
156 /**
157 * Proof of work, causing leading zeros when hashed with pkey.
158 */
159 uint64_t proof_of_work;
160
161 /**
162 * Signature (over range specified in purpose).
163 */
164 struct GNUNET_CRYPTO_RsaSignature signature;
113}; 165};
114 166
167
115/** 168/**
116 * Handle to our current configuration. 169 * Handle to our current configuration.
117 */ 170 */
@@ -128,49 +181,31 @@ static struct GNUNET_STATISTICS_Handle *stats;
128static struct GNUNET_CORE_Handle *coreAPI; 181static struct GNUNET_CORE_Handle *coreAPI;
129 182
130/** 183/**
131 * Head of global list of peers. 184 * Map of all connected peers.
132 */
133static struct NSEPeerEntry *peers_head;
134
135/**
136 * Head of global list of clients.
137 */
138static struct NSEPeerEntry *peers_tail;
139
140/**
141 * Head of global list of clients.
142 */
143static struct ClientListEntry *cle_head;
144
145/**
146 * Tail of global list of clients.
147 */ 185 */
148static struct ClientListEntry *cle_tail; 186static struct GNUNET_CONTAINER_MultiHashMap *peers;
149 187
150/** 188/**
151 * The current network size estimate. 189 * The current network size estimate. Number of bits matching on
152 * Number of bits matching on average 190 * average thus far.
153 * thus far.
154 */ 191 */
155static double current_size_estimate; 192static double current_size_estimate;
156 193
157/** 194/**
158 * The standard deviation of the last 195 * The standard deviation of the last HISTORY_SIZE network
159 * DEFAULT_HISTORY_SIZE network size estimates. 196 * size estimates.
160 */ 197 */
161static double current_std_dev; 198static double current_std_dev = NAN;
162 199
163/** 200/**
164 * Array of the last DEFAULT_HISTORY_SIZE 201 * Current hop counter estimate (estimate for network diameter).
165 * network size estimates (matching bits, actually).
166 */ 202 */
167static unsigned int size_estimates[DEFAULT_HISTORY_SIZE]; 203static uint32_t hop_count_max;
168 204
169/** 205/**
170 * Array of size estimate messages. 206 * Array of recent size estimate messages.
171 */ 207 */
172static struct GNUNET_NSE_FloodMessage 208static struct GNUNET_NSE_FloodMessage size_estimate_messages[HISTORY_SIZE];
173 size_estimate_messages[DEFAULT_HISTORY_SIZE];
174 209
175/** 210/**
176 * Index of most recent estimate. 211 * Index of most recent estimate.
@@ -178,39 +213,24 @@ static struct GNUNET_NSE_FloodMessage
178static unsigned int estimate_index; 213static unsigned int estimate_index;
179 214
180/** 215/**
181 * Task scheduled to send flood message. 216 * Task scheduled to update our flood message for the next round.
182 */ 217 */
183static GNUNET_SCHEDULER_TaskIdentifier flood_task; 218static GNUNET_SCHEDULER_TaskIdentifier flood_task;
184 219
185/** 220/**
186 * Task to schedule flood message and update state.
187 */
188static GNUNET_SCHEDULER_TaskIdentifier schedule_flood_task;
189
190/**
191 * Notification context, simplifies client broadcasts. 221 * Notification context, simplifies client broadcasts.
192 */ 222 */
193static struct GNUNET_SERVER_NotificationContext *nc; 223static struct GNUNET_SERVER_NotificationContext *nc;
194 224
195/** 225/**
196 * The previous major time.
197 */
198static struct GNUNET_TIME_Absolute previous_timestamp;
199
200/**
201 * The next major time. 226 * The next major time.
202 */ 227 */
203static struct GNUNET_TIME_Absolute next_timestamp; 228static struct GNUNET_TIME_Absolute next_timestamp;
204 229
205/** 230/**
206 * Base increment of time to add to send time. 231 * The current major time.
207 */ 232 */
208static struct GNUNET_TIME_Relative increment; 233static struct GNUNET_TIME_Absolute current_timestamp;
209
210/**
211 * The current network size estimate message.
212 */
213static struct GNUNET_NSE_ClientMessage current_estimate_message;
214 234
215/** 235/**
216 * The public key of this peer. 236 * The public key of this peer.
@@ -228,9 +248,66 @@ static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
228static struct GNUNET_PeerIdentity my_identity; 248static struct GNUNET_PeerIdentity my_identity;
229 249
230/** 250/**
231 * Our flood message, updated whenever a flood is sent. 251 * Proof of work for this peer.
232 */ 252 */
233static struct GNUNET_NSE_FloodMessage flood_message; 253static uint64_t my_proof;
254
255
256/**
257 * Initialize a message to clients with the current network
258 * size estimate.
259 *
260 * @param em message to fill in
261 */
262static void
263setup_estimate_message (struct GNUNET_NSE_ClientMessage *em)
264{
265 unsigned int i;
266 double mean;
267 double sum;
268 double std_dev;
269 double variance;
270 double val;
271 double weight;
272 double sumweight;
273 double q;
274 double r;
275 double temp;
276
277 /* Weighted incremental algorithm for stddev according to West (1979) */
278 mean = 0.0;
279 sum = 0.0;
280 sumweight = 0.0;
281 for (i=0; i<HISTORY_SIZE; i++)
282 {
283 val = htonl (size_estimate_messages[i].matching_bits);
284 weight = HISTORY_SIZE - ((estimate_index + HISTORY_SIZE - i) % HISTORY_SIZE);
285
286 temp = weight + sumweight;
287 q = val - mean;
288 r = q * weight / temp;
289 sum += sumweight * q * r;
290 mean += r;
291 sumweight = temp;
292 }
293 variance = sum / (sumweight - 1.0);
294 GNUNET_assert (variance >= 0);
295 std_dev = sqrt (variance);
296 current_std_dev = std_dev;
297 current_size_estimate = mean;
298
299 em->header.size
300 = htons (sizeof(struct GNUNET_NSE_ClientMessage));
301 em->header.type
302 = htons (GNUNET_MESSAGE_TYPE_NSE_ESTIMATE);
303 em->reserved = htonl (0);
304 em->size_estimate = mean - 0.5;
305 em->std_deviation = std_dev;
306 GNUNET_STATISTICS_set (stats,
307 "Current network size estimate",
308 (uint64_t) pow (2, mean - 0.5), GNUNET_NO);
309}
310
234 311
235/** 312/**
236 * Handler for START message from client, triggers an 313 * Handler for START message from client, triggers an
@@ -246,18 +323,126 @@ static void
246handle_start_message(void *cls, struct GNUNET_SERVER_Client *client, 323handle_start_message(void *cls, struct GNUNET_SERVER_Client *client,
247 const struct GNUNET_MessageHeader *message) 324 const struct GNUNET_MessageHeader *message)
248{ 325{
249 if ((ntohs (message->size) != sizeof(struct GNUNET_MessageHeader)) 326 struct GNUNET_NSE_ClientMessage em;
250 || (ntohs (message->type) != GNUNET_MESSAGE_TYPE_NSE_START))
251 return;
252
253#if DEBUG_NSE 327#if DEBUG_NSE
254 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "NSE", 328 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
255 "Received START message from client\n"); 329 "Received START message from client\n");
256#endif 330#endif
257 GNUNET_SERVER_notification_context_add (nc, client); 331 GNUNET_SERVER_notification_context_add (nc, client);
332 setup_estimate_message (&em);
333 GNUNET_SERVER_notification_context_unicast (nc, client, &em.header, GNUNET_YES);
258 GNUNET_SERVER_receive_done (client, GNUNET_OK); 334 GNUNET_SERVER_receive_done (client, GNUNET_OK);
259} 335}
260 336
337
338/**
339 * How long should we delay a message to go the given number of
340 * matching bits?
341 *
342 * @param matching_bits number of matching bits to consider
343 */
344static double
345get_matching_bits_delay (uint32_t matching_bits)
346{
347 /* Calculated as: S + f/2 - (f / pi) * (atan(x - p'))*/
348 // S is next_timestamp
349 // f is frequency (GNUNET_NSE_INTERVAL)
350 // x is matching_bits
351 // p' is current_size_estimate
352 return ((double) GNUNET_NSE_INTERVAL.rel_value / (double) 2)
353 - ((GNUNET_NSE_INTERVAL.rel_value / M_PI) * atan (matching_bits - current_size_estimate));
354}
355
356
357/**
358 * What delay randomization should we apply for a given number of matching bits?
359 *
360 * @param matching_bits number of matching bits
361 * @return random delay to apply
362 */
363static struct GNUNET_TIME_Relative
364get_delay_randomization (uint32_t matching_bits)
365{
366 struct GNUNET_TIME_Relative ret;
367
368 if (matching_bits == 0)
369 return GNUNET_TIME_UNIT_ZERO;
370 ret.rel_value = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
371 (uint32_t) (get_matching_bits_delay (matching_bits - 1) / (double) (hop_count_max + 1)));
372 return ret;
373}
374
375
376/**
377 * Get the number of matching bits that the given timestamp has to the given peer ID.
378 *
379 * @param timestamp time to generate key
380 * @param id peer identity to compare with
381 * @return number of matching bits
382 */
383static uint32_t
384get_matching_bits (struct GNUNET_TIME_Absolute timestamp,
385 const struct GNUNET_PeerIdentity *id)
386{
387 GNUNET_HashCode timestamp_hash;
388
389 GNUNET_CRYPTO_hash (&timestamp.abs_value,
390 sizeof(timestamp.abs_value),
391 &timestamp_hash);
392 return GNUNET_CRYPTO_hash_matching_bits (&timestamp_hash,
393 &id->hashPubKey);
394}
395
396
397/**
398 * Get the transmission delay that should be applied for a
399 * particular round.
400 *
401 * @param round_offset -1 for the previous round (random delay between 0 and 50ms)
402 * 0 for the current round (based on our proximity to time key)
403 * @return delay that should be applied
404 */
405static struct GNUNET_TIME_Relative
406get_transmit_delay (int round_offset)
407{
408 struct GNUNET_TIME_Relative ret;
409 struct GNUNET_TIME_Absolute tgt;
410 double dist_delay;
411 uint32_t matching_bits;
412
413 switch (round_offset)
414 {
415 case -1:
416 /* previous round is randomized between 0 and 50 ms */
417 ret.rel_value = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
418 50);
419 return ret;
420 case 0:
421 /* current round is based on best-known matching_bits */
422 matching_bits = ntohl (size_estimate_messages[estimate_index].matching_bits);
423 dist_delay = get_matching_bits_delay (matching_bits);
424 dist_delay += get_delay_randomization (matching_bits).rel_value;
425 ret.rel_value = (uint64_t) dist_delay;
426 /* now consider round start time and add delay to it */
427 tgt = GNUNET_TIME_absolute_add (current_timestamp, ret);
428 return GNUNET_TIME_absolute_get_remaining (tgt);
429 }
430 GNUNET_break (0);
431 return GNUNET_TIME_UNIT_FOREVER_REL;
432}
433
434
435/**
436 * Task that triggers a NSE P2P transmission.
437 *
438 * @param cls the 'struct NSEPeerEntry'
439 * @param tc scheduler context
440 */
441static void
442transmit_task (void *cls,
443 const struct GNUNET_SCHEDULER_TaskContext *tc);
444
445
261/** 446/**
262 * Called when core is ready to send a message we asked for 447 * Called when core is ready to send a message we asked for
263 * out to the destination. 448 * out to the destination.
@@ -268,313 +453,272 @@ handle_start_message(void *cls, struct GNUNET_SERVER_Client *client,
268 * @return number of bytes written to buf 453 * @return number of bytes written to buf
269 */ 454 */
270static size_t 455static size_t
271transmit_ready(void *cls, size_t size, void *buf) 456transmit_ready (void *cls, size_t size, void *buf)
272{ 457{
273 struct NSEPeerEntry *peer_entry = cls; 458 struct NSEPeerEntry *peer_entry = cls;
274 char *cbuf = buf; 459 unsigned int idx;
275 460
276 size_t msize;
277 peer_entry->th = NULL; 461 peer_entry->th = NULL;
278#if DEBUG_NSE > 1 462 if (buf == NULL)
279 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "%s: transmit_ready called\n",
280 GNUNET_i2s (&my_identity));
281#endif
282 if (buf == NULL) /* client disconnected */
283 { 463 {
284 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 464 /* client disconnected */
285 "%s: transmit_ready called (disconnect)\n",
286 GNUNET_i2s (&my_identity));
287 return 0; 465 return 0;
288 } 466 }
289 467 GNUNET_assert (size >= sizeof (struct GNUNET_NSE_FloodMessage));
290 if (peer_entry->pending_message == NULL) 468#if DEBUG_NSE > 1
469 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
470 "Sending size estimate to `%s'\n",
471 GNUNET_i2s (&peer_entry->id));
472#endif
473 idx = estimate_index;
474 if (peer_entry->previous_round == GNUNET_YES)
291 { 475 {
292 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 476 idx = (idx + HISTORY_SIZE -1) % HISTORY_SIZE;
293 "%s: transmit_ready called (no message)\n", 477 peer_entry->previous_round = GNUNET_NO;
294 GNUNET_i2s (&my_identity)); 478 peer_entry->transmit_task = GNUNET_SCHEDULER_add_delayed (get_transmit_delay (0),
295 return 0; 479 &transmit_task,
480 peer_entry);
296 } 481 }
482 memcpy (buf,
483 &size_estimate_messages[idx],
484 sizeof (struct GNUNET_NSE_FloodMessage));
485 GNUNET_STATISTICS_update (stats,
486 "# flood messages sent",
487 1,
488 GNUNET_NO);
489 return sizeof (struct GNUNET_NSE_FloodMessage);
490}
297 491
298 msize = ntohs (peer_entry->pending_message->size); 492
299 if (msize <= size) 493/**
300 memcpy (cbuf, peer_entry->pending_message, msize); 494 * Task that triggers a NSE P2P transmission.
301#if DEBUG_NSE > 1 495 *
302 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 496 * @param cls the 'struct NSEPeerEntry'
303 "%s: transmit_ready called (transmit %d bytes)\n", 497 * @param tc scheduler context
304 GNUNET_i2s (&my_identity), msize); 498 */
305#endif 499static void
306 return msize; 500transmit_task (void *cls,
501 const struct GNUNET_SCHEDULER_TaskContext *tc)
502{
503 struct NSEPeerEntry *peer_entry = cls;
504
505 peer_entry->transmit_task = GNUNET_SCHEDULER_NO_TASK;
506 peer_entry->th
507 = GNUNET_CORE_notify_transmit_ready (coreAPI,
508 GNUNET_NO,
509 NSE_PRIORITY,
510 GNUNET_TIME_UNIT_FOREVER_REL,
511 &peer_entry->id,
512 sizeof (struct GNUNET_NSE_FloodMessage),
513 &transmit_ready, peer_entry);
307} 514}
308 515
516
309/** 517/**
310 * We sent on our flood message or one that we received 518 * We've sent on our flood message or one that we received which was
311 * which was validated and closer than ours. Update the 519 * validated and closer than ours. Update the global list of recent
312 * global list of recent messages and the average. Also 520 * messages and the average. Also re-broadcast the message to any
313 * re-broadcast the message to any clients. 521 * clients.
522 */
523static void
524update_network_size_estimate ()
525{
526 struct GNUNET_NSE_ClientMessage em;
527
528 setup_estimate_message (&em);
529 GNUNET_SERVER_notification_context_broadcast (nc,
530 &em.header,
531 GNUNET_YES);
532}
533
534
535/**
536 * Setup a flood message in our history array at the given
537 * slot offset for the given timestamp.
314 * 538 *
315 * @param message the network flood message 539 * @param slot index to use
540 * @param ts timestamp to use
316 */ 541 */
317static void 542static void
318update_network_size_estimate(struct GNUNET_NSE_FloodMessage *message) 543setup_flood_message (unsigned int slot,
544 struct GNUNET_TIME_Absolute ts)
319{ 545{
320 unsigned int i; 546 struct GNUNET_NSE_FloodMessage *fm;
321 unsigned int count; 547 uint32_t matching_bits;
322 double average; 548
323 double std_dev; 549 matching_bits = get_matching_bits (ts, &my_identity);
324 double diff; 550 fm = &size_estimate_messages[slot];
551 fm->header.size = htons (sizeof(struct GNUNET_NSE_FloodMessage));
552 fm->header.type = htons (GNUNET_MESSAGE_TYPE_NSE_P2P_FLOOD);
553 fm->hop_count = htonl (0);
554 fm->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_NSE_SEND);
555 fm->purpose.size = htonl (sizeof(struct GNUNET_NSE_FloodMessage)
556 - sizeof (struct GNUNET_MessageHeader)
557 - sizeof (uint32_t)
558 - sizeof (struct GNUNET_CRYPTO_RsaSignature));
559 fm->matching_bits = htonl (matching_bits);
560 fm->timestamp = GNUNET_TIME_absolute_hton (ts);
561 fm->pkey = my_public_key;
562 fm->proof_of_work = my_proof;
563 GNUNET_CRYPTO_rsa_sign (my_private_key,
564 &fm->purpose,
565 &fm->signature);
566}
567
325 568
326 size_estimates[estimate_index] = htonl (message->distance); 569/**
327 memcpy (&size_estimate_messages[estimate_index], message, 570 * Schedule transmission for the given peer for the current round based
328 sizeof(struct GNUNET_NSE_FloodMessage)); 571 * on what we know about the desired delay.
572 *
573 * @param cls unused
574 * @param key hash of peer identity
575 * @param value the 'struct NSEPeerEntry'
576 * @return GNUNET_OK (continue to iterate)
577 */
578static int
579schedule_current_round (void *cls,
580 const GNUNET_HashCode *key,
581 void *value)
582{
583 struct NSEPeerEntry *peer_entry = value;
584 struct GNUNET_TIME_Relative delay;
329 585
330 count = 0; 586 if (peer_entry->th != NULL)
331 std_dev = 0.0;
332 average = 0.0;
333 for (i = 0; i < DEFAULT_HISTORY_SIZE; i++)
334 { 587 {
335 if (size_estimate_messages[i].distance != 0) 588 peer_entry->previous_round = GNUNET_NO;
336 { 589 return GNUNET_OK;
337#if AVERAGE_SQUARE
338 average += (1 << htonl (size_estimate_messages[i].distance));
339#else
340 average += htonl (size_estimate_messages[i].distance);
341#endif
342 count++;
343 }
344 } 590 }
345 591 if (peer_entry->transmit_task != GNUNET_SCHEDULER_NO_TASK)
346 if (count > 0)
347 { 592 {
348 average /= (double) count; 593 GNUNET_SCHEDULER_cancel (peer_entry->transmit_task);
349 for (i = 0; i < DEFAULT_HISTORY_SIZE; i++) 594 peer_entry->previous_round = GNUNET_NO;
350 {
351 if (size_estimate_messages[i].distance != 0)
352 {
353#if DEBUG_NSE
354 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "%s: estimate %d %d\n", GNUNET_i2s(&my_identity), i, (1 << htonl(size_estimate_messages[i].distance)));
355#endif
356#if AVERAGE_SQUARE
357 diff = average
358 - (1 << htonl (size_estimate_messages[i].distance));
359#else
360 diff = average - htonl (size_estimate_messages[i].distance);
361#endif
362 std_dev += diff * diff;
363 }
364 }
365 std_dev /= count;
366 std_dev = sqrt (std_dev);
367 current_estimate_message.header.size
368 = htons (sizeof(struct GNUNET_NSE_ClientMessage));
369 current_estimate_message.header.type
370 = htons (GNUNET_MESSAGE_TYPE_NSE_ESTIMATE);
371#if AVERAGE_SQUARE
372 current_estimate_message.size_estimate = average;
373 current_estimate_message.std_deviation = std_dev;
374#else
375 current_estimate_message.size_estimate = pow(2, average);
376 current_estimate_message.std_deviation = pow(2, std_dev);
377#endif
378 /* Finally, broadcast the current estimate to all clients */
379#if DEBUG_NSE
380 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
381 "%s: sending estimate %f -- %f to client\n",
382 GNUNET_i2s (&my_identity),
383 average,
384 std_dev);
385#endif
386 GNUNET_SERVER_notification_context_broadcast (
387 nc,
388 &current_estimate_message.header,
389 GNUNET_NO);
390
391 GNUNET_STATISTICS_set (stats, "Current network size estimate",
392 (uint64_t) average, GNUNET_NO);
393 } 595 }
596 delay = get_transmit_delay ((peer_entry->previous_round == GNUNET_NO) ? -1 : 0);
597 peer_entry->transmit_task = GNUNET_SCHEDULER_add_delayed (delay,
598 &transmit_task,
599 peer_entry);
600 return GNUNET_OK;
394} 601}
395 602
396static void
397send_flood_message(void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc);
398 603
399/** 604/**
400 * Schedule a flood message to be sent. 605 * Update our flood message to be sent (and our timestamps).
401 * 606 *
402 * @param cls unused 607 * @param cls unused
403 * @param tc context for this message 608 * @param tc context for this message
404 *
405 * This should be called on startup,
406 * when a valid flood message is received (and
407 * the next send flood message hasn't been
408 * scheduled yet) and when this peer sends
409 * a valid flood message. As such, there should
410 * always be a message scheduled to be sent.
411 */ 609 */
412static void 610static void
413schedule_flood_message(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) 611update_flood_message(void *cls,
612 const struct GNUNET_SCHEDULER_TaskContext *tc)
414{ 613{
415 GNUNET_HashCode timestamp_hash;
416 struct GNUNET_TIME_Absolute curr_time;
417 struct GNUNET_TIME_Relative offset; 614 struct GNUNET_TIME_Relative offset;
418 unsigned int matching_bits; 615 unsigned int i;
419 double millisecond_offset;
420
421 schedule_flood_task = GNUNET_SCHEDULER_NO_TASK;
422 if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
423 return;
424
425 GNUNET_assert(flood_task == GNUNET_SCHEDULER_NO_TASK);
426 616
427 if (0 != GNUNET_TIME_absolute_get_remaining (next_timestamp).rel_value) 617 flood_task = GNUNET_SCHEDULER_NO_TASK;
618 offset = GNUNET_TIME_absolute_get_remaining (next_timestamp);
619 if (0 != offset.rel_value)
428 { 620 {
429 GNUNET_break(0); /* Shouldn't ever happen! */ 621 /* somehow run early, delay more */
430 schedule_flood_task 622 flood_task
431 = GNUNET_SCHEDULER_add_delayed ( 623 = GNUNET_SCHEDULER_add_delayed (offset,
432 GNUNET_TIME_absolute_get_remaining ( 624 &update_flood_message,
433 next_timestamp), 625 NULL);
434 &schedule_flood_message, NULL); 626 return;
435 } 627 }
628 current_timestamp = next_timestamp;
629 next_timestamp = GNUNET_TIME_absolute_add (current_timestamp,
630 GNUNET_NSE_INTERVAL);
631 estimate_index = (estimate_index + 1) % HISTORY_SIZE;
632 setup_flood_message (estimate_index, current_timestamp);
633 hop_count_max = 0;
634 for (i=0;i<HISTORY_SIZE;i++)
635 hop_count_max = GNUNET_MAX (ntohl (size_estimate_messages[i].hop_count),
636 hop_count_max);
637 GNUNET_CONTAINER_multihashmap_iterate (peers,
638 &schedule_current_round,
639 NULL);
640 flood_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining (next_timestamp),
641 &update_flood_message, NULL);
642}
436 643
437 /* Get the current UTC time */
438 curr_time = GNUNET_TIME_absolute_get ();
439 /* Find the previous interval start time */
440 previous_timestamp.abs_value = (curr_time.abs_value / GNUNET_NSE_INTERVAL)
441 * GNUNET_NSE_INTERVAL;
442 /* Find the next interval start time */
443 next_timestamp.abs_value = previous_timestamp.abs_value + GNUNET_NSE_INTERVAL;
444#if DEBUG_NSE > 1
445 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
446 "%s: curr_time %lu, prev timestamp %lu, next timestamp %lu\n",
447 GNUNET_i2s (&my_identity), curr_time.abs_value,
448 previous_timestamp.abs_value, next_timestamp.abs_value);
449#endif
450 GNUNET_CRYPTO_hash (&next_timestamp.abs_value,
451 sizeof(next_timestamp.abs_value), &timestamp_hash);
452 matching_bits = GNUNET_CRYPTO_hash_matching_bits (&timestamp_hash,
453 &my_identity.hashPubKey);
454
455 flood_message.header.size = htons (sizeof(struct GNUNET_NSE_FloodMessage));
456 flood_message.header.type = htons (GNUNET_MESSAGE_TYPE_NSE_P2P_FLOOD);
457 flood_message.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_NSE_SEND);
458 flood_message.purpose.size = htonl (sizeof(struct GNUNET_NSE_FloodMessage)
459 - sizeof(struct GNUNET_MessageHeader) - sizeof(flood_message.signature));
460 flood_message.distance = htonl (matching_bits);
461 flood_message.timestamp = GNUNET_TIME_absolute_hton (next_timestamp);
462 memcpy (&flood_message.pkey, &my_public_key,
463 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
464 flood_message.proof_of_work = htonl (0);
465 GNUNET_CRYPTO_rsa_sign (my_private_key, &flood_message.purpose,
466 &flood_message.signature);
467
468 /*S + f/2 - (f / pi) * (atan(x - p'))*/
469
470 // S is next_timestamp
471 // f is frequency (GNUNET_NSE_INTERVAL)
472 // x is matching_bits
473 // p' is current_size_estimate
474 millisecond_offset = ((double) GNUNET_NSE_INTERVAL / (double) 2)
475 - ((GNUNET_NSE_INTERVAL / M_PI) * atan (matching_bits
476 - current_size_estimate));
477#if DEBUG_NSE > 1
478 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
479 "%s: id matches %d bits, offset is %lu\n\n",
480 GNUNET_i2s (&my_identity), matching_bits,
481 (uint64_t) millisecond_offset);
482#endif
483 /* Stop initial call from incrementing */
484 if (size_estimate_messages[estimate_index].distance != 0)
485 estimate_index += 1;
486
487 if (estimate_index >= DEFAULT_HISTORY_SIZE)
488 estimate_index = 0;
489
490 if (millisecond_offset < curr_time.abs_value - previous_timestamp.abs_value)
491 offset.rel_value = 0;
492 else
493 offset.rel_value = (uint64_t) millisecond_offset + curr_time.abs_value
494 - previous_timestamp.abs_value;
495#if DEBUG_NSE
496 GNUNET_log (
497 GNUNET_ERROR_TYPE_WARNING,
498 "%s: %u bits match, %lu milliseconds to timestamp , sending flood in %lu\n",
499 GNUNET_i2s (&my_identity), matching_bits,
500 GNUNET_TIME_absolute_get_remaining (next_timestamp).rel_value,
501 offset.rel_value);
502#endif
503 flood_task = GNUNET_SCHEDULER_add_delayed (offset, &send_flood_message, NULL);
504 644
645/**
646 * Count the trailing zeroes in hash.
647 *
648 * @param hash
649 * @return the number of trailing zero bits.
650 */
651static unsigned int
652count_trailing_zeroes(const GNUNET_HashCode *hash)
653{
654 unsigned int hash_count;
655
656 hash_count = sizeof(GNUNET_HashCode) * 8;
657 while ((0 == GNUNET_CRYPTO_hash_get_bit(hash, hash_count)))
658 hash_count--;
659 return (sizeof(GNUNET_HashCode) * 8) - hash_count;
505} 660}
506 661
507#if VERIFY_CRYPTO 662
508/** 663/**
509 * Check whether the given public key 664 * Check whether the given public key
510 * and integer are a valid proof of work. 665 * and integer are a valid proof of work.
511 * 666 *
512 * @param pkey the public key 667 * @param pkey the public key
513 * @param val the integer 668 * @param val the integer
514 * @param want the number of trailing zeroes
515 * 669 *
516 * @return GNUNET_YES if valid, GNUNET_NO if not 670 * @return GNUNET_YES if valid, GNUNET_NO if not
517 */ 671 */
518static int check_proof_of_work(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey, uint64_t val, unsigned int want) 672static int
519 { 673check_proof_of_work(const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *pkey,
520 674 uint64_t val)
521 return GNUNET_YES; 675{
522 } 676 char buf[sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + sizeof(val)];
523 677 GNUNET_HashCode result;
524/** 678
525 * Count the trailing zeroes in hash. 679 memcpy (buf,
526 * 680 &val,
527 * @param hash 681 sizeof (val));
528 * 682 memcpy (&buf[sizeof(val)],
529 * @return the number of trailing zero bits. 683 pkey,
530 */ 684 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
531static unsigned int count_trailing_zeroes(GNUNET_HashCode *hash) 685 GNUNET_CRYPTO_hash (buf, sizeof (buf), &result);
532 { 686 return (count_trailing_zeroes (&result) >= NSE_WORK_REQUIRED) ? GNUNET_YES : GNUNET_NO;
533 unsigned int hash_count; 687}
534 688
535 hash_count = sizeof(GNUNET_HashCode) * 8;
536 while ((0 == GNUNET_CRYPTO_hash_get_bit(hash, hash_count)))
537 hash_count--;
538 return (sizeof(GNUNET_HashCode) * 8) - hash_count;
539 }
540 689
541/** 690/**
542 * Given a public key, find an integer such that 691 * Given a public key, find an integer such that the hash of the key
543 * the hash of the key concatenated with the integer 692 * concatenated with the integer has NSE_WORK_REQUIRED trailing 0
544 * has <param>want</param> trailing 0 bits. 693 * bits. FIXME: this is a synchronous function... bad
545 * 694 *
546 * @param pkey the public key 695 * @param pkey the public key
547 * @param want the number of trailing 0 bits 696 * @return 64 bit number that satisfies the requirements
548 *
549 * @return 64 bit number that satisfies the
550 * requirements
551 *
552 * FIXME: use pointer and return GNUNET_YES or
553 * GNUNET_NO in case no such number works?
554 */ 697 */
555static uint64_t find_proof_of_work(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *pkey, unsigned int want) 698static uint64_t
556 { 699find_proof_of_work(const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *pkey)
557 uint64_t counter; 700{
558 static char buf[sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + sizeof(uint64_t)]; 701 uint64_t counter;
559 unsigned int data_size; 702 char buf[sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + sizeof(uint64_t)];
560 static GNUNET_HashCode result; 703 GNUNET_HashCode result;
561 704
562 data_size = sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + sizeof(uint64_t); 705 memcpy (&buf[sizeof(uint64_t)],
563 memcpy(buf, pkey, sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); 706 pkey,
564 counter = 0; 707 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
565 while (counter != (uint64_t)-1) 708 counter = 0;
566 { 709 while (counter != UINT64_MAX)
567 memcpy(&buf[sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)], &counter, sizeof(uint64_t)); 710 {
568 GNUNET_CRYPTO_hash(buf, data_size, &result); 711 memcpy (buf,
569 if (want == count_trailing_zeroes(&result)) /* Found good proof of work! */ 712 &counter,
713 sizeof(uint64_t));
714 GNUNET_CRYPTO_hash (buf, sizeof (buf), &result);
715 if (NSE_WORK_REQUIRED <= count_trailing_zeroes(&result))
570 break; 716 break;
571 counter++; 717 counter++;
572 } 718 }
573 if (counter < (uint64_t)-1) 719 return counter;
574 return counter; /* Found valid proof of work */ 720}
575 else 721
576 return 0; /* Did not find valid proof of work */
577 }
578 722
579/** 723/**
580 * An incoming flood message has been received which claims 724 * An incoming flood message has been received which claims
@@ -586,19 +730,70 @@ static uint64_t find_proof_of_work(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncode
586 * @return GNUNET_YES if the message is verified 730 * @return GNUNET_YES if the message is verified
587 * GNUNET_NO if the key/signature don't verify 731 * GNUNET_NO if the key/signature don't verify
588 */ 732 */
589static int verify_message_crypto(struct GNUNET_NSE_FloodMessage *incoming_flood) 733static int
590 { 734verify_message_crypto(const struct GNUNET_NSE_FloodMessage *incoming_flood)
591 int ret; 735{
592 if (GNUNET_OK == (ret 736 if (GNUNET_YES !=
593 = GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_NSE_SEND, 737 check_proof_of_work (&incoming_flood->pkey,
594 &incoming_flood->purpose, 738 incoming_flood->proof_of_work))
595 &incoming_flood->signature, 739 {
596 &incoming_flood->pkey))) 740 GNUNET_break_op (0);
597 return GNUNET_YES; 741 return GNUNET_NO;
598 742 }
599 return GNUNET_NO; 743 if (GNUNET_OK !=
600 } 744 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_NSE_SEND,
601#endif 745 &incoming_flood->purpose,
746 &incoming_flood->signature,
747 &incoming_flood->pkey))
748 {
749 GNUNET_break_op (0);
750 return GNUNET_NO;
751 }
752 return GNUNET_YES;
753}
754
755
756/**
757 * Update transmissions for the given peer for the current round based
758 * on updated proximity information.
759 *
760 * @param cls peer entry to exclude from updates
761 * @param key hash of peer identity
762 * @param value the 'struct NSEPeerEntry'
763 * @return GNUNET_OK (continue to iterate)
764 */
765static int
766update_flood_times (void *cls,
767 const GNUNET_HashCode *key,
768 void *value)
769{
770 struct NSEPeerEntry *exclude = cls;
771 struct NSEPeerEntry *peer_entry = value;
772 struct GNUNET_TIME_Relative delay;
773
774 if (peer_entry->th != NULL)
775 return GNUNET_OK; /* already active */
776 if (peer_entry == exclude)
777 return GNUNET_OK; /* trigger of the update */
778 if (peer_entry->previous_round == GNUNET_YES)
779 {
780 /* still stuck in previous round, no point to update, check that
781 we are active here though... */
782 GNUNET_break (peer_entry->transmit_task != GNUNET_SCHEDULER_NO_TASK);
783 return GNUNET_OK;
784 }
785 if (peer_entry->transmit_task != GNUNET_SCHEDULER_NO_TASK)
786 {
787 GNUNET_SCHEDULER_cancel (peer_entry->transmit_task);
788 peer_entry->transmit_task = GNUNET_SCHEDULER_NO_TASK;
789 }
790 delay = get_transmit_delay (0);
791 peer_entry->transmit_task = GNUNET_SCHEDULER_add_delayed (delay,
792 &transmit_task,
793 peer_entry);
794 return GNUNET_OK;
795}
796
602 797
603/** 798/**
604 * Core handler for size estimate flooding messages. 799 * Core handler for size estimate flooding messages.
@@ -610,176 +805,122 @@ static int verify_message_crypto(struct GNUNET_NSE_FloodMessage *incoming_flood)
610 * 805 *
611 */ 806 */
612static int 807static int
613handle_p2p_size_estimate(void *cls, const struct GNUNET_PeerIdentity *peer, 808handle_p2p_size_estimate(void *cls,
809 const struct GNUNET_PeerIdentity *peer,
614 const struct GNUNET_MessageHeader *message, 810 const struct GNUNET_MessageHeader *message,
615 const struct GNUNET_TRANSPORT_ATS_Information *atsi) 811 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
616{ 812{
617 struct GNUNET_NSE_FloodMessage *incoming_flood; 813 const struct GNUNET_NSE_FloodMessage *incoming_flood;
618 struct GNUNET_TIME_Absolute curr_time; 814 struct GNUNET_TIME_Absolute ts;
619 uint64_t drift; 815 struct NSEPeerEntry *peer_entry;
620 816 uint32_t matching_bits;
621#if DEBUG_NSE > 1 817 unsigned int idx;
622 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "%s: received flood message!\n", 818
623 GNUNET_i2s (&my_identity)); 819 incoming_flood = (const struct GNUNET_NSE_FloodMessage *) message;
624#endif 820 GNUNET_STATISTICS_update (stats,
625 if (ntohs (message->size) != sizeof(struct GNUNET_NSE_FloodMessage)) 821 "# flood messages received",
822 1,
823 GNUNET_NO);
824 matching_bits = ntohl (incoming_flood->matching_bits);
825 peer_entry = GNUNET_CONTAINER_multihashmap_get (peers, &peer->hashPubKey);
826 if (NULL == peer_entry)
626 { 827 {
627 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "%s: bad message size!\n", 828 GNUNET_break (0);
628 GNUNET_i2s (&my_identity)); 829 return GNUNET_OK;
629 return GNUNET_NO;
630 } 830 }
631 831 ts = GNUNET_TIME_absolute_ntoh (incoming_flood->timestamp);
632 GNUNET_STATISTICS_update (stats, "# flood messages received", 1, GNUNET_NO); 832 if (ts.abs_value == current_timestamp.abs_value)
633 incoming_flood = (struct GNUNET_NSE_FloodMessage *) message; 833 idx = estimate_index;
634 if (ntohl (incoming_flood->distance) 834 else if (ts.abs_value == current_timestamp.abs_value - GNUNET_NSE_INTERVAL.rel_value)
635 <= ntohl (size_estimate_messages[estimate_index].distance)) /* Not closer than our most recent message */ 835 idx = (estimate_index + HISTORY_SIZE - 1) % HISTORY_SIZE;
836 else if (ts.abs_value == next_timestamp.abs_value - GNUNET_NSE_INTERVAL.rel_value)
636 { 837 {
637#if DEBUG_NSE 838 if (GNUNET_YES !=
638 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 839 verify_message_crypto (incoming_flood))
639 "%s: distance %d not greater than %d, discarding\n", 840 {
640 GNUNET_i2s (&my_identity), ntohl (incoming_flood->distance), 841 GNUNET_break_op (0);
641 ntohl (size_estimate_messages[estimate_index].distance)); 842 return GNUNET_OK;
642#endif 843 }
643 GNUNET_STATISTICS_update (stats, 844 /* FIXME: keep in special 'future' buffer until next round starts for us! */
644 "# flood messages discarded (had closer)", 1, 845 GNUNET_break (0); /* not implemented */
645 GNUNET_NO);
646 return GNUNET_OK; 846 return GNUNET_OK;
647 } 847 }
648
649 curr_time = GNUNET_TIME_absolute_get ();
650 if (curr_time.abs_value
651 > GNUNET_TIME_absolute_ntoh (incoming_flood->timestamp).abs_value)
652 drift = curr_time.abs_value
653 - GNUNET_TIME_absolute_ntoh (incoming_flood->timestamp).abs_value;
654 else 848 else
655 drift = GNUNET_TIME_absolute_ntoh (incoming_flood->timestamp).abs_value
656 - curr_time.abs_value;
657
658 if (drift > GNUNET_NSE_DRIFT_TOLERANCE)
659 { 849 {
660 GNUNET_STATISTICS_update ( 850 GNUNET_STATISTICS_update (stats,
661 stats, 851 "# flood messages discarded (clock skew too large)",
662 "# flood messages discarded (clock skew too high)", 852 1,
663 1, GNUNET_NO); 853 GNUNET_NO);
854 GNUNET_break_op (0);
664 return GNUNET_OK; 855 return GNUNET_OK;
665 } 856 }
666 857 if (0 == (memcmp (peer, &my_identity, sizeof(struct GNUNET_PeerIdentity))))
667#if VERIFY_CRYPTO 858 {
668 if (GNUNET_YES != verify_message_crypto(incoming_flood)) 859 /* send to self, update our own estimate IF this also comes from us! */
860 if (0 == memcmp (&incoming_flood->pkey,
861 &my_public_key,
862 sizeof (my_public_key)))
863 update_network_size_estimate ();
864 return GNUNET_OK;
865 }
866 if (matching_bits >= ntohl (size_estimate_messages[idx].matching_bits))
867 {
868 /* cancel transmission from us to this peer for this round */
869 if (idx == estimate_index)
870 {
871 if (peer_entry->previous_round == GNUNET_NO)
872 {
873 /* cancel any activity for current round */
874 if (peer_entry->transmit_task != GNUNET_SCHEDULER_NO_TASK)
875 {
876 GNUNET_SCHEDULER_cancel (peer_entry->transmit_task);
877 peer_entry->previous_round = GNUNET_NO;
878 }
879 if (peer_entry->th != NULL)
880 {
881 GNUNET_CORE_notify_transmit_ready_cancel (peer_entry->th);
882 peer_entry->th = NULL;
883 }
884 }
885 }
886 else
887 {
888 /* cancel previous round only */
889 peer_entry->previous_round = GNUNET_NO;
890 }
891
892 }
893 if (matching_bits <= ntohl (size_estimate_messages[idx].matching_bits))
669 { 894 {
895 /* Not closer than our most recent message, no need to do work here */
670 GNUNET_STATISTICS_update (stats, 896 GNUNET_STATISTICS_update (stats,
671 "# flood messages discarded (bad crypto)", 897 "# flood messages ignored (had closer already)",
672 1, GNUNET_NO); 898 1,
899 GNUNET_NO);
673 return GNUNET_OK; 900 return GNUNET_OK;
674 } 901 }
675#endif 902 if (GNUNET_YES !=
676 903 verify_message_crypto (incoming_flood))
677 /* Have a new, better size estimate! */
678 update_network_size_estimate (incoming_flood);
679
680 if (flood_task != GNUNET_SCHEDULER_NO_TASK)
681 { 904 {
682#if DEBUG_NSE 905 GNUNET_break_op (0);
683 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "%s: received closer message, canceling my flood task!\n", GNUNET_i2s(&my_identity)); 906 return GNUNET_OK;
684#endif
685 GNUNET_SCHEDULER_cancel (flood_task);
686 flood_task = GNUNET_SCHEDULER_NO_TASK;
687 } 907 }
688 908 size_estimate_messages[idx] = *incoming_flood;
689 /** Commenting out prevents forwarding of messages */ 909 size_estimate_messages[idx].hop_count = htonl (ntohl (incoming_flood->hop_count) + 1);
690#if DO_FORWARD 910 hop_count_max = GNUNET_MAX (ntohl (incoming_flood->hop_count) + 1,
691 GNUNET_SCHEDULER_add_now(&send_flood_message, &size_estimate_messages[estimate_index]); 911 hop_count_max);
692#endif 912
693 if (schedule_flood_task != GNUNET_SCHEDULER_NO_TASK) 913 /* have a new, better size estimate, inform clients */
694 GNUNET_SCHEDULER_cancel (schedule_flood_task); 914 update_network_size_estimate ();
695 915
696 schedule_flood_task 916 /* flood to rest */
697 = GNUNET_SCHEDULER_add_delayed ( 917 GNUNET_CONTAINER_multihashmap_iterate (peers,
698 GNUNET_TIME_absolute_get_remaining ( 918 &update_flood_times,
699 next_timestamp), 919 peer_entry);
700 &schedule_flood_message, NULL);
701
702 return GNUNET_OK; 920 return GNUNET_OK;
703} 921}
704 922
705/**
706 * Send a flood message.
707 *
708 * If we've gotten here, it means either we haven't received
709 * a network size estimate message closer than ours, or
710 * we need to forward a message we received which was closer
711 * than ours.
712 */
713static void
714send_flood_message(void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
715{
716 struct NSEPeerEntry *peer_entry;
717 struct GNUNET_NSE_FloodMessage *to_send;
718
719 if (cls == NULL) /* Means we are sending our OWN flood message */
720 to_send = &flood_message;
721 else
722 /* Received a message from another peer that should be forwarded */
723 to_send = (struct GNUNET_NSE_FloodMessage *) cls;
724 923
725 flood_task = GNUNET_SCHEDULER_NO_TASK;
726 if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
727 return;
728#if DEBUG_NSE
729 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
730 "%s: my time has come, sending flood message of size %d!\n",
731 GNUNET_i2s (&my_identity), ntohs (to_send->header.size));
732#endif
733 peer_entry = peers_head;
734
735 while (peer_entry != NULL)
736 {
737 peer_entry->pending_message = &to_send->header;
738 peer_entry->th
739 = GNUNET_CORE_notify_transmit_ready (
740 coreAPI,
741 GNUNET_NO,
742 DEFAULT_NSE_PRIORITY,
743 GNUNET_TIME_absolute_get_remaining (
744 next_timestamp),
745 &peer_entry->id,
746 ntohs (to_send->header.size),
747 &transmit_ready, peer_entry);
748 if (peer_entry->th == NULL)
749 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
750 "%s: transmit handle is null!\n", GNUNET_i2s (&my_identity));
751#if DEBUG_NSE > 1
752 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
753 "%s: Sending flood message (distance %d) to %s!\n",
754 GNUNET_i2s (&my_identity), ntohl (to_send->distance),
755 GNUNET_h2s (&peer_entry->id.hashPubKey));
756#endif
757 peer_entry = peer_entry->next;
758 }
759
760 if (cls == NULL) /* Need to update our size estimate */
761 {
762 update_network_size_estimate (to_send);
763 GNUNET_STATISTICS_update (stats, "# flood messages sent", 1, GNUNET_NO);
764 }
765 else
766 GNUNET_STATISTICS_update (stats, "# flood messages forwarded", 1, GNUNET_NO);
767
768#if DEBUG_NSE
769 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
770 "%s: scheduling schedule_flood_message in %lu\n",
771 GNUNET_i2s (&my_identity),
772 GNUNET_TIME_absolute_get_remaining (next_timestamp).rel_value);
773#endif
774 if (schedule_flood_task != GNUNET_SCHEDULER_NO_TASK)
775 GNUNET_SCHEDULER_cancel (schedule_flood_task);
776
777 schedule_flood_task
778 = GNUNET_SCHEDULER_add_delayed (
779 GNUNET_TIME_absolute_get_remaining (
780 next_timestamp),
781 &schedule_flood_message, NULL);
782}
783 924
784/** 925/**
785 * Method called whenever a peer connects. 926 * Method called whenever a peer connects.
@@ -794,14 +935,18 @@ handle_core_connect(void *cls, const struct GNUNET_PeerIdentity *peer,
794{ 935{
795 struct NSEPeerEntry *peer_entry; 936 struct NSEPeerEntry *peer_entry;
796 937
797 if (0 == (memcmp (peer, &my_identity, sizeof(struct GNUNET_PeerIdentity))))
798 return; /* Do not connect to self... */
799
800 peer_entry = GNUNET_malloc(sizeof(struct NSEPeerEntry)); 938 peer_entry = GNUNET_malloc(sizeof(struct NSEPeerEntry));
801 memcpy (&peer_entry->id, peer, sizeof(struct GNUNET_PeerIdentity)); 939 peer_entry->id = *peer;
802 GNUNET_CONTAINER_DLL_insert(peers_head, peers_tail, peer_entry); 940 GNUNET_CONTAINER_multihashmap_put (peers,
941 &peer->hashPubKey,
942 peer_entry,
943 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
944 peer_entry->transmit_task = GNUNET_SCHEDULER_add_delayed (get_transmit_delay (-1),
945 &transmit_task,
946 peer_entry);
803} 947}
804 948
949
805/** 950/**
806 * Method called whenever a peer disconnects. 951 * Method called whenever a peer disconnects.
807 * 952 *
@@ -813,57 +958,24 @@ handle_core_disconnect(void *cls, const struct GNUNET_PeerIdentity *peer)
813{ 958{
814 struct NSEPeerEntry *pos; 959 struct NSEPeerEntry *pos;
815 960
816 if (0 == (memcmp (peer, &my_identity, sizeof(struct GNUNET_PeerIdentity)))) 961 pos = GNUNET_CONTAINER_multihashmap_get (peers,
817 return; /* Ignore disconnect from self... */ 962 &peer->hashPubKey);
818 963 if (NULL == pos)
819 pos = peers_head;
820 while ((NULL != pos) && (0 != memcmp (&pos->id, peer,
821 sizeof(struct GNUNET_PeerIdentity))))
822 pos = pos->next;
823
824 if (pos == NULL)
825 { 964 {
826 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 965 GNUNET_break (0);
827 "Received disconnect before connect!\n");
828 GNUNET_break(0); /* Should never receive a disconnect message for a peer we don't know about... */
829 return; 966 return;
830 } 967 }
831 968 GNUNET_assert (GNUNET_YES ==
969 GNUNET_CONTAINER_multihashmap_remove (peers,
970 &peer->hashPubKey,
971 pos));
972 if (pos->transmit_task != GNUNET_SCHEDULER_NO_TASK)
973 GNUNET_SCHEDULER_cancel (pos->transmit_task);
832 if (pos->th != NULL) 974 if (pos->th != NULL)
833 GNUNET_CORE_notify_transmit_ready_cancel (pos->th); 975 GNUNET_CORE_notify_transmit_ready_cancel (pos->th);
834 GNUNET_CONTAINER_DLL_remove(peers_head, peers_tail, pos);
835 GNUNET_free(pos); 976 GNUNET_free(pos);
836} 977}
837 978
838/**
839 * A client disconnected. Remove it from the
840 * global DLL of clients.
841 *
842 * @param cls closure, NULL
843 * @param client identification of the client
844 */
845static void
846handle_client_disconnect(void *cls, struct GNUNET_SERVER_Client* client)
847{
848 struct ClientListEntry *cle;
849
850 while (NULL != (cle = cle_head))
851 cle = cle->next;
852
853 if (cle != NULL)
854 {
855 GNUNET_SERVER_client_drop (cle->client);
856 GNUNET_CONTAINER_DLL_remove(cle_head,
857 cle_tail,
858 cle);
859 GNUNET_free(cle);
860 }
861 if (coreAPI != NULL)
862 {
863 GNUNET_CORE_disconnect (coreAPI);
864 coreAPI = NULL;
865 }
866}
867 979
868/** 980/**
869 * Task run during shutdown. 981 * Task run during shutdown.
@@ -872,34 +984,29 @@ handle_client_disconnect(void *cls, struct GNUNET_SERVER_Client* client)
872 * @param tc unused 984 * @param tc unused
873 */ 985 */
874static void 986static void
875shutdown_task(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) 987shutdown_task(void *cls,
988 const struct GNUNET_SCHEDULER_TaskContext *tc)
876{ 989{
877 struct ClientListEntry *cle;
878
879 if (flood_task != GNUNET_SCHEDULER_NO_TASK) 990 if (flood_task != GNUNET_SCHEDULER_NO_TASK)
880 GNUNET_SCHEDULER_cancel (flood_task);
881 GNUNET_SERVER_notification_context_destroy (nc);
882 nc = NULL;
883 while (NULL != (cle = cle_head))
884 { 991 {
885 GNUNET_SERVER_client_drop (cle->client); 992 GNUNET_SCHEDULER_cancel (flood_task);
886 GNUNET_CONTAINER_DLL_remove (cle_head, 993 flood_task = GNUNET_SCHEDULER_NO_TASK;
887 cle_tail,
888 cle);
889 GNUNET_free (cle);
890 } 994 }
891 995 GNUNET_SERVER_notification_context_destroy (nc);
996 nc = NULL;
892 if (coreAPI != NULL) 997 if (coreAPI != NULL)
893 { 998 {
894 GNUNET_CORE_disconnect (coreAPI); 999 GNUNET_CORE_disconnect (coreAPI);
895 coreAPI = NULL; 1000 coreAPI = NULL;
896 } 1001 }
897
898 if (stats != NULL) 1002 if (stats != NULL)
899 GNUNET_STATISTICS_destroy (stats, GNUNET_NO); 1003 {
900 1004 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
1005 stats = NULL;
1006 }
901} 1007}
902 1008
1009
903/** 1010/**
904 * Called on core init/fail. 1011 * Called on core init/fail.
905 * 1012 *
@@ -913,54 +1020,39 @@ core_init(void *cls, struct GNUNET_CORE_Handle *server,
913 const struct GNUNET_PeerIdentity *identity, 1020 const struct GNUNET_PeerIdentity *identity,
914 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *publicKey) 1021 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *publicKey)
915{ 1022{
916 struct GNUNET_TIME_Absolute curr_time; 1023 struct GNUNET_TIME_Absolute now;
1024 struct GNUNET_TIME_Absolute prev_time;
1025 unsigned int i;
1026
917 if (server == NULL) 1027 if (server == NULL)
918 { 1028 {
919#if DEBUG_NSE 1029#if DEBUG_NSE
920 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s: Connection to core FAILED!\n", 1030 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
921 "nse", GNUNET_i2s (identity)); 1031 "Connection to core FAILED!\n");
922#endif 1032#endif
923 GNUNET_SCHEDULER_add_now (&shutdown_task, NULL); 1033 GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
924 return; 1034 return;
925 } 1035 }
926 1036 my_identity = *identity;
927 /* Copy our identity so we can use it */ 1037 my_public_key = *publicKey;
928 memcpy (&my_identity, identity, sizeof(struct GNUNET_PeerIdentity)); 1038
929 /* Copy our public key for inclusion in flood messages */ 1039 now = GNUNET_TIME_absolute_get ();
930 memcpy (&my_public_key, publicKey, 1040 current_timestamp.abs_value = (now.abs_value / GNUNET_NSE_INTERVAL.rel_value) * GNUNET_NSE_INTERVAL.rel_value;
931 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); 1041 next_timestamp.abs_value = current_timestamp.abs_value + GNUNET_NSE_INTERVAL.rel_value;
932 1042
933 if (flood_task != GNUNET_SCHEDULER_NO_TASK) 1043 for (i=0;i<HISTORY_SIZE;i++)
934 GNUNET_SCHEDULER_cancel (flood_task); 1044 {
935 1045 prev_time.abs_value = next_timestamp.abs_value - (HISTORY_SIZE - i - 1) * GNUNET_NSE_INTERVAL.rel_value;
936 /* Get the current UTC time */ 1046 setup_flood_message (i, prev_time);
937 curr_time = GNUNET_TIME_absolute_get (); 1047 }
938 /* Find the previous interval start time */ 1048 estimate_index = HISTORY_SIZE - 1;
939 previous_timestamp.abs_value = (curr_time.abs_value / GNUNET_NSE_INTERVAL) 1049 flood_task
940 * GNUNET_NSE_INTERVAL; 1050 = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining (next_timestamp),
941 /* Find the next interval start time */ 1051 &update_flood_message, NULL);
942 next_timestamp.abs_value = previous_timestamp.abs_value + GNUNET_NSE_INTERVAL; 1052 my_proof = find_proof_of_work (&my_public_key);
943
944#if DEBUG_NSE
945 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
946 "%s: Core connection initialized, I am peer: %s, scheduling flood task in %lu\n", "nse",
947 GNUNET_i2s (identity), GNUNET_TIME_absolute_get_remaining(next_timestamp));
948#endif
949 /* FIXME: In production, we'd likely want to do this immediately, but in test-beds it causes stupid behavior */
950 if (schedule_flood_task != GNUNET_SCHEDULER_NO_TASK)
951 GNUNET_SCHEDULER_cancel (schedule_flood_task);
952 schedule_flood_task
953 = GNUNET_SCHEDULER_add_delayed (
954 GNUNET_TIME_absolute_get_remaining (
955 next_timestamp),
956 &schedule_flood_message, NULL);
957
958 GNUNET_SERVER_notification_context_broadcast (
959 nc,
960 &current_estimate_message.header,
961 GNUNET_NO);
962} 1053}
963 1054
1055
964/** 1056/**
965 * Handle network size estimate clients. 1057 * Handle network size estimate clients.
966 * 1058 *
@@ -973,83 +1065,61 @@ run(void *cls, struct GNUNET_SERVER_Handle *server,
973 const struct GNUNET_CONFIGURATION_Handle *c) 1065 const struct GNUNET_CONFIGURATION_Handle *c)
974{ 1066{
975 char *keyfile; 1067 char *keyfile;
1068
976 static const struct GNUNET_SERVER_MessageHandler handlers[] = 1069 static const struct GNUNET_SERVER_MessageHandler handlers[] =
977 { 1070 {
978 { &handle_start_message, NULL, GNUNET_MESSAGE_TYPE_NSE_START, 0 }, 1071 { &handle_start_message, NULL, GNUNET_MESSAGE_TYPE_NSE_START, sizeof (struct GNUNET_MessageHeader) },
979 { NULL, NULL, 0, 0 } }; 1072 { NULL, NULL, 0, 0 }
980 1073 };
981 static const struct GNUNET_CORE_MessageHandler core_handlers[] = 1074 static const struct GNUNET_CORE_MessageHandler core_handlers[] =
982 { 1075 {
983 { &handle_p2p_size_estimate, GNUNET_MESSAGE_TYPE_NSE_P2P_FLOOD, 0 }, 1076 { &handle_p2p_size_estimate, GNUNET_MESSAGE_TYPE_NSE_P2P_FLOOD, sizeof (struct GNUNET_NSE_FloodMessage) },
984 { NULL, 0, 0 } }; 1077 { NULL, 0, 0 }
985 1078 };
986 cfg = c; 1079 cfg = c;
987 1080 if (GNUNET_OK !=
988 if (GNUNET_OK 1081 GNUNET_CONFIGURATION_get_value_filename (cfg,
989 != GNUNET_CONFIGURATION_get_value_filename (c, "GNUNETD", "HOSTKEY", 1082 "GNUNETD", "HOSTKEY",
990 &keyfile)) 1083 &keyfile))
991 { 1084 {
992 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ 1085 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
993 ("NSE service is lacking key configuration settings. Exiting.\n")); 1086 _ ("NSE service is lacking key configuration settings. Exiting.\n"));
994 GNUNET_SCHEDULER_shutdown (); 1087 GNUNET_SCHEDULER_shutdown ();
995 return; 1088 return;
996 } 1089 }
997
998 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); 1090 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
999 GNUNET_free (keyfile); 1091 GNUNET_free (keyfile);
1000 if (my_private_key == NULL) 1092 if (my_private_key == NULL)
1001 { 1093 {
1002 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1094 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1003 _("NSE Service could not access hostkey. Exiting.\n")); 1095 _("NSE service could not access hostkey. Exiting.\n"));
1004 GNUNET_SCHEDULER_shutdown (); 1096 GNUNET_SCHEDULER_shutdown ();
1005 return; 1097 return;
1006 } 1098 }
1007
1008 GNUNET_SERVER_add_handlers (server, handlers); 1099 GNUNET_SERVER_add_handlers (server, handlers);
1009 nc = GNUNET_SERVER_notification_context_create (server, 16); 1100 nc = GNUNET_SERVER_notification_context_create (server, 1);
1010 GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL); 1101 /* Connect to core service and register core handlers */
1011
1012 flood_task = GNUNET_SCHEDULER_NO_TASK;
1013 /** Connect to core service and register core handlers */
1014 coreAPI = GNUNET_CORE_connect (cfg, /* Main configuration */ 1102 coreAPI = GNUNET_CORE_connect (cfg, /* Main configuration */
1015 DEFAULT_CORE_QUEUE_SIZE, /* queue size */ 1103 CORE_QUEUE_SIZE, /* queue size */
1016 NULL, /* Closure passed to functions */ 1104 NULL, /* Closure passed to functions */
1017 &core_init, /* Call core_init once connected */ 1105 &core_init, /* Call core_init once connected */
1018 &handle_core_connect, /* Handle connects */ 1106 &handle_core_connect, /* Handle connects */
1019 &handle_core_disconnect, /* Handle disconnects */ 1107 &handle_core_disconnect, /* Handle disconnects */
1020 NULL, /* Do we care about "status" updates? */ 1108 NULL, /* Do we care about "status" updates? */
1021 NULL, /* Don't want notified about all incoming messages */ 1109 NULL, /* Don't want notified about all incoming messages */
1022 GNUNET_NO, /* For header only inbound notification */ 1110 GNUNET_NO, /* For header only inbound notification */
1023 NULL, /* Don't want notified about all outbound messages */ 1111 NULL, /* Don't want notified about all outbound messages */
1024 GNUNET_NO, /* For header only outbound notification */ 1112 GNUNET_NO, /* For header only outbound notification */
1025 core_handlers); /* Register these handlers */ 1113 core_handlers); /* Register these handlers */
1026
1027 if (coreAPI == NULL) 1114 if (coreAPI == NULL)
1028 { 1115 {
1029 GNUNET_SCHEDULER_add_now (&shutdown_task, NULL); 1116 GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
1030 return; 1117 return;
1031 } 1118 }
1032
1033 stats = GNUNET_STATISTICS_create ("NSE", cfg); 1119 stats = GNUNET_STATISTICS_create ("NSE", cfg);
1034
1035 increment
1036 = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
1037 GNUNET_NSE_INTERVAL
1038 / (sizeof(GNUNET_HashCode) * 8));
1039 /* Set we have no idea defaults for network size estimate */
1040 current_size_estimate = 0.0;
1041 current_std_dev = NAN;
1042 size_estimates[estimate_index] = 0;
1043 current_estimate_message.header.size
1044 = htons (sizeof(struct GNUNET_NSE_ClientMessage));
1045 current_estimate_message.header.type
1046 = htons (GNUNET_MESSAGE_TYPE_NSE_ESTIMATE);
1047 current_estimate_message.size_estimate = current_size_estimate;
1048 current_estimate_message.std_deviation = current_std_dev;
1049 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
1050 NULL);
1051} 1120}
1052 1121
1122
1053/** 1123/**
1054 * The main function for the statistics service. 1124 * The main function for the statistics service.
1055 * 1125 *
@@ -1060,10 +1130,11 @@ run(void *cls, struct GNUNET_SERVER_Handle *server,
1060int 1130int
1061main(int argc, char * const *argv) 1131main(int argc, char * const *argv)
1062{ 1132{
1063 return (GNUNET_OK == GNUNET_SERVICE_run (argc, argv, "nse", 1133 return (GNUNET_OK == GNUNET_SERVICE_run (argc, argv,
1134 "gnunet-service-nse",
1064 GNUNET_SERVICE_OPTION_NONE, &run, 1135 GNUNET_SERVICE_OPTION_NONE, &run,
1065 NULL)) ? 0 : 1; 1136 NULL)) ? 0 : 1;
1066} 1137}
1067 1138
1068/* End of gnunet-service-nse.c */ 1139/* end of gnunet-service-nse.c */
1069 1140
diff --git a/src/nse/nse.h b/src/nse/nse.h
index a1bf2b1dd..9a13d99b2 100644
--- a/src/nse/nse.h
+++ b/src/nse/nse.h
@@ -45,11 +45,16 @@
45struct GNUNET_NSE_ClientMessage 45struct GNUNET_NSE_ClientMessage
46{ 46{
47 /** 47 /**
48 * Type: GNUNET_MESSAGE_TYPE_NSE_UPDATE 48 * Type: GNUNET_MESSAGE_TYPE_NSE_UPDATE
49 */ 49 */
50 struct GNUNET_MessageHeader header; 50 struct GNUNET_MessageHeader header;
51 51
52 /* 52 /**
53 * For alignment.
54 */
55 uint32_t reserved;
56
57 /**
53 * The current estimated network size. 58 * The current estimated network size.
54 */ 59 */
55 double size_estimate; 60 double size_estimate;
@@ -62,50 +67,5 @@ struct GNUNET_NSE_ClientMessage
62 double std_deviation; 67 double std_deviation;
63}; 68};
64 69
65/**
66 * Network size estimate reply; sent when "this"
67 * peer's timer has run out before receiving a
68 * valid reply from another peer.
69 */
70struct GNUNET_NSE_FloodMessage
71{
72 /**
73 * Type: GNUNET_MESSAGE_TYPE_NSE_P2P_FLOOD
74 */
75 struct GNUNET_MessageHeader header;
76
77 /**
78 * Purpose.
79 */
80 struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
81
82 /**
83 * Number of matching bits between the hash
84 * of timestamp and the initiator's public
85 * key.
86 */
87 uint32_t distance;
88
89 /**
90 * The current timestamp value (which all
91 * peers should agree on).
92 */
93 struct GNUNET_TIME_AbsoluteNBO timestamp;
94
95 /**
96 * Public key of the originator.
97 */
98 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey;
99
100 /**
101 * FIXME: use, document.
102 */
103 uint32_t proof_of_work;
104
105 /**
106 * FIXME: use, document.
107 */
108 struct GNUNET_CRYPTO_RsaSignature signature;
109};
110 70
111#endif 71#endif
diff --git a/src/nse/nse_api.c b/src/nse/nse_api.c
index 4c441608f..a50cd5a41 100644
--- a/src/nse/nse_api.c
+++ b/src/nse/nse_api.c
@@ -22,8 +22,6 @@
22 * @file nse/nse_api.c 22 * @file nse/nse_api.c
23 * @brief api to get information from the network size estimation service 23 * @brief api to get information from the network size estimation service
24 * @author Nathan Evans 24 * @author Nathan Evans
25 *
26 * TODO:
27 */ 25 */
28#include "platform.h" 26#include "platform.h"
29#include "gnunet_client_lib.h" 27#include "gnunet_client_lib.h"
@@ -69,17 +67,6 @@ struct GNUNET_NSE_Handle
69 struct GNUNET_TIME_Relative reconnect_delay; 67 struct GNUNET_TIME_Relative reconnect_delay;
70 68
71 /** 69 /**
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. 70 * Callback function to call when message is received.
84 */ 71 */
85 GNUNET_NSE_Callback recv_cb; 72 GNUNET_NSE_Callback recv_cb;
@@ -93,45 +80,57 @@ struct GNUNET_NSE_Handle
93 80
94 81
95/** 82/**
83 * Try again to connect to network size estimation service.
84 *
85 * @param cls the handle to the transport service
86 * @param tc scheduler context
87 */
88static void
89reconnect (void *cls,
90 const struct GNUNET_SCHEDULER_TaskContext *tc);
91
92
93/**
96 * Type of a function to call when we receive a message 94 * Type of a function to call when we receive a message
97 * from the service. 95 * from the service.
98 * 96 *
99 * @param cls closure 97 * @param cls closure
100 * @param msg message received, NULL on timeout or fatal error 98 * @param msg message received, NULL on timeout or fatal error
101 */ 99 */
102void message_handler (void *cls, 100static void
103 const struct GNUNET_MessageHeader * msg) 101message_handler (void *cls,
102 const struct GNUNET_MessageHeader * msg)
104{ 103{
105 struct GNUNET_NSE_Handle *h = cls; 104 struct GNUNET_NSE_Handle *h = cls;
106 struct GNUNET_NSE_ClientMessage *client_msg; 105 const struct GNUNET_NSE_ClientMessage *client_msg;
107
108 if (msg == NULL) /* Error, timeout, death */
109 return;
110 106
111 if ((ntohs (msg->size) < sizeof(struct GNUNET_NSE_ClientMessage)) 107 if (msg == NULL)
112 || (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_NSE_ESTIMATE))
113 { 108 {
114#if DEBUG_NSE 109 /* Error, timeout, death */
115 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 110 GNUNET_CLIENT_disconnect (h->client, GNUNET_NO);
116 "%s: received incorrect message (size %d < %d) from service!", 111 h->client = NULL;
117 "NSE API", ntohs (msg->size), 112 h->reconnect_task = GNUNET_SCHEDULER_add_delayed (h->reconnect_delay,
118 sizeof(struct GNUNET_NSE_ClientMessage)); 113 &reconnect,
119#endif 114 h);
120 return; 115 return;
121 } 116 }
122 117 if ( (ntohs (msg->size) != sizeof(struct GNUNET_NSE_ClientMessage)) ||
123 client_msg = (struct GNUNET_NSE_ClientMessage *)msg; 118 (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_NSE_ESTIMATE) )
124 119 {
125 h->recv_cb (h->recv_cb_cls, client_msg->size_estimate, 120 GNUNET_break (0);
121 return;
122 }
123 client_msg = (const struct GNUNET_NSE_ClientMessage *)msg;
124 h->recv_cb (h->recv_cb_cls,
125 client_msg->size_estimate,
126 client_msg->std_deviation); 126 client_msg->std_deviation);
127
128 GNUNET_CLIENT_receive (h->client, 127 GNUNET_CLIENT_receive (h->client,
129 &message_handler, h, GNUNET_TIME_UNIT_FOREVER_REL); 128 &message_handler,
129 h,
130 GNUNET_TIME_UNIT_FOREVER_REL);
130} 131}
131 132
132static void 133
133reconnect (void *cls,
134 const struct GNUNET_SCHEDULER_TaskContext *tc);
135 134
136/** 135/**
137 * Reschedule a connect attempt to the service. 136 * Reschedule a connect attempt to the service.
@@ -174,6 +173,7 @@ reschedule_connect (struct GNUNET_NSE_Handle *h)
174 } 173 }
175} 174}
176 175
176
177/** 177/**
178 * Transmit START message to service. 178 * Transmit START message to service.
179 * 179 *
@@ -214,6 +214,7 @@ send_start (void *cls, size_t size, void *buf)
214 return sizeof (struct GNUNET_MessageHeader); 214 return sizeof (struct GNUNET_MessageHeader);
215} 215}
216 216
217
217/** 218/**
218 * Try again to connect to network size estimation service. 219 * Try again to connect to network size estimation service.
219 * 220 *
@@ -250,6 +251,7 @@ reconnect (void *cls,
250 GNUNET_assert(h->th != NULL); 251 GNUNET_assert(h->th != NULL);
251} 252}
252 253
254
253/** 255/**
254 * Connect to the network size estimation service. 256 * Connect to the network size estimation service.
255 * 257 *
@@ -265,11 +267,8 @@ GNUNET_NSE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
265{ 267{
266 struct GNUNET_NSE_Handle *ret; 268 struct GNUNET_NSE_Handle *ret;
267 269
270 GNUNET_assert (func != NULL);
268 ret = GNUNET_malloc (sizeof (struct GNUNET_NSE_Handle)); 271 ret = GNUNET_malloc (sizeof (struct GNUNET_NSE_Handle));
269
270 if (func == NULL)
271 return NULL;
272
273 ret->cfg = cfg; 272 ret->cfg = cfg;
274 ret->recv_cb = func; 273 ret->recv_cb = func;
275 ret->recv_cb_cls = func_cls; 274 ret->recv_cb_cls = func_cls;
@@ -278,11 +277,11 @@ GNUNET_NSE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
278 return ret; 277 return ret;
279} 278}
280 279
280
281/** 281/**
282 * Disconnect from network size estimation service 282 * Disconnect from network size estimation service
283 * 283 *
284 * @param h handle to destroy 284 * @param h handle to destroy
285 *
286 */ 285 */
287void 286void
288GNUNET_NSE_disconnect (struct GNUNET_NSE_Handle *h) 287GNUNET_NSE_disconnect (struct GNUNET_NSE_Handle *h)
@@ -294,9 +293,16 @@ GNUNET_NSE_disconnect (struct GNUNET_NSE_Handle *h)
294 h->reconnect_task = GNUNET_SCHEDULER_NO_TASK; 293 h->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
295 } 294 }
296 if (h->th != NULL) 295 if (h->th != NULL)
297 GNUNET_CLIENT_notify_transmit_ready_cancel(h->th); 296 {
297 GNUNET_CLIENT_notify_transmit_ready_cancel(h->th);
298 h->th = NULL;
299 }
298 if (h->client != NULL) 300 if (h->client != NULL)
299 GNUNET_CLIENT_disconnect(h->client, GNUNET_NO); 301 {
300 302 GNUNET_CLIENT_disconnect(h->client, GNUNET_NO);
303 h->client = NULL;
304 }
301 GNUNET_free(h); 305 GNUNET_free(h);
302} 306}
307
308/* end of nse_api.c */
diff --git a/src/nse/test_nse_api.c b/src/nse/test_nse_api.c
index 4f83a6d78..273cff294 100644
--- a/src/nse/test_nse_api.c
+++ b/src/nse/test_nse_api.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 (C) 2009 Christian Grothoff (and other contributing authors) 3 (C) 2011 Christian Grothoff (and other contributing authors)
4 4
5 GNUnet is free software; you can redistribute it and/or modify 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 6 it under the terms of the GNU General Public License as published
@@ -35,7 +35,7 @@
35 35
36static struct GNUNET_NSE_Handle *h; 36static struct GNUNET_NSE_Handle *h;
37 37
38GNUNET_SCHEDULER_TaskIdentifier die_task; 38static GNUNET_SCHEDULER_TaskIdentifier die_task;
39 39
40struct PeerContext 40struct PeerContext
41{ 41{
@@ -83,18 +83,19 @@ check_nse_message (void *cls, double estimate, double std_dev)
83 /* Fantastic check below. Expect NaN, the only thing not equal to itself. */ 83 /* Fantastic check below. Expect NaN, the only thing not equal to itself. */
84 if ((estimate != estimate) && (std_dev != std_dev)) 84 if ((estimate != estimate) && (std_dev != std_dev))
85 (*ok) = 0; 85 (*ok) = 0;
86
87 if (die_task != GNUNET_SCHEDULER_NO_TASK) 86 if (die_task != GNUNET_SCHEDULER_NO_TASK)
88 GNUNET_SCHEDULER_cancel(die_task); 87 GNUNET_SCHEDULER_cancel(die_task);
89 GNUNET_SCHEDULER_add_now(&end_test, NULL); 88 die_task = GNUNET_SCHEDULER_add_now(&end_test, NULL);
90} 89}
91 90
91
92static void 92static void
93setup_peer (struct PeerContext *p, const char *cfgname) 93setup_peer (struct PeerContext *p, const char *cfgname)
94{ 94{
95 p->cfg = GNUNET_CONFIGURATION_create (); 95 p->cfg = GNUNET_CONFIGURATION_create ();
96#if START_ARM 96#if START_ARM
97 p->arm_proc = GNUNET_OS_start_process (NULL, NULL, "gnunet-service-arm", 97 p->arm_proc = GNUNET_OS_start_process (NULL, NULL,
98 "gnunet-service-arm",
98 "gnunet-service-arm", 99 "gnunet-service-arm",
99#if VERBOSE_ARM 100#if VERBOSE_ARM
100 "-L", "DEBUG", 101 "-L", "DEBUG",
@@ -118,6 +119,7 @@ stop_arm (struct PeerContext *p)
118 GNUNET_CONFIGURATION_destroy (p->cfg); 119 GNUNET_CONFIGURATION_destroy (p->cfg);
119} 120}
120 121
122
121static void 123static void
122run (void *cls, 124run (void *cls,
123 char *const *args, 125 char *const *args,
@@ -135,6 +137,7 @@ run (void *cls,
135 GNUNET_assert (h != NULL); 137 GNUNET_assert (h != NULL);
136} 138}
137 139
140
138static int 141static int
139check () 142check ()
140{ 143{
@@ -161,6 +164,7 @@ check ()
161 return ok; 164 return ok;
162} 165}
163 166
167
164int 168int
165main (int argc, char *argv[]) 169main (int argc, char *argv[])
166{ 170{