diff options
author | Christian Grothoff <christian@grothoff.org> | 2011-07-23 13:23:40 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2011-07-23 13:23:40 +0000 |
commit | f53e991a59f4befa47b0ce90d8b68318dcd23864 (patch) | |
tree | 89dae5aaf3c8bef1fa1412133fe9d22d4f4e232d | |
parent | c1ed03a28d6de09d7d0ac2025af9f8067e6bb0fd (diff) | |
download | gnunet-f53e991a59f4befa47b0ce90d8b68318dcd23864.tar.gz gnunet-f53e991a59f4befa47b0ce90d8b68318dcd23864.zip |
nse hacking
-rw-r--r-- | configure.ac | 1 | ||||
-rw-r--r-- | src/Makefile.am | 1 | ||||
-rw-r--r-- | src/include/gnunet_nse_service.h | 56 | ||||
-rw-r--r-- | src/nse/Makefile.am | 2 | ||||
-rw-r--r-- | src/nse/gnunet-service-nse.c | 1413 | ||||
-rw-r--r-- | src/nse/nse.h | 54 | ||||
-rw-r--r-- | src/nse/nse_api.c | 94 | ||||
-rw-r--r-- | src/nse/test_nse_api.c | 14 |
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 | |||
755 | src/hostlist/Makefile | 755 | src/hostlist/Makefile |
756 | src/mesh/Makefile | 756 | src/mesh/Makefile |
757 | src/nat/Makefile | 757 | src/nat/Makefile |
758 | src/nse/Makefile | ||
758 | src/peerinfo/Makefile | 759 | src/peerinfo/Makefile |
759 | src/peerinfo-tool/Makefile | 760 | src/peerinfo-tool/Makefile |
760 | src/statistics/Makefile | 761 | src/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 | */ |
86 | struct GNUNET_NSE_Handle; | 53 | struct 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 | */ | ||
63 | typedef 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 | */ |
98 | typedef 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 = \ | |||
31 | nse_profiler_LDADD = \ | 31 | nse_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) |
36 | nse_profiler_DEPENDENCIES = \ | 36 | nse_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 | */ |
66 | struct ClientListEntry | 79 | #define GNUNET_NSE_INTERVAL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) |
80 | |||
81 | |||
82 | /** | ||
83 | * Per-peer information. | ||
84 | */ | ||
85 | struct 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 | */ |
87 | struct NSEPeerEntry | 121 | struct 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; | |||
128 | static struct GNUNET_CORE_Handle *coreAPI; | 181 | static struct GNUNET_CORE_Handle *coreAPI; |
129 | 182 | ||
130 | /** | 183 | /** |
131 | * Head of global list of peers. | 184 | * Map of all connected peers. |
132 | */ | ||
133 | static struct NSEPeerEntry *peers_head; | ||
134 | |||
135 | /** | ||
136 | * Head of global list of clients. | ||
137 | */ | ||
138 | static struct NSEPeerEntry *peers_tail; | ||
139 | |||
140 | /** | ||
141 | * Head of global list of clients. | ||
142 | */ | ||
143 | static struct ClientListEntry *cle_head; | ||
144 | |||
145 | /** | ||
146 | * Tail of global list of clients. | ||
147 | */ | 185 | */ |
148 | static struct ClientListEntry *cle_tail; | 186 | static 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 | */ |
155 | static double current_size_estimate; | 192 | static 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 | */ |
161 | static double current_std_dev; | 198 | static 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 | */ |
167 | static unsigned int size_estimates[DEFAULT_HISTORY_SIZE]; | 203 | static uint32_t hop_count_max; |
168 | 204 | ||
169 | /** | 205 | /** |
170 | * Array of size estimate messages. | 206 | * Array of recent size estimate messages. |
171 | */ | 207 | */ |
172 | static struct GNUNET_NSE_FloodMessage | 208 | static 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 | |||
178 | static unsigned int estimate_index; | 213 | static 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 | */ |
183 | static GNUNET_SCHEDULER_TaskIdentifier flood_task; | 218 | static GNUNET_SCHEDULER_TaskIdentifier flood_task; |
184 | 219 | ||
185 | /** | 220 | /** |
186 | * Task to schedule flood message and update state. | ||
187 | */ | ||
188 | static GNUNET_SCHEDULER_TaskIdentifier schedule_flood_task; | ||
189 | |||
190 | /** | ||
191 | * Notification context, simplifies client broadcasts. | 221 | * Notification context, simplifies client broadcasts. |
192 | */ | 222 | */ |
193 | static struct GNUNET_SERVER_NotificationContext *nc; | 223 | static struct GNUNET_SERVER_NotificationContext *nc; |
194 | 224 | ||
195 | /** | 225 | /** |
196 | * The previous major time. | ||
197 | */ | ||
198 | static struct GNUNET_TIME_Absolute previous_timestamp; | ||
199 | |||
200 | /** | ||
201 | * The next major time. | 226 | * The next major time. |
202 | */ | 227 | */ |
203 | static struct GNUNET_TIME_Absolute next_timestamp; | 228 | static 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 | */ |
208 | static struct GNUNET_TIME_Relative increment; | 233 | static struct GNUNET_TIME_Absolute current_timestamp; |
209 | |||
210 | /** | ||
211 | * The current network size estimate message. | ||
212 | */ | ||
213 | static 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; | |||
228 | static struct GNUNET_PeerIdentity my_identity; | 248 | static 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 | */ |
233 | static struct GNUNET_NSE_FloodMessage flood_message; | 253 | static 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 | */ | ||
262 | static void | ||
263 | setup_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 | |||
246 | handle_start_message(void *cls, struct GNUNET_SERVER_Client *client, | 323 | handle_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 | */ | ||
344 | static double | ||
345 | get_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 | */ | ||
363 | static struct GNUNET_TIME_Relative | ||
364 | get_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 | */ | ||
383 | static uint32_t | ||
384 | get_matching_bits (struct GNUNET_TIME_Absolute timestamp, | ||
385 | const struct GNUNET_PeerIdentity *id) | ||
386 | { | ||
387 | GNUNET_HashCode timestamp_hash; | ||
388 | |||
389 | GNUNET_CRYPTO_hash (×tamp.abs_value, | ||
390 | sizeof(timestamp.abs_value), | ||
391 | ×tamp_hash); | ||
392 | return GNUNET_CRYPTO_hash_matching_bits (×tamp_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 | */ | ||
405 | static struct GNUNET_TIME_Relative | ||
406 | get_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 | */ | ||
441 | static void | ||
442 | transmit_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 | */ |
270 | static size_t | 455 | static size_t |
271 | transmit_ready(void *cls, size_t size, void *buf) | 456 | transmit_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 | 499 | static void |
306 | return msize; | 500 | transmit_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 | */ | ||
523 | static void | ||
524 | update_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 | */ |
317 | static void | 542 | static void |
318 | update_network_size_estimate(struct GNUNET_NSE_FloodMessage *message) | 543 | setup_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 | */ | ||
578 | static int | ||
579 | schedule_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 | ¤t_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 | ||
396 | static void | ||
397 | send_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 | */ |
412 | static void | 610 | static void |
413 | schedule_flood_message(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | 611 | update_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), ×tamp_hash); | ||
452 | matching_bits = GNUNET_CRYPTO_hash_matching_bits (×tamp_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 | */ | ||
651 | static unsigned int | ||
652 | count_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 | */ |
518 | static int check_proof_of_work(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey, uint64_t val, unsigned int want) | 672 | static int |
519 | { | 673 | check_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)); |
531 | static 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 | */ |
555 | static uint64_t find_proof_of_work(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *pkey, unsigned int want) | 698 | static uint64_t |
556 | { | 699 | find_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 | */ |
589 | static int verify_message_crypto(struct GNUNET_NSE_FloodMessage *incoming_flood) | 733 | static int |
590 | { | 734 | verify_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 | */ | ||
765 | static int | ||
766 | update_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 | */ |
612 | static int | 807 | static int |
613 | handle_p2p_size_estimate(void *cls, const struct GNUNET_PeerIdentity *peer, | 808 | handle_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 | */ | ||
713 | static void | ||
714 | send_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 | */ | ||
845 | static void | ||
846 | handle_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 | */ |
874 | static void | 986 | static void |
875 | shutdown_task(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | 987 | shutdown_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 | ¤t_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, | |||
1060 | int | 1130 | int |
1061 | main(int argc, char * const *argv) | 1131 | main(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 @@ | |||
45 | struct GNUNET_NSE_ClientMessage | 45 | struct 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 | */ | ||
70 | struct 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 | */ | ||
88 | static void | ||
89 | reconnect (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 | */ |
102 | void message_handler (void *cls, | 100 | static void |
103 | const struct GNUNET_MessageHeader * msg) | 101 | message_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 | ||
132 | static void | 133 | |
133 | reconnect (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 | */ |
287 | void | 286 | void |
288 | GNUNET_NSE_disconnect (struct GNUNET_NSE_Handle *h) | 287 | GNUNET_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 | ||
36 | static struct GNUNET_NSE_Handle *h; | 36 | static struct GNUNET_NSE_Handle *h; |
37 | 37 | ||
38 | GNUNET_SCHEDULER_TaskIdentifier die_task; | 38 | static GNUNET_SCHEDULER_TaskIdentifier die_task; |
39 | 39 | ||
40 | struct PeerContext | 40 | struct 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 | |||
92 | static void | 92 | static void |
93 | setup_peer (struct PeerContext *p, const char *cfgname) | 93 | setup_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 | |||
121 | static void | 123 | static void |
122 | run (void *cls, | 124 | run (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 | |||
138 | static int | 141 | static int |
139 | check () | 142 | check () |
140 | { | 143 | { |
@@ -161,6 +164,7 @@ check () | |||
161 | return ok; | 164 | return ok; |
162 | } | 165 | } |
163 | 166 | ||
167 | |||
164 | int | 168 | int |
165 | main (int argc, char *argv[]) | 169 | main (int argc, char *argv[]) |
166 | { | 170 | { |