diff options
author | Christian Grothoff <christian@grothoff.org> | 2011-10-17 11:40:45 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2011-10-17 11:40:45 +0000 |
commit | 43fd4ad946c398e06e5048837de8b3e48d9cd8ff (patch) | |
tree | 0b0f10d60eaf15209cbc4a3f2c2d1a59cc869e59 /src/core/gnunet-service-core.c | |
parent | 0f316ae394d8de0f386f7cbba00d7b01fc250272 (diff) | |
download | gnunet-43fd4ad946c398e06e5048837de8b3e48d9cd8ff.tar.gz gnunet-43fd4ad946c398e06e5048837de8b3e48d9cd8ff.zip |
remove old core
Diffstat (limited to 'src/core/gnunet-service-core.c')
-rw-r--r-- | src/core/gnunet-service-core.c | 4460 |
1 files changed, 0 insertions, 4460 deletions
diff --git a/src/core/gnunet-service-core.c b/src/core/gnunet-service-core.c deleted file mode 100644 index 010c42a09..000000000 --- a/src/core/gnunet-service-core.c +++ /dev/null | |||
@@ -1,4460 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2009, 2010 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 3, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file core/gnunet-service-core.c | ||
23 | * @brief high-level P2P messaging | ||
24 | * @author Christian Grothoff | ||
25 | * | ||
26 | * Type map implementation: | ||
27 | * - track type maps for neighbours (can wait) | ||
28 | * - only notify clients about peers with matching type maps (can wait) | ||
29 | * | ||
30 | * Considerations for later: | ||
31 | * - check that hostkey used by transport (for HELLOs) is the | ||
32 | * same as the hostkey that we are using! | ||
33 | */ | ||
34 | #include "platform.h" | ||
35 | #include <zlib.h> | ||
36 | #include "gnunet_constants.h" | ||
37 | #include "gnunet_util_lib.h" | ||
38 | #include "gnunet_hello_lib.h" | ||
39 | #include "gnunet_peerinfo_service.h" | ||
40 | #include "gnunet_protocols.h" | ||
41 | #include "gnunet_signatures.h" | ||
42 | #include "gnunet_statistics_service.h" | ||
43 | #include "gnunet_transport_service.h" | ||
44 | #include "core.h" | ||
45 | |||
46 | |||
47 | #define DEBUG_HANDSHAKE GNUNET_EXTRA_LOGGING | ||
48 | |||
49 | #define DEBUG_CORE_QUOTA GNUNET_EXTRA_LOGGING | ||
50 | |||
51 | /** | ||
52 | * Receive and send buffer windows grow over time. For | ||
53 | * how long can 'unused' bandwidth accumulate before we | ||
54 | * need to cap it? (specified in seconds). | ||
55 | */ | ||
56 | #define MAX_WINDOW_TIME_S (5 * 60) | ||
57 | |||
58 | /** | ||
59 | * How many messages do we queue up at most for optional | ||
60 | * notifications to a client? (this can cause notifications | ||
61 | * about outgoing messages to be dropped). | ||
62 | */ | ||
63 | #define MAX_NOTIFY_QUEUE 1024 | ||
64 | |||
65 | /** | ||
66 | * Minimum bandwidth (out) to assign to any connected peer. | ||
67 | * Should be rather low; values larger than DEFAULT_BW_IN_OUT make no | ||
68 | * sense. | ||
69 | */ | ||
70 | #define MIN_BANDWIDTH_PER_PEER GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT | ||
71 | |||
72 | /** | ||
73 | * After how much time past the "official" expiration time do | ||
74 | * we discard messages? Should not be zero since we may | ||
75 | * intentionally defer transmission until close to the deadline | ||
76 | * and then may be slightly past the deadline due to inaccuracy | ||
77 | * in sleep and our own CPU consumption. | ||
78 | */ | ||
79 | #define PAST_EXPIRATION_DISCARD_TIME GNUNET_TIME_UNIT_SECONDS | ||
80 | |||
81 | /** | ||
82 | * What is the maximum delay for a SET_KEY message? | ||
83 | */ | ||
84 | #define MAX_SET_KEY_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10) | ||
85 | |||
86 | /** | ||
87 | * How long do we wait for SET_KEY confirmation initially? | ||
88 | */ | ||
89 | #define INITIAL_SET_KEY_RETRY_FREQUENCY GNUNET_TIME_relative_multiply (MAX_SET_KEY_DELAY, 1) | ||
90 | |||
91 | /** | ||
92 | * What is the maximum delay for a PING message? | ||
93 | */ | ||
94 | #define MAX_PING_DELAY GNUNET_TIME_relative_multiply (MAX_SET_KEY_DELAY, 2) | ||
95 | |||
96 | /** | ||
97 | * What is the maximum delay for a PONG message? | ||
98 | */ | ||
99 | #define MAX_PONG_DELAY GNUNET_TIME_relative_multiply (MAX_PING_DELAY, 2) | ||
100 | |||
101 | /** | ||
102 | * What is the minimum frequency for a PING message? | ||
103 | */ | ||
104 | #define MIN_PING_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) | ||
105 | |||
106 | /** | ||
107 | * How often do we recalculate bandwidth quotas? | ||
108 | */ | ||
109 | #define QUOTA_UPDATE_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) | ||
110 | |||
111 | /** | ||
112 | * What is the priority for a SET_KEY message? | ||
113 | */ | ||
114 | #define SET_KEY_PRIORITY 0xFFFFFF | ||
115 | |||
116 | /** | ||
117 | * What is the priority for a PING message? | ||
118 | */ | ||
119 | #define PING_PRIORITY 0xFFFFFF | ||
120 | |||
121 | /** | ||
122 | * What is the priority for a PONG message? | ||
123 | */ | ||
124 | #define PONG_PRIORITY 0xFFFFFF | ||
125 | |||
126 | /** | ||
127 | * How many messages do we queue per peer at most? Must be at | ||
128 | * least two. | ||
129 | */ | ||
130 | #define MAX_PEER_QUEUE_SIZE 16 | ||
131 | |||
132 | /** | ||
133 | * How many non-mandatory messages do we queue per client at most? | ||
134 | */ | ||
135 | #define MAX_CLIENT_QUEUE_SIZE 32 | ||
136 | |||
137 | /** | ||
138 | * What is the maximum age of a message for us to consider | ||
139 | * processing it? Note that this looks at the timestamp used | ||
140 | * by the other peer, so clock skew between machines does | ||
141 | * come into play here. So this should be picked high enough | ||
142 | * so that a little bit of clock skew does not prevent peers | ||
143 | * from connecting to us. | ||
144 | */ | ||
145 | #define MAX_MESSAGE_AGE GNUNET_TIME_UNIT_DAYS | ||
146 | |||
147 | |||
148 | /** | ||
149 | * State machine for our P2P encryption handshake. Everyone starts in | ||
150 | * "DOWN", if we receive the other peer's key (other peer initiated) | ||
151 | * we start in state RECEIVED (since we will immediately send our | ||
152 | * own); otherwise we start in SENT. If we get back a PONG from | ||
153 | * within either state, we move up to CONFIRMED (the PONG will always | ||
154 | * be sent back encrypted with the key we sent to the other peer). | ||
155 | */ | ||
156 | enum PeerStateMachine | ||
157 | { | ||
158 | /** | ||
159 | * No handshake yet. | ||
160 | */ | ||
161 | PEER_STATE_DOWN, | ||
162 | |||
163 | /** | ||
164 | * We've sent our session key. | ||
165 | */ | ||
166 | PEER_STATE_KEY_SENT, | ||
167 | |||
168 | /** | ||
169 | * We've received the other peers session key. | ||
170 | */ | ||
171 | PEER_STATE_KEY_RECEIVED, | ||
172 | |||
173 | /** | ||
174 | * The other peer has confirmed our session key with a message | ||
175 | * encrypted with his session key (which we got). Session is now fully up. | ||
176 | */ | ||
177 | PEER_STATE_KEY_CONFIRMED | ||
178 | }; | ||
179 | |||
180 | |||
181 | /** | ||
182 | * Encapsulation for encrypted messages exchanged between | ||
183 | * peers. Followed by the actual encrypted data. | ||
184 | */ | ||
185 | struct EncryptedMessage | ||
186 | { | ||
187 | /** | ||
188 | * Message type is either CORE_ENCRYPTED_MESSAGE. | ||
189 | */ | ||
190 | struct GNUNET_MessageHeader header; | ||
191 | |||
192 | /** | ||
193 | * Random value used for IV generation. | ||
194 | */ | ||
195 | uint32_t iv_seed GNUNET_PACKED; | ||
196 | |||
197 | /** | ||
198 | * MAC of the encrypted message (starting at 'sequence_number'), | ||
199 | * used to verify message integrity. Everything after this value | ||
200 | * (excluding this value itself) will be encrypted and authenticated. | ||
201 | * ENCRYPTED_HEADER_SIZE must be set to the offset of the *next* field. | ||
202 | */ | ||
203 | GNUNET_HashCode hmac; | ||
204 | |||
205 | /** | ||
206 | * Sequence number, in network byte order. This field | ||
207 | * must be the first encrypted/decrypted field | ||
208 | */ | ||
209 | uint32_t sequence_number GNUNET_PACKED; | ||
210 | |||
211 | /** | ||
212 | * Desired bandwidth (how much we should send to this peer / how | ||
213 | * much is the sender willing to receive)? | ||
214 | */ | ||
215 | struct GNUNET_BANDWIDTH_Value32NBO inbound_bw_limit; | ||
216 | |||
217 | /** | ||
218 | * Timestamp. Used to prevent reply of ancient messages | ||
219 | * (recent messages are caught with the sequence number). | ||
220 | */ | ||
221 | struct GNUNET_TIME_AbsoluteNBO timestamp; | ||
222 | |||
223 | }; | ||
224 | |||
225 | |||
226 | /** | ||
227 | * Number of bytes (at the beginning) of "struct EncryptedMessage" | ||
228 | * that are NOT encrypted. | ||
229 | */ | ||
230 | #define ENCRYPTED_HEADER_SIZE (offsetof(struct EncryptedMessage, sequence_number)) | ||
231 | |||
232 | |||
233 | /** | ||
234 | * We're sending an (encrypted) PING to the other peer to check if he | ||
235 | * can decrypt. The other peer should respond with a PONG with the | ||
236 | * same content, except this time encrypted with the receiver's key. | ||
237 | */ | ||
238 | struct PingMessage | ||
239 | { | ||
240 | /** | ||
241 | * Message type is CORE_PING. | ||
242 | */ | ||
243 | struct GNUNET_MessageHeader header; | ||
244 | |||
245 | /** | ||
246 | * Seed for the IV | ||
247 | */ | ||
248 | uint32_t iv_seed GNUNET_PACKED; | ||
249 | |||
250 | /** | ||
251 | * Intended target of the PING, used primarily to check | ||
252 | * that decryption actually worked. | ||
253 | */ | ||
254 | struct GNUNET_PeerIdentity target; | ||
255 | |||
256 | /** | ||
257 | * Random number chosen to make reply harder. | ||
258 | */ | ||
259 | uint32_t challenge GNUNET_PACKED; | ||
260 | }; | ||
261 | |||
262 | |||
263 | |||
264 | /** | ||
265 | * Response to a PING. Includes data from the original PING | ||
266 | * plus initial bandwidth quota information. | ||
267 | */ | ||
268 | struct PongMessage | ||
269 | { | ||
270 | /** | ||
271 | * Message type is CORE_PONG. | ||
272 | */ | ||
273 | struct GNUNET_MessageHeader header; | ||
274 | |||
275 | /** | ||
276 | * Seed for the IV | ||
277 | */ | ||
278 | uint32_t iv_seed GNUNET_PACKED; | ||
279 | |||
280 | /** | ||
281 | * Random number to make faking the reply harder. Must be | ||
282 | * first field after header (this is where we start to encrypt!). | ||
283 | */ | ||
284 | uint32_t challenge GNUNET_PACKED; | ||
285 | |||
286 | /** | ||
287 | * Desired bandwidth (how much we should send to this | ||
288 | * peer / how much is the sender willing to receive). | ||
289 | */ | ||
290 | struct GNUNET_BANDWIDTH_Value32NBO inbound_bw_limit; | ||
291 | |||
292 | /** | ||
293 | * Intended target of the PING, used primarily to check | ||
294 | * that decryption actually worked. | ||
295 | */ | ||
296 | struct GNUNET_PeerIdentity target; | ||
297 | }; | ||
298 | |||
299 | |||
300 | /** | ||
301 | * Message transmitted to set (or update) a session key. | ||
302 | */ | ||
303 | struct SetKeyMessage | ||
304 | { | ||
305 | |||
306 | /** | ||
307 | * Message type is either CORE_SET_KEY. | ||
308 | */ | ||
309 | struct GNUNET_MessageHeader header; | ||
310 | |||
311 | /** | ||
312 | * Status of the sender (should be in "enum PeerStateMachine"), nbo. | ||
313 | */ | ||
314 | int32_t sender_status GNUNET_PACKED; | ||
315 | |||
316 | /** | ||
317 | * Purpose of the signature, will be | ||
318 | * GNUNET_SIGNATURE_PURPOSE_SET_KEY. | ||
319 | */ | ||
320 | struct GNUNET_CRYPTO_RsaSignaturePurpose purpose; | ||
321 | |||
322 | /** | ||
323 | * At what time was this key created? | ||
324 | */ | ||
325 | struct GNUNET_TIME_AbsoluteNBO creation_time; | ||
326 | |||
327 | /** | ||
328 | * The encrypted session key. | ||
329 | */ | ||
330 | struct GNUNET_CRYPTO_RsaEncryptedData encrypted_key; | ||
331 | |||
332 | /** | ||
333 | * Who is the intended recipient? | ||
334 | */ | ||
335 | struct GNUNET_PeerIdentity target; | ||
336 | |||
337 | /** | ||
338 | * Signature of the stuff above (starting at purpose). | ||
339 | */ | ||
340 | struct GNUNET_CRYPTO_RsaSignature signature; | ||
341 | |||
342 | }; | ||
343 | |||
344 | |||
345 | /** | ||
346 | * Message waiting for transmission. This struct | ||
347 | * is followed by the actual content of the message. | ||
348 | */ | ||
349 | struct MessageEntry | ||
350 | { | ||
351 | |||
352 | /** | ||
353 | * We keep messages in a doubly linked list. | ||
354 | */ | ||
355 | struct MessageEntry *next; | ||
356 | |||
357 | /** | ||
358 | * We keep messages in a doubly linked list. | ||
359 | */ | ||
360 | struct MessageEntry *prev; | ||
361 | |||
362 | /** | ||
363 | * By when are we supposed to transmit this message? | ||
364 | */ | ||
365 | struct GNUNET_TIME_Absolute deadline; | ||
366 | |||
367 | /** | ||
368 | * By when are we supposed to transmit this message (after | ||
369 | * giving slack)? | ||
370 | */ | ||
371 | struct GNUNET_TIME_Absolute slack_deadline; | ||
372 | |||
373 | /** | ||
374 | * How important is this message to us? | ||
375 | */ | ||
376 | unsigned int priority; | ||
377 | |||
378 | /** | ||
379 | * If this is a SET_KEY message, what was our connection status when this | ||
380 | * message was queued? | ||
381 | */ | ||
382 | enum PeerStateMachine sender_status; | ||
383 | |||
384 | /** | ||
385 | * Is this a SET_KEY message? | ||
386 | */ | ||
387 | int is_setkey; | ||
388 | |||
389 | /** | ||
390 | * How long is the message? (number of bytes following | ||
391 | * the "struct MessageEntry", but not including the | ||
392 | * size of "struct MessageEntry" itself!) | ||
393 | */ | ||
394 | uint16_t size; | ||
395 | |||
396 | /** | ||
397 | * Was this message selected for transmission in the | ||
398 | * current round? GNUNET_YES or GNUNET_NO. | ||
399 | */ | ||
400 | int8_t do_transmit; | ||
401 | |||
402 | /** | ||
403 | * Did we give this message some slack (delayed sending) previously | ||
404 | * (and hence should not give it any more slack)? GNUNET_YES or | ||
405 | * GNUNET_NO. | ||
406 | */ | ||
407 | int8_t got_slack; | ||
408 | |||
409 | }; | ||
410 | |||
411 | |||
412 | /** | ||
413 | * Record kept for each request for transmission issued by a | ||
414 | * client that is still pending. | ||
415 | */ | ||
416 | struct ClientActiveRequest; | ||
417 | |||
418 | /** | ||
419 | * Data kept per neighbouring peer. | ||
420 | */ | ||
421 | struct Neighbour | ||
422 | { | ||
423 | |||
424 | /** | ||
425 | * Unencrypted messages destined for this peer. | ||
426 | */ | ||
427 | struct MessageEntry *messages; | ||
428 | |||
429 | /** | ||
430 | * Head of the batched, encrypted message queue (already ordered, | ||
431 | * transmit starting with the head). | ||
432 | */ | ||
433 | struct MessageEntry *encrypted_head; | ||
434 | |||
435 | /** | ||
436 | * Tail of the batched, encrypted message queue (already ordered, | ||
437 | * append new messages to tail) | ||
438 | */ | ||
439 | struct MessageEntry *encrypted_tail; | ||
440 | |||
441 | /** | ||
442 | * Head of list of requests from clients for transmission to | ||
443 | * this peer. | ||
444 | */ | ||
445 | struct ClientActiveRequest *active_client_request_head; | ||
446 | |||
447 | /** | ||
448 | * Tail of list of requests from clients for transmission to | ||
449 | * this peer. | ||
450 | */ | ||
451 | struct ClientActiveRequest *active_client_request_tail; | ||
452 | |||
453 | /** | ||
454 | * Handle for pending requests for transmission to this peer | ||
455 | * with the transport service. NULL if no request is pending. | ||
456 | */ | ||
457 | struct GNUNET_TRANSPORT_TransmitHandle *th; | ||
458 | |||
459 | /** | ||
460 | * Public key of the neighbour, NULL if we don't have it yet. | ||
461 | */ | ||
462 | struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key; | ||
463 | |||
464 | /** | ||
465 | * We received a PING message before we got the "public_key" | ||
466 | * (or the SET_KEY). We keep it here until we have a key | ||
467 | * to decrypt it. NULL if no PING is pending. | ||
468 | */ | ||
469 | struct PingMessage *pending_ping; | ||
470 | |||
471 | /** | ||
472 | * We received a PONG message before we got the "public_key" | ||
473 | * (or the SET_KEY). We keep it here until we have a key | ||
474 | * to decrypt it. NULL if no PONG is pending. | ||
475 | */ | ||
476 | struct PongMessage *pending_pong; | ||
477 | |||
478 | /** | ||
479 | * Non-NULL if we are currently looking up HELLOs for this peer. | ||
480 | * for this peer. | ||
481 | */ | ||
482 | struct GNUNET_PEERINFO_IteratorContext *pitr; | ||
483 | |||
484 | /** | ||
485 | * SetKeyMessage to transmit, NULL if we are not currently trying | ||
486 | * to send one. | ||
487 | */ | ||
488 | struct SetKeyMessage *skm; | ||
489 | |||
490 | /** | ||
491 | * Performance data for the peer. | ||
492 | */ | ||
493 | struct GNUNET_ATS_Information *ats; | ||
494 | |||
495 | /** | ||
496 | * Identity of the neighbour. | ||
497 | */ | ||
498 | struct GNUNET_PeerIdentity peer; | ||
499 | |||
500 | /** | ||
501 | * Key we use to encrypt our messages for the other peer | ||
502 | * (initialized by us when we do the handshake). | ||
503 | */ | ||
504 | struct GNUNET_CRYPTO_AesSessionKey encrypt_key; | ||
505 | |||
506 | /** | ||
507 | * Key we use to decrypt messages from the other peer | ||
508 | * (given to us by the other peer during the handshake). | ||
509 | */ | ||
510 | struct GNUNET_CRYPTO_AesSessionKey decrypt_key; | ||
511 | |||
512 | /** | ||
513 | * ID of task used for re-trying plaintext scheduling. | ||
514 | */ | ||
515 | GNUNET_SCHEDULER_TaskIdentifier retry_plaintext_task; | ||
516 | |||
517 | /** | ||
518 | * ID of task used for re-trying SET_KEY and PING message. | ||
519 | */ | ||
520 | GNUNET_SCHEDULER_TaskIdentifier retry_set_key_task; | ||
521 | |||
522 | /** | ||
523 | * ID of task used for updating bandwidth quota for this neighbour. | ||
524 | */ | ||
525 | GNUNET_SCHEDULER_TaskIdentifier quota_update_task; | ||
526 | |||
527 | /** | ||
528 | * ID of task used for sending keep-alive pings. | ||
529 | */ | ||
530 | GNUNET_SCHEDULER_TaskIdentifier keep_alive_task; | ||
531 | |||
532 | /** | ||
533 | * ID of task used for cleaning up dead neighbour entries. | ||
534 | */ | ||
535 | GNUNET_SCHEDULER_TaskIdentifier dead_clean_task; | ||
536 | |||
537 | /** | ||
538 | * At what time did we generate our encryption key? | ||
539 | */ | ||
540 | struct GNUNET_TIME_Absolute encrypt_key_created; | ||
541 | |||
542 | /** | ||
543 | * At what time did the other peer generate the decryption key? | ||
544 | */ | ||
545 | struct GNUNET_TIME_Absolute decrypt_key_created; | ||
546 | |||
547 | /** | ||
548 | * At what time did we initially establish (as in, complete session | ||
549 | * key handshake) this connection? Should be zero if status != KEY_CONFIRMED. | ||
550 | */ | ||
551 | struct GNUNET_TIME_Absolute time_established; | ||
552 | |||
553 | /** | ||
554 | * At what time did we last receive an encrypted message from the | ||
555 | * other peer? Should be zero if status != KEY_CONFIRMED. | ||
556 | */ | ||
557 | struct GNUNET_TIME_Absolute last_activity; | ||
558 | |||
559 | /** | ||
560 | * At what frequency are we currently re-trying SET_KEY messages? | ||
561 | */ | ||
562 | struct GNUNET_TIME_Relative set_key_retry_frequency; | ||
563 | |||
564 | /** | ||
565 | * Tracking bandwidth for sending to this peer. | ||
566 | */ | ||
567 | struct GNUNET_BANDWIDTH_Tracker available_send_window; | ||
568 | |||
569 | /** | ||
570 | * How valueable were the messages of this peer recently? | ||
571 | */ | ||
572 | unsigned long long current_preference; | ||
573 | |||
574 | /** | ||
575 | * Number of entries in 'ats'. | ||
576 | */ | ||
577 | unsigned int ats_count; | ||
578 | |||
579 | /** | ||
580 | * Bit map indicating which of the 32 sequence numbers before the last | ||
581 | * were received (good for accepting out-of-order packets and | ||
582 | * estimating reliability of the connection) | ||
583 | */ | ||
584 | unsigned int last_packets_bitmap; | ||
585 | |||
586 | /** | ||
587 | * last sequence number received on this connection (highest) | ||
588 | */ | ||
589 | uint32_t last_sequence_number_received; | ||
590 | |||
591 | /** | ||
592 | * last sequence number transmitted | ||
593 | */ | ||
594 | uint32_t last_sequence_number_sent; | ||
595 | |||
596 | /** | ||
597 | * Available bandwidth in for this peer (current target). | ||
598 | */ | ||
599 | struct GNUNET_BANDWIDTH_Value32NBO bw_in; | ||
600 | |||
601 | /** | ||
602 | * Available bandwidth out for this peer (current target). | ||
603 | */ | ||
604 | struct GNUNET_BANDWIDTH_Value32NBO bw_out; | ||
605 | |||
606 | /** | ||
607 | * Internal bandwidth limit set for this peer (initially typically | ||
608 | * set to "-1"). Actual "bw_out" is MIN of | ||
609 | * "bpm_out_internal_limit" and "bw_out_external_limit". | ||
610 | */ | ||
611 | struct GNUNET_BANDWIDTH_Value32NBO bw_out_internal_limit; | ||
612 | |||
613 | /** | ||
614 | * External bandwidth limit set for this peer by the | ||
615 | * peer that we are communicating with. "bw_out" is MIN of | ||
616 | * "bw_out_internal_limit" and "bw_out_external_limit". | ||
617 | */ | ||
618 | struct GNUNET_BANDWIDTH_Value32NBO bw_out_external_limit; | ||
619 | |||
620 | /** | ||
621 | * What was our PING challenge number (for this peer)? | ||
622 | */ | ||
623 | uint32_t ping_challenge; | ||
624 | |||
625 | /** | ||
626 | * What is our connection status? | ||
627 | */ | ||
628 | enum PeerStateMachine status; | ||
629 | |||
630 | /** | ||
631 | * Are we currently connected to this neighbour? | ||
632 | */ | ||
633 | int is_connected; | ||
634 | |||
635 | }; | ||
636 | |||
637 | |||
638 | /** | ||
639 | * Data structure for each client connected to the core service. | ||
640 | */ | ||
641 | struct Client | ||
642 | { | ||
643 | /** | ||
644 | * Clients are kept in a linked list. | ||
645 | */ | ||
646 | struct Client *next; | ||
647 | |||
648 | /** | ||
649 | * Handle for the client with the server API. | ||
650 | */ | ||
651 | struct GNUNET_SERVER_Client *client_handle; | ||
652 | |||
653 | /** | ||
654 | * Array of the types of messages this peer cares | ||
655 | * about (with "tcnt" entries). Allocated as part | ||
656 | * of this client struct, do not free! | ||
657 | */ | ||
658 | const uint16_t *types; | ||
659 | |||
660 | /** | ||
661 | * Map of peer identities to active transmission requests of this | ||
662 | * client to the peer (of type 'struct ClientActiveRequest'). | ||
663 | */ | ||
664 | struct GNUNET_CONTAINER_MultiHashMap *requests; | ||
665 | |||
666 | /** | ||
667 | * Options for messages this client cares about, | ||
668 | * see GNUNET_CORE_OPTION_ values. | ||
669 | */ | ||
670 | uint32_t options; | ||
671 | |||
672 | /** | ||
673 | * Number of types of incoming messages this client | ||
674 | * specifically cares about. Size of the "types" array. | ||
675 | */ | ||
676 | unsigned int tcnt; | ||
677 | |||
678 | }; | ||
679 | |||
680 | |||
681 | /** | ||
682 | * Record kept for each request for transmission issued by a | ||
683 | * client that is still pending. | ||
684 | */ | ||
685 | struct ClientActiveRequest | ||
686 | { | ||
687 | |||
688 | /** | ||
689 | * Active requests are kept in a doubly-linked list of | ||
690 | * the respective target peer. | ||
691 | */ | ||
692 | struct ClientActiveRequest *next; | ||
693 | |||
694 | /** | ||
695 | * Active requests are kept in a doubly-linked list of | ||
696 | * the respective target peer. | ||
697 | */ | ||
698 | struct ClientActiveRequest *prev; | ||
699 | |||
700 | /** | ||
701 | * Handle to the client. | ||
702 | */ | ||
703 | struct Client *client; | ||
704 | |||
705 | /** | ||
706 | * By what time would the client want to see this message out? | ||
707 | */ | ||
708 | struct GNUNET_TIME_Absolute deadline; | ||
709 | |||
710 | /** | ||
711 | * How important is this request. | ||
712 | */ | ||
713 | uint32_t priority; | ||
714 | |||
715 | /** | ||
716 | * How many more requests does this client have? | ||
717 | */ | ||
718 | uint32_t queue_size; | ||
719 | |||
720 | /** | ||
721 | * How many bytes does the client intend to send? | ||
722 | */ | ||
723 | uint16_t msize; | ||
724 | |||
725 | /** | ||
726 | * Unique request ID (in big endian). | ||
727 | */ | ||
728 | uint16_t smr_id; | ||
729 | |||
730 | }; | ||
731 | |||
732 | |||
733 | |||
734 | /** | ||
735 | * Our public key. | ||
736 | */ | ||
737 | static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key; | ||
738 | |||
739 | /** | ||
740 | * Our identity. | ||
741 | */ | ||
742 | static struct GNUNET_PeerIdentity my_identity; | ||
743 | |||
744 | /** | ||
745 | * Our private key. | ||
746 | */ | ||
747 | static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key; | ||
748 | |||
749 | /** | ||
750 | * Bitmap of message types this peer is able to handle. | ||
751 | */ | ||
752 | static uint32_t my_type_map[(UINT16_MAX + 1) / 32]; | ||
753 | |||
754 | /** | ||
755 | * Handle to peerinfo service. | ||
756 | */ | ||
757 | static struct GNUNET_PEERINFO_Handle *peerinfo; | ||
758 | |||
759 | /** | ||
760 | * Our message stream tokenizer (for encrypted payload). | ||
761 | */ | ||
762 | static struct GNUNET_SERVER_MessageStreamTokenizer *mst; | ||
763 | |||
764 | /** | ||
765 | * Our configuration. | ||
766 | */ | ||
767 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
768 | |||
769 | /** | ||
770 | * Transport service. | ||
771 | */ | ||
772 | static struct GNUNET_TRANSPORT_Handle *transport; | ||
773 | |||
774 | /** | ||
775 | * Linked list of our clients. | ||
776 | */ | ||
777 | static struct Client *clients; | ||
778 | |||
779 | /** | ||
780 | * Context for notifications we need to send to our clients. | ||
781 | */ | ||
782 | static struct GNUNET_SERVER_NotificationContext *notifier; | ||
783 | |||
784 | /** | ||
785 | * Map of peer identities to 'struct Neighbour'. | ||
786 | */ | ||
787 | static struct GNUNET_CONTAINER_MultiHashMap *neighbours; | ||
788 | |||
789 | /** | ||
790 | * Neighbour entry for "this" peer. | ||
791 | */ | ||
792 | static struct Neighbour self; | ||
793 | |||
794 | /** | ||
795 | * For creating statistics. | ||
796 | */ | ||
797 | static struct GNUNET_STATISTICS_Handle *stats; | ||
798 | |||
799 | /** | ||
800 | * Sum of all preferences among all neighbours. | ||
801 | */ | ||
802 | static unsigned long long preference_sum; | ||
803 | |||
804 | /** | ||
805 | * How much inbound bandwidth are we supposed to be using per second? | ||
806 | */ | ||
807 | static unsigned long long bandwidth_target_in_bps; | ||
808 | |||
809 | /** | ||
810 | * How much outbound bandwidth are we supposed to be using per second? | ||
811 | */ | ||
812 | static unsigned long long bandwidth_target_out_bps; | ||
813 | |||
814 | /** | ||
815 | * Derive an authentication key from "set key" information | ||
816 | */ | ||
817 | static void | ||
818 | derive_auth_key (struct GNUNET_CRYPTO_AuthKey *akey, | ||
819 | const struct GNUNET_CRYPTO_AesSessionKey *skey, uint32_t seed, | ||
820 | struct GNUNET_TIME_Absolute creation_time) | ||
821 | { | ||
822 | static const char ctx[] = "authentication key"; | ||
823 | struct GNUNET_TIME_AbsoluteNBO ctbe; | ||
824 | |||
825 | |||
826 | ctbe = GNUNET_TIME_absolute_hton (creation_time); | ||
827 | GNUNET_CRYPTO_hmac_derive_key (akey, skey, &seed, sizeof (seed), &skey->key, | ||
828 | sizeof (skey->key), &ctbe, sizeof (ctbe), ctx, | ||
829 | sizeof (ctx), NULL); | ||
830 | } | ||
831 | |||
832 | |||
833 | /** | ||
834 | * Derive an IV from packet information | ||
835 | */ | ||
836 | static void | ||
837 | derive_iv (struct GNUNET_CRYPTO_AesInitializationVector *iv, | ||
838 | const struct GNUNET_CRYPTO_AesSessionKey *skey, uint32_t seed, | ||
839 | const struct GNUNET_PeerIdentity *identity) | ||
840 | { | ||
841 | static const char ctx[] = "initialization vector"; | ||
842 | |||
843 | GNUNET_CRYPTO_aes_derive_iv (iv, skey, &seed, sizeof (seed), | ||
844 | &identity->hashPubKey.bits, | ||
845 | sizeof (identity->hashPubKey.bits), ctx, | ||
846 | sizeof (ctx), NULL); | ||
847 | } | ||
848 | |||
849 | /** | ||
850 | * Derive an IV from pong packet information | ||
851 | */ | ||
852 | static void | ||
853 | derive_pong_iv (struct GNUNET_CRYPTO_AesInitializationVector *iv, | ||
854 | const struct GNUNET_CRYPTO_AesSessionKey *skey, uint32_t seed, | ||
855 | uint32_t challenge, const struct GNUNET_PeerIdentity *identity) | ||
856 | { | ||
857 | static const char ctx[] = "pong initialization vector"; | ||
858 | |||
859 | GNUNET_CRYPTO_aes_derive_iv (iv, skey, &seed, sizeof (seed), | ||
860 | &identity->hashPubKey.bits, | ||
861 | sizeof (identity->hashPubKey.bits), &challenge, | ||
862 | sizeof (challenge), ctx, sizeof (ctx), NULL); | ||
863 | } | ||
864 | |||
865 | |||
866 | /** | ||
867 | * At what time should the connection to the given neighbour | ||
868 | * time out (given no further activity?) | ||
869 | * | ||
870 | * @param n neighbour in question | ||
871 | * @return absolute timeout | ||
872 | */ | ||
873 | static struct GNUNET_TIME_Absolute | ||
874 | get_neighbour_timeout (struct Neighbour *n) | ||
875 | { | ||
876 | return GNUNET_TIME_absolute_add (n->last_activity, | ||
877 | GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); | ||
878 | } | ||
879 | |||
880 | |||
881 | /** | ||
882 | * Find the entry for the given neighbour. | ||
883 | * | ||
884 | * @param peer identity of the neighbour | ||
885 | * @return NULL if we are not connected, otherwise the | ||
886 | * neighbour's entry. | ||
887 | */ | ||
888 | static struct Neighbour * | ||
889 | find_neighbour (const struct GNUNET_PeerIdentity *peer) | ||
890 | { | ||
891 | return GNUNET_CONTAINER_multihashmap_get (neighbours, &peer->hashPubKey); | ||
892 | } | ||
893 | |||
894 | |||
895 | /** | ||
896 | * Send a message to one of our clients. | ||
897 | * | ||
898 | * @param client target for the message | ||
899 | * @param msg message to transmit | ||
900 | * @param can_drop could this message be dropped if the | ||
901 | * client's queue is getting too large? | ||
902 | */ | ||
903 | static void | ||
904 | send_to_client (struct Client *client, const struct GNUNET_MessageHeader *msg, | ||
905 | int can_drop) | ||
906 | { | ||
907 | #if DEBUG_CORE_CLIENT | ||
908 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
909 | "Preparing to send %u bytes of message of type %u to client.\n", | ||
910 | (unsigned int) ntohs (msg->size), | ||
911 | (unsigned int) ntohs (msg->type)); | ||
912 | #endif | ||
913 | GNUNET_SERVER_notification_context_unicast (notifier, client->client_handle, | ||
914 | msg, can_drop); | ||
915 | } | ||
916 | |||
917 | |||
918 | /** | ||
919 | * Send a message to all of our current clients that have | ||
920 | * the right options set. | ||
921 | * | ||
922 | * @param msg message to multicast | ||
923 | * @param can_drop can this message be discarded if the queue is too long | ||
924 | * @param options mask to use | ||
925 | */ | ||
926 | static void | ||
927 | send_to_all_clients (const struct GNUNET_MessageHeader *msg, int can_drop, | ||
928 | int options) | ||
929 | { | ||
930 | struct Client *c; | ||
931 | |||
932 | c = clients; | ||
933 | while (c != NULL) | ||
934 | { | ||
935 | if (0 != (c->options & options)) | ||
936 | { | ||
937 | #if DEBUG_CORE_CLIENT > 1 | ||
938 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
939 | "Sending message of type %u to client.\n", | ||
940 | (unsigned int) ntohs (msg->type)); | ||
941 | #endif | ||
942 | send_to_client (c, msg, can_drop); | ||
943 | } | ||
944 | c = c->next; | ||
945 | } | ||
946 | } | ||
947 | |||
948 | |||
949 | /** | ||
950 | * Function called by transport telling us that a peer | ||
951 | * changed status. | ||
952 | * | ||
953 | * @param n the peer that changed status | ||
954 | */ | ||
955 | static void | ||
956 | handle_peer_status_change (struct Neighbour *n) | ||
957 | { | ||
958 | struct PeerStatusNotifyMessage *psnm; | ||
959 | char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1]; | ||
960 | struct GNUNET_ATS_Information *ats; | ||
961 | size_t size; | ||
962 | |||
963 | if ((!n->is_connected) || (n->status != PEER_STATE_KEY_CONFIRMED)) | ||
964 | return; | ||
965 | #if DEBUG_CORE > 1 | ||
966 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%4s' changed status\n", | ||
967 | GNUNET_i2s (&n->peer)); | ||
968 | #endif | ||
969 | size = | ||
970 | sizeof (struct PeerStatusNotifyMessage) + | ||
971 | n->ats_count * sizeof (struct GNUNET_ATS_Information); | ||
972 | if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE) | ||
973 | { | ||
974 | GNUNET_break (0); | ||
975 | /* recovery strategy: throw away performance data */ | ||
976 | GNUNET_array_grow (n->ats, n->ats_count, 0); | ||
977 | size = | ||
978 | sizeof (struct PeerStatusNotifyMessage) + | ||
979 | n->ats_count * sizeof (struct GNUNET_ATS_Information); | ||
980 | } | ||
981 | psnm = (struct PeerStatusNotifyMessage *) buf; | ||
982 | psnm->header.size = htons (size); | ||
983 | psnm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_STATUS_CHANGE); | ||
984 | psnm->timeout = GNUNET_TIME_absolute_hton (get_neighbour_timeout (n)); | ||
985 | psnm->bandwidth_in = n->bw_in; | ||
986 | psnm->bandwidth_out = n->bw_out; | ||
987 | psnm->peer = n->peer; | ||
988 | psnm->ats_count = htonl (n->ats_count); | ||
989 | ats = &psnm->ats; | ||
990 | memcpy (ats, n->ats, | ||
991 | n->ats_count * sizeof (struct GNUNET_ATS_Information)); | ||
992 | ats[n->ats_count].type = htonl (0); | ||
993 | ats[n->ats_count].value = htonl (0); | ||
994 | send_to_all_clients (&psnm->header, GNUNET_YES, | ||
995 | GNUNET_CORE_OPTION_SEND_STATUS_CHANGE); | ||
996 | GNUNET_STATISTICS_update (stats, gettext_noop ("# peer status changes"), 1, | ||
997 | GNUNET_NO); | ||
998 | } | ||
999 | |||
1000 | |||
1001 | /** | ||
1002 | * Go over our message queue and if it is not too long, go | ||
1003 | * over the pending requests from clients for this | ||
1004 | * neighbour and send some clients a 'READY' notification. | ||
1005 | * | ||
1006 | * @param n which peer to process | ||
1007 | */ | ||
1008 | static void | ||
1009 | schedule_peer_messages (struct Neighbour *n) | ||
1010 | { | ||
1011 | struct SendMessageReady smr; | ||
1012 | struct ClientActiveRequest *car; | ||
1013 | struct ClientActiveRequest *pos; | ||
1014 | struct Client *c; | ||
1015 | struct MessageEntry *mqe; | ||
1016 | unsigned int queue_size; | ||
1017 | |||
1018 | /* check if neighbour queue is empty enough! */ | ||
1019 | if (n != &self) | ||
1020 | { | ||
1021 | queue_size = 0; | ||
1022 | mqe = n->messages; | ||
1023 | while (mqe != NULL) | ||
1024 | { | ||
1025 | queue_size++; | ||
1026 | mqe = mqe->next; | ||
1027 | } | ||
1028 | if (queue_size >= MAX_PEER_QUEUE_SIZE) | ||
1029 | { | ||
1030 | #if DEBUG_CORE_CLIENT | ||
1031 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1032 | "Not considering client transmission requests: queue full\n"); | ||
1033 | #endif | ||
1034 | return; /* queue still full */ | ||
1035 | } | ||
1036 | /* find highest priority request */ | ||
1037 | pos = n->active_client_request_head; | ||
1038 | car = NULL; | ||
1039 | while (pos != NULL) | ||
1040 | { | ||
1041 | if ((car == NULL) || (pos->priority > car->priority)) | ||
1042 | car = pos; | ||
1043 | pos = pos->next; | ||
1044 | } | ||
1045 | } | ||
1046 | else | ||
1047 | { | ||
1048 | car = n->active_client_request_head; | ||
1049 | } | ||
1050 | if (car == NULL) | ||
1051 | return; /* no pending requests */ | ||
1052 | #if DEBUG_CORE_CLIENT | ||
1053 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1054 | "Permitting client transmission request to `%s'\n", | ||
1055 | GNUNET_i2s (&n->peer)); | ||
1056 | #endif | ||
1057 | c = car->client; | ||
1058 | GNUNET_CONTAINER_DLL_remove (n->active_client_request_head, | ||
1059 | n->active_client_request_tail, car); | ||
1060 | GNUNET_assert (GNUNET_YES == | ||
1061 | GNUNET_CONTAINER_multihashmap_remove (c->requests, | ||
1062 | &n->peer.hashPubKey, | ||
1063 | car)); | ||
1064 | smr.header.size = htons (sizeof (struct SendMessageReady)); | ||
1065 | smr.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_SEND_READY); | ||
1066 | smr.size = htons (car->msize); | ||
1067 | smr.smr_id = car->smr_id; | ||
1068 | smr.peer = n->peer; | ||
1069 | send_to_client (c, &smr.header, GNUNET_NO); | ||
1070 | GNUNET_free (car); | ||
1071 | } | ||
1072 | |||
1073 | |||
1074 | /** | ||
1075 | * Compute a type map message for this peer. | ||
1076 | * | ||
1077 | * @return this peers current type map message. | ||
1078 | */ | ||
1079 | static struct GNUNET_MessageHeader * | ||
1080 | compute_type_map_message () | ||
1081 | { | ||
1082 | char *tmp; | ||
1083 | uLongf dlen; | ||
1084 | struct GNUNET_MessageHeader *hdr; | ||
1085 | |||
1086 | #ifdef compressBound | ||
1087 | dlen = compressBound (sizeof (my_type_map)); | ||
1088 | #else | ||
1089 | dlen = sizeof (my_type_map) + (sizeof (my_type_map) / 100) + 20; | ||
1090 | /* documentation says 100.1% oldSize + 12 bytes, but we | ||
1091 | * should be able to overshoot by more to be safe */ | ||
1092 | #endif | ||
1093 | hdr = GNUNET_malloc (dlen + sizeof (struct GNUNET_MessageHeader)); | ||
1094 | hdr->size = htons ((uint16_t) dlen + sizeof (struct GNUNET_MessageHeader)); | ||
1095 | tmp = (char *) &hdr[1]; | ||
1096 | if ((Z_OK != | ||
1097 | compress2 ((Bytef *) tmp, &dlen, (const Bytef *) my_type_map, | ||
1098 | sizeof (my_type_map), 9)) || (dlen >= sizeof (my_type_map))) | ||
1099 | { | ||
1100 | dlen = sizeof (my_type_map); | ||
1101 | memcpy (tmp, my_type_map, sizeof (my_type_map)); | ||
1102 | hdr->type = htons (GNUNET_MESSAGE_TYPE_CORE_BINARY_TYPE_MAP); | ||
1103 | } | ||
1104 | else | ||
1105 | { | ||
1106 | hdr->type = htons (GNUNET_MESSAGE_TYPE_CORE_COMPRESSED_TYPE_MAP); | ||
1107 | } | ||
1108 | return hdr; | ||
1109 | } | ||
1110 | |||
1111 | |||
1112 | /** | ||
1113 | * Send a type map message to the neighbour. | ||
1114 | * | ||
1115 | * @param cls the type map message | ||
1116 | * @param key neighbour's identity | ||
1117 | * @param value 'struct Neighbour' of the target | ||
1118 | * @return always GNUNET_OK | ||
1119 | */ | ||
1120 | static int | ||
1121 | send_type_map_to_neighbour (void *cls, const GNUNET_HashCode * key, void *value) | ||
1122 | { | ||
1123 | struct GNUNET_MessageHeader *hdr = cls; | ||
1124 | struct Neighbour *n = value; | ||
1125 | struct MessageEntry *m; | ||
1126 | uint16_t size; | ||
1127 | |||
1128 | if (n == &self) | ||
1129 | return GNUNET_OK; | ||
1130 | size = ntohs (hdr->size); | ||
1131 | m = GNUNET_malloc (sizeof (struct MessageEntry) + size); | ||
1132 | memcpy (&m[1], hdr, size); | ||
1133 | m->deadline = GNUNET_TIME_UNIT_FOREVER_ABS; | ||
1134 | m->slack_deadline = GNUNET_TIME_UNIT_FOREVER_ABS; | ||
1135 | m->priority = UINT_MAX; | ||
1136 | m->sender_status = n->status; | ||
1137 | m->size = size; | ||
1138 | m->next = n->messages; | ||
1139 | n->messages = m; | ||
1140 | return GNUNET_OK; | ||
1141 | } | ||
1142 | |||
1143 | |||
1144 | |||
1145 | /** | ||
1146 | * Send my type map to all connected peers (it got changed). | ||
1147 | */ | ||
1148 | static void | ||
1149 | broadcast_my_type_map () | ||
1150 | { | ||
1151 | struct GNUNET_MessageHeader *hdr; | ||
1152 | |||
1153 | if (NULL == neighbours) | ||
1154 | return; | ||
1155 | hdr = compute_type_map_message (); | ||
1156 | GNUNET_CONTAINER_multihashmap_iterate (neighbours, | ||
1157 | &send_type_map_to_neighbour, hdr); | ||
1158 | GNUNET_free (hdr); | ||
1159 | } | ||
1160 | |||
1161 | |||
1162 | /** | ||
1163 | * Handle CORE_SEND_REQUEST message. | ||
1164 | */ | ||
1165 | static void | ||
1166 | handle_client_send_request (void *cls, struct GNUNET_SERVER_Client *client, | ||
1167 | const struct GNUNET_MessageHeader *message) | ||
1168 | { | ||
1169 | const struct SendMessageRequest *req; | ||
1170 | struct Neighbour *n; | ||
1171 | struct Client *c; | ||
1172 | struct ClientActiveRequest *car; | ||
1173 | |||
1174 | req = (const struct SendMessageRequest *) message; | ||
1175 | if (0 == | ||
1176 | memcmp (&req->peer, &my_identity, sizeof (struct GNUNET_PeerIdentity))) | ||
1177 | n = &self; | ||
1178 | else | ||
1179 | n = find_neighbour (&req->peer); | ||
1180 | if ((n == NULL) || (GNUNET_YES != n->is_connected) || | ||
1181 | (n->status != PEER_STATE_KEY_CONFIRMED)) | ||
1182 | { | ||
1183 | /* neighbour must have disconnected since request was issued, | ||
1184 | * ignore (client will realize it once it processes the | ||
1185 | * disconnect notification) */ | ||
1186 | #if DEBUG_CORE_CLIENT | ||
1187 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1188 | "Dropped client request for transmission (am disconnected)\n"); | ||
1189 | #endif | ||
1190 | GNUNET_STATISTICS_update (stats, | ||
1191 | gettext_noop | ||
1192 | ("# send requests dropped (disconnected)"), 1, | ||
1193 | GNUNET_NO); | ||
1194 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
1195 | return; | ||
1196 | } | ||
1197 | c = clients; | ||
1198 | while ((c != NULL) && (c->client_handle != client)) | ||
1199 | c = c->next; | ||
1200 | if (c == NULL) | ||
1201 | { | ||
1202 | /* client did not send INIT first! */ | ||
1203 | GNUNET_break (0); | ||
1204 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
1205 | return; | ||
1206 | } | ||
1207 | if (c->requests == NULL) | ||
1208 | c->requests = GNUNET_CONTAINER_multihashmap_create (16); | ||
1209 | #if DEBUG_CORE_CLIENT | ||
1210 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1211 | "Received client transmission request. queueing\n"); | ||
1212 | #endif | ||
1213 | car = GNUNET_CONTAINER_multihashmap_get (c->requests, &req->peer.hashPubKey); | ||
1214 | if (car == NULL) | ||
1215 | { | ||
1216 | /* create new entry */ | ||
1217 | car = GNUNET_malloc (sizeof (struct ClientActiveRequest)); | ||
1218 | GNUNET_assert (GNUNET_OK == | ||
1219 | GNUNET_CONTAINER_multihashmap_put (c->requests, | ||
1220 | &req->peer.hashPubKey, | ||
1221 | car, | ||
1222 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)); | ||
1223 | GNUNET_CONTAINER_DLL_insert (n->active_client_request_head, | ||
1224 | n->active_client_request_tail, car); | ||
1225 | car->client = c; | ||
1226 | } | ||
1227 | car->deadline = GNUNET_TIME_absolute_ntoh (req->deadline); | ||
1228 | car->priority = ntohl (req->priority); | ||
1229 | car->queue_size = ntohl (req->queue_size); | ||
1230 | car->msize = ntohs (req->size); | ||
1231 | car->smr_id = req->smr_id; | ||
1232 | schedule_peer_messages (n); | ||
1233 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
1234 | } | ||
1235 | |||
1236 | |||
1237 | /** | ||
1238 | * Notify client about an existing connection to one of our neighbours. | ||
1239 | */ | ||
1240 | static int | ||
1241 | notify_client_about_neighbour (void *cls, const GNUNET_HashCode * key, | ||
1242 | void *value) | ||
1243 | { | ||
1244 | struct Client *c = cls; | ||
1245 | struct Neighbour *n = value; | ||
1246 | size_t size; | ||
1247 | char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1]; | ||
1248 | struct GNUNET_ATS_Information *ats; | ||
1249 | struct ConnectNotifyMessage *cnm; | ||
1250 | |||
1251 | size = | ||
1252 | sizeof (struct ConnectNotifyMessage) + | ||
1253 | (n->ats_count) * sizeof (struct GNUNET_ATS_Information); | ||
1254 | if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE) | ||
1255 | { | ||
1256 | GNUNET_break (0); | ||
1257 | /* recovery strategy: throw away performance data */ | ||
1258 | GNUNET_array_grow (n->ats, n->ats_count, 0); | ||
1259 | size = | ||
1260 | sizeof (struct ConnectNotifyMessage) + | ||
1261 | (n->ats_count) * sizeof (struct GNUNET_ATS_Information); | ||
1262 | } | ||
1263 | cnm = (struct ConnectNotifyMessage *) buf; | ||
1264 | cnm->header.size = htons (size); | ||
1265 | cnm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT); | ||
1266 | cnm->ats_count = htonl (n->ats_count); | ||
1267 | ats = &cnm->ats; | ||
1268 | memcpy (ats, n->ats, | ||
1269 | sizeof (struct GNUNET_ATS_Information) * n->ats_count); | ||
1270 | ats[n->ats_count].type = htonl (GNUNET_ATS_ARRAY_TERMINATOR); | ||
1271 | ats[n->ats_count].value = htonl (0); | ||
1272 | if (n->status == PEER_STATE_KEY_CONFIRMED) | ||
1273 | { | ||
1274 | #if DEBUG_CORE_CLIENT | ||
1275 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message to client.\n", | ||
1276 | "NOTIFY_CONNECT"); | ||
1277 | #endif | ||
1278 | cnm->peer = n->peer; | ||
1279 | send_to_client (c, &cnm->header, GNUNET_NO); | ||
1280 | } | ||
1281 | return GNUNET_OK; | ||
1282 | } | ||
1283 | |||
1284 | |||
1285 | |||
1286 | /** | ||
1287 | * Handle CORE_INIT request. | ||
1288 | */ | ||
1289 | static void | ||
1290 | handle_client_init (void *cls, struct GNUNET_SERVER_Client *client, | ||
1291 | const struct GNUNET_MessageHeader *message) | ||
1292 | { | ||
1293 | const struct InitMessage *im; | ||
1294 | struct InitReplyMessage irm; | ||
1295 | struct Client *c; | ||
1296 | uint16_t msize; | ||
1297 | const uint16_t *types; | ||
1298 | uint16_t *wtypes; | ||
1299 | unsigned int i; | ||
1300 | |||
1301 | #if DEBUG_CORE_CLIENT | ||
1302 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1303 | "Client connecting to core service with `%s' message\n", "INIT"); | ||
1304 | #endif | ||
1305 | /* check that we don't have an entry already */ | ||
1306 | c = clients; | ||
1307 | while (c != NULL) | ||
1308 | { | ||
1309 | if (client == c->client_handle) | ||
1310 | { | ||
1311 | GNUNET_break (0); | ||
1312 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
1313 | return; | ||
1314 | } | ||
1315 | c = c->next; | ||
1316 | } | ||
1317 | msize = ntohs (message->size); | ||
1318 | if (msize < sizeof (struct InitMessage)) | ||
1319 | { | ||
1320 | GNUNET_break (0); | ||
1321 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
1322 | return; | ||
1323 | } | ||
1324 | GNUNET_SERVER_notification_context_add (notifier, client); | ||
1325 | im = (const struct InitMessage *) message; | ||
1326 | types = (const uint16_t *) &im[1]; | ||
1327 | msize -= sizeof (struct InitMessage); | ||
1328 | c = GNUNET_malloc (sizeof (struct Client) + msize); | ||
1329 | c->client_handle = client; | ||
1330 | c->next = clients; | ||
1331 | clients = c; | ||
1332 | c->tcnt = msize / sizeof (uint16_t); | ||
1333 | c->types = (const uint16_t *) &c[1]; | ||
1334 | wtypes = (uint16_t *) & c[1]; | ||
1335 | for (i = 0; i < c->tcnt; i++) | ||
1336 | { | ||
1337 | wtypes[i] = ntohs (types[i]); | ||
1338 | my_type_map[wtypes[i] / 32] |= (1 << (wtypes[i] % 32)); | ||
1339 | } | ||
1340 | if (c->tcnt > 0) | ||
1341 | broadcast_my_type_map (); | ||
1342 | c->options = ntohl (im->options); | ||
1343 | #if DEBUG_CORE_CLIENT | ||
1344 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1345 | "Client %p is interested in %u message types\n", c, | ||
1346 | (unsigned int) c->tcnt); | ||
1347 | #endif | ||
1348 | /* send init reply message */ | ||
1349 | irm.header.size = htons (sizeof (struct InitReplyMessage)); | ||
1350 | irm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_INIT_REPLY); | ||
1351 | irm.reserved = htonl (0); | ||
1352 | irm.my_identity = my_identity; | ||
1353 | #if DEBUG_CORE_CLIENT | ||
1354 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message to client.\n", | ||
1355 | "INIT_REPLY"); | ||
1356 | #endif | ||
1357 | send_to_client (c, &irm.header, GNUNET_NO); | ||
1358 | if (0 != (c->options & GNUNET_CORE_OPTION_SEND_CONNECT)) | ||
1359 | { | ||
1360 | /* notify new client about existing neighbours */ | ||
1361 | GNUNET_CONTAINER_multihashmap_iterate (neighbours, | ||
1362 | ¬ify_client_about_neighbour, c); | ||
1363 | } | ||
1364 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
1365 | } | ||
1366 | |||
1367 | |||
1368 | /** | ||
1369 | * Free client request records. | ||
1370 | * | ||
1371 | * @param cls NULL | ||
1372 | * @param key identity of peer for which this is an active request | ||
1373 | * @param value the 'struct ClientActiveRequest' to free | ||
1374 | * @return GNUNET_YES (continue iteration) | ||
1375 | */ | ||
1376 | static int | ||
1377 | destroy_active_client_request (void *cls, const GNUNET_HashCode * key, | ||
1378 | void *value) | ||
1379 | { | ||
1380 | struct ClientActiveRequest *car = value; | ||
1381 | struct Neighbour *n; | ||
1382 | struct GNUNET_PeerIdentity peer; | ||
1383 | |||
1384 | peer.hashPubKey = *key; | ||
1385 | n = find_neighbour (&peer); | ||
1386 | GNUNET_assert (NULL != n); | ||
1387 | GNUNET_CONTAINER_DLL_remove (n->active_client_request_head, | ||
1388 | n->active_client_request_tail, car); | ||
1389 | GNUNET_free (car); | ||
1390 | return GNUNET_YES; | ||
1391 | } | ||
1392 | |||
1393 | |||
1394 | /** | ||
1395 | * A client disconnected, clean up. | ||
1396 | * | ||
1397 | * @param cls closure | ||
1398 | * @param client identification of the client | ||
1399 | */ | ||
1400 | static void | ||
1401 | handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client) | ||
1402 | { | ||
1403 | struct Client *pos; | ||
1404 | struct Client *prev; | ||
1405 | unsigned int i; | ||
1406 | const uint16_t *wtypes; | ||
1407 | |||
1408 | if (client == NULL) | ||
1409 | return; | ||
1410 | #if DEBUG_CORE_CLIENT | ||
1411 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1412 | "Client %p has disconnected from core service.\n", client); | ||
1413 | #endif | ||
1414 | prev = NULL; | ||
1415 | pos = clients; | ||
1416 | while (pos != NULL) | ||
1417 | { | ||
1418 | if (client == pos->client_handle) | ||
1419 | break; | ||
1420 | prev = pos; | ||
1421 | pos = pos->next; | ||
1422 | } | ||
1423 | if (pos == NULL) | ||
1424 | { | ||
1425 | /* client never sent INIT */ | ||
1426 | return; | ||
1427 | } | ||
1428 | if (prev == NULL) | ||
1429 | clients = pos->next; | ||
1430 | else | ||
1431 | prev->next = pos->next; | ||
1432 | if (pos->requests != NULL) | ||
1433 | { | ||
1434 | GNUNET_CONTAINER_multihashmap_iterate (pos->requests, | ||
1435 | &destroy_active_client_request, | ||
1436 | NULL); | ||
1437 | GNUNET_CONTAINER_multihashmap_destroy (pos->requests); | ||
1438 | } | ||
1439 | GNUNET_free (pos); | ||
1440 | |||
1441 | /* rebuild my_type_map */ | ||
1442 | memset (my_type_map, 0, sizeof (my_type_map)); | ||
1443 | for (pos = clients; NULL != pos; pos = pos->next) | ||
1444 | { | ||
1445 | wtypes = (const uint16_t *) &pos[1]; | ||
1446 | for (i = 0; i < pos->tcnt; i++) | ||
1447 | my_type_map[wtypes[i] / 32] |= (1 << (wtypes[i] % 32)); | ||
1448 | } | ||
1449 | broadcast_my_type_map (); | ||
1450 | } | ||
1451 | |||
1452 | |||
1453 | /** | ||
1454 | * Helper function for handle_client_iterate_peers. | ||
1455 | * | ||
1456 | * @param cls the 'struct GNUNET_SERVER_TransmitContext' to queue replies | ||
1457 | * @param key identity of the connected peer | ||
1458 | * @param value the 'struct Neighbour' for the peer | ||
1459 | * @return GNUNET_OK (continue to iterate) | ||
1460 | */ | ||
1461 | static int | ||
1462 | queue_connect_message (void *cls, const GNUNET_HashCode * key, void *value) | ||
1463 | { | ||
1464 | struct GNUNET_SERVER_TransmitContext *tc = cls; | ||
1465 | struct Neighbour *n = value; | ||
1466 | char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1]; | ||
1467 | struct GNUNET_ATS_Information *ats; | ||
1468 | size_t size; | ||
1469 | struct ConnectNotifyMessage *cnm; | ||
1470 | |||
1471 | cnm = (struct ConnectNotifyMessage *) buf; | ||
1472 | if (n->status != PEER_STATE_KEY_CONFIRMED) | ||
1473 | return GNUNET_OK; | ||
1474 | size = | ||
1475 | sizeof (struct ConnectNotifyMessage) + | ||
1476 | (n->ats_count) * sizeof (struct GNUNET_ATS_Information); | ||
1477 | if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE) | ||
1478 | { | ||
1479 | GNUNET_break (0); | ||
1480 | /* recovery strategy: throw away performance data */ | ||
1481 | GNUNET_array_grow (n->ats, n->ats_count, 0); | ||
1482 | size = | ||
1483 | sizeof (struct PeerStatusNotifyMessage) + | ||
1484 | n->ats_count * sizeof (struct GNUNET_ATS_Information); | ||
1485 | } | ||
1486 | cnm = (struct ConnectNotifyMessage *) buf; | ||
1487 | cnm->header.size = htons (size); | ||
1488 | cnm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT); | ||
1489 | cnm->ats_count = htonl (n->ats_count); | ||
1490 | ats = &cnm->ats; | ||
1491 | memcpy (ats, n->ats, | ||
1492 | n->ats_count * sizeof (struct GNUNET_ATS_Information)); | ||
1493 | ats[n->ats_count].type = htonl (GNUNET_ATS_ARRAY_TERMINATOR); | ||
1494 | ats[n->ats_count].value = htonl (0); | ||
1495 | #if DEBUG_CORE_CLIENT | ||
1496 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message to client.\n", | ||
1497 | "NOTIFY_CONNECT"); | ||
1498 | #endif | ||
1499 | cnm->peer = n->peer; | ||
1500 | GNUNET_SERVER_transmit_context_append_message (tc, &cnm->header); | ||
1501 | return GNUNET_OK; | ||
1502 | } | ||
1503 | |||
1504 | |||
1505 | /** | ||
1506 | * Handle CORE_ITERATE_PEERS request. | ||
1507 | * | ||
1508 | * @param cls unused | ||
1509 | * @param client client sending the iteration request | ||
1510 | * @param message iteration request message | ||
1511 | */ | ||
1512 | static void | ||
1513 | handle_client_iterate_peers (void *cls, struct GNUNET_SERVER_Client *client, | ||
1514 | const struct GNUNET_MessageHeader *message) | ||
1515 | { | ||
1516 | struct GNUNET_MessageHeader done_msg; | ||
1517 | struct GNUNET_SERVER_TransmitContext *tc; | ||
1518 | int msize; | ||
1519 | |||
1520 | /* notify new client about existing neighbours */ | ||
1521 | |||
1522 | msize = ntohs (message->size); | ||
1523 | tc = GNUNET_SERVER_transmit_context_create (client); | ||
1524 | if (msize == sizeof (struct GNUNET_MessageHeader)) | ||
1525 | GNUNET_CONTAINER_multihashmap_iterate (neighbours, &queue_connect_message, | ||
1526 | tc); | ||
1527 | else | ||
1528 | GNUNET_break (0); | ||
1529 | |||
1530 | done_msg.size = htons (sizeof (struct GNUNET_MessageHeader)); | ||
1531 | done_msg.type = htons (GNUNET_MESSAGE_TYPE_CORE_ITERATE_PEERS_END); | ||
1532 | GNUNET_SERVER_transmit_context_append_message (tc, &done_msg); | ||
1533 | GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL); | ||
1534 | } | ||
1535 | |||
1536 | |||
1537 | /** | ||
1538 | * Handle CORE_PEER_CONNECTED request. Notify client about existing neighbours. | ||
1539 | * | ||
1540 | * @param cls unused | ||
1541 | * @param client client sending the iteration request | ||
1542 | * @param message iteration request message | ||
1543 | */ | ||
1544 | static void | ||
1545 | handle_client_have_peer (void *cls, struct GNUNET_SERVER_Client *client, | ||
1546 | const struct GNUNET_MessageHeader *message) | ||
1547 | { | ||
1548 | struct GNUNET_MessageHeader done_msg; | ||
1549 | struct GNUNET_SERVER_TransmitContext *tc; | ||
1550 | struct GNUNET_PeerIdentity *peer; | ||
1551 | |||
1552 | tc = GNUNET_SERVER_transmit_context_create (client); | ||
1553 | peer = (struct GNUNET_PeerIdentity *) &message[1]; | ||
1554 | GNUNET_CONTAINER_multihashmap_get_multiple (neighbours, &peer->hashPubKey, | ||
1555 | &queue_connect_message, tc); | ||
1556 | done_msg.size = htons (sizeof (struct GNUNET_MessageHeader)); | ||
1557 | done_msg.type = htons (GNUNET_MESSAGE_TYPE_CORE_ITERATE_PEERS_END); | ||
1558 | GNUNET_SERVER_transmit_context_append_message (tc, &done_msg); | ||
1559 | GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL); | ||
1560 | } | ||
1561 | |||
1562 | |||
1563 | /** | ||
1564 | * Free the given entry for the neighbour (it has | ||
1565 | * already been removed from the list at this point). | ||
1566 | * | ||
1567 | * @param n neighbour to free | ||
1568 | */ | ||
1569 | static void | ||
1570 | free_neighbour (struct Neighbour *n) | ||
1571 | { | ||
1572 | struct MessageEntry *m; | ||
1573 | struct ClientActiveRequest *car; | ||
1574 | |||
1575 | #if DEBUG_CORE | ||
1576 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1577 | "Destroying neighbour entry for peer `%4s'\n", | ||
1578 | GNUNET_i2s (&n->peer)); | ||
1579 | #endif | ||
1580 | if (n->pitr != NULL) | ||
1581 | { | ||
1582 | GNUNET_PEERINFO_iterate_cancel (n->pitr); | ||
1583 | n->pitr = NULL; | ||
1584 | } | ||
1585 | if (n->skm != NULL) | ||
1586 | { | ||
1587 | GNUNET_free (n->skm); | ||
1588 | n->skm = NULL; | ||
1589 | } | ||
1590 | while (NULL != (m = n->messages)) | ||
1591 | { | ||
1592 | n->messages = m->next; | ||
1593 | GNUNET_free (m); | ||
1594 | } | ||
1595 | while (NULL != (m = n->encrypted_head)) | ||
1596 | { | ||
1597 | GNUNET_CONTAINER_DLL_remove (n->encrypted_head, n->encrypted_tail, m); | ||
1598 | GNUNET_free (m); | ||
1599 | } | ||
1600 | while (NULL != (car = n->active_client_request_head)) | ||
1601 | { | ||
1602 | GNUNET_CONTAINER_DLL_remove (n->active_client_request_head, | ||
1603 | n->active_client_request_tail, car); | ||
1604 | GNUNET_assert (GNUNET_YES == | ||
1605 | GNUNET_CONTAINER_multihashmap_remove (car->client->requests, | ||
1606 | &n->peer.hashPubKey, | ||
1607 | car)); | ||
1608 | GNUNET_free (car); | ||
1609 | } | ||
1610 | if (NULL != n->th) | ||
1611 | { | ||
1612 | GNUNET_TRANSPORT_notify_transmit_ready_cancel (n->th); | ||
1613 | n->th = NULL; | ||
1614 | } | ||
1615 | if (n->retry_plaintext_task != GNUNET_SCHEDULER_NO_TASK) | ||
1616 | GNUNET_SCHEDULER_cancel (n->retry_plaintext_task); | ||
1617 | if (n->retry_set_key_task != GNUNET_SCHEDULER_NO_TASK) | ||
1618 | GNUNET_SCHEDULER_cancel (n->retry_set_key_task); | ||
1619 | if (n->quota_update_task != GNUNET_SCHEDULER_NO_TASK) | ||
1620 | GNUNET_SCHEDULER_cancel (n->quota_update_task); | ||
1621 | if (n->dead_clean_task != GNUNET_SCHEDULER_NO_TASK) | ||
1622 | GNUNET_SCHEDULER_cancel (n->dead_clean_task); | ||
1623 | if (n->keep_alive_task != GNUNET_SCHEDULER_NO_TASK) | ||
1624 | GNUNET_SCHEDULER_cancel (n->keep_alive_task); | ||
1625 | if (n->status == PEER_STATE_KEY_CONFIRMED) | ||
1626 | GNUNET_STATISTICS_update (stats, gettext_noop ("# established sessions"), | ||
1627 | -1, GNUNET_NO); | ||
1628 | GNUNET_array_grow (n->ats, n->ats_count, 0); | ||
1629 | GNUNET_free_non_null (n->public_key); | ||
1630 | GNUNET_free_non_null (n->pending_ping); | ||
1631 | GNUNET_free_non_null (n->pending_pong); | ||
1632 | GNUNET_free (n); | ||
1633 | } | ||
1634 | |||
1635 | |||
1636 | /** | ||
1637 | * Check if we have encrypted messages for the specified neighbour | ||
1638 | * pending, and if so, check with the transport about sending them | ||
1639 | * out. | ||
1640 | * | ||
1641 | * @param n neighbour to check. | ||
1642 | */ | ||
1643 | static void | ||
1644 | process_encrypted_neighbour_queue (struct Neighbour *n); | ||
1645 | |||
1646 | |||
1647 | /** | ||
1648 | * Encrypt size bytes from in and write the result to out. Use the | ||
1649 | * key for outbound traffic of the given neighbour. | ||
1650 | * | ||
1651 | * @param n neighbour we are sending to | ||
1652 | * @param iv initialization vector to use | ||
1653 | * @param in ciphertext | ||
1654 | * @param out plaintext | ||
1655 | * @param size size of in/out | ||
1656 | * @return GNUNET_OK on success | ||
1657 | */ | ||
1658 | static int | ||
1659 | do_encrypt (struct Neighbour *n, | ||
1660 | const struct GNUNET_CRYPTO_AesInitializationVector *iv, | ||
1661 | const void *in, void *out, size_t size) | ||
1662 | { | ||
1663 | if (size != (uint16_t) size) | ||
1664 | { | ||
1665 | GNUNET_break (0); | ||
1666 | return GNUNET_NO; | ||
1667 | } | ||
1668 | GNUNET_assert (size == | ||
1669 | GNUNET_CRYPTO_aes_encrypt (in, (uint16_t) size, | ||
1670 | &n->encrypt_key, iv, out)); | ||
1671 | GNUNET_STATISTICS_update (stats, gettext_noop ("# bytes encrypted"), size, | ||
1672 | GNUNET_NO); | ||
1673 | #if DEBUG_CORE > 2 | ||
1674 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1675 | "Encrypted %u bytes for `%4s' using key %u, IV %u\n", | ||
1676 | (unsigned int) size, GNUNET_i2s (&n->peer), | ||
1677 | (unsigned int) n->encrypt_key.crc32, GNUNET_CRYPTO_crc32_n (iv, | ||
1678 | sizeof | ||
1679 | (iv))); | ||
1680 | #endif | ||
1681 | return GNUNET_OK; | ||
1682 | } | ||
1683 | |||
1684 | |||
1685 | /** | ||
1686 | * Consider freeing the given neighbour since we may not need | ||
1687 | * to keep it around anymore. | ||
1688 | * | ||
1689 | * @param n neighbour to consider discarding | ||
1690 | */ | ||
1691 | static void | ||
1692 | consider_free_neighbour (struct Neighbour *n); | ||
1693 | |||
1694 | |||
1695 | /** | ||
1696 | * Task triggered when a neighbour entry is about to time out | ||
1697 | * (and we should prevent this by sending a PING). | ||
1698 | * | ||
1699 | * @param cls the 'struct Neighbour' | ||
1700 | * @param tc scheduler context (not used) | ||
1701 | */ | ||
1702 | static void | ||
1703 | send_keep_alive (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
1704 | { | ||
1705 | struct Neighbour *n = cls; | ||
1706 | struct GNUNET_TIME_Relative retry; | ||
1707 | struct GNUNET_TIME_Relative left; | ||
1708 | struct MessageEntry *me; | ||
1709 | struct PingMessage pp; | ||
1710 | struct PingMessage *pm; | ||
1711 | struct GNUNET_CRYPTO_AesInitializationVector iv; | ||
1712 | |||
1713 | n->keep_alive_task = GNUNET_SCHEDULER_NO_TASK; | ||
1714 | /* send PING */ | ||
1715 | me = GNUNET_malloc (sizeof (struct MessageEntry) + | ||
1716 | sizeof (struct PingMessage)); | ||
1717 | me->deadline = GNUNET_TIME_relative_to_absolute (MAX_PING_DELAY); | ||
1718 | me->priority = PING_PRIORITY; | ||
1719 | me->size = sizeof (struct PingMessage); | ||
1720 | GNUNET_CONTAINER_DLL_insert_after (n->encrypted_head, n->encrypted_tail, | ||
1721 | n->encrypted_tail, me); | ||
1722 | pm = (struct PingMessage *) &me[1]; | ||
1723 | pm->header.size = htons (sizeof (struct PingMessage)); | ||
1724 | pm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_PING); | ||
1725 | pm->iv_seed = | ||
1726 | GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX); | ||
1727 | derive_iv (&iv, &n->encrypt_key, pm->iv_seed, &n->peer); | ||
1728 | pp.challenge = n->ping_challenge; | ||
1729 | pp.target = n->peer; | ||
1730 | #if DEBUG_HANDSHAKE | ||
1731 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1732 | "Encrypting `%s' message with challenge %u for `%4s' using key %u, IV %u (salt %u).\n", | ||
1733 | "PING", (unsigned int) n->ping_challenge, GNUNET_i2s (&n->peer), | ||
1734 | (unsigned int) n->encrypt_key.crc32, GNUNET_CRYPTO_crc32_n (&iv, | ||
1735 | sizeof | ||
1736 | (iv)), | ||
1737 | pm->iv_seed); | ||
1738 | #endif | ||
1739 | do_encrypt (n, &iv, &pp.target, &pm->target, | ||
1740 | sizeof (struct PingMessage) - ((void *) &pm->target - | ||
1741 | (void *) pm)); | ||
1742 | process_encrypted_neighbour_queue (n); | ||
1743 | /* reschedule PING job */ | ||
1744 | left = GNUNET_TIME_absolute_get_remaining (get_neighbour_timeout (n)); | ||
1745 | retry = | ||
1746 | GNUNET_TIME_relative_max (GNUNET_TIME_relative_divide (left, 2), | ||
1747 | MIN_PING_FREQUENCY); | ||
1748 | n->keep_alive_task = | ||
1749 | GNUNET_SCHEDULER_add_delayed (retry, &send_keep_alive, n); | ||
1750 | |||
1751 | } | ||
1752 | |||
1753 | |||
1754 | /** | ||
1755 | * Task triggered when a neighbour entry might have gotten stale. | ||
1756 | * | ||
1757 | * @param cls the 'struct Neighbour' | ||
1758 | * @param tc scheduler context (not used) | ||
1759 | */ | ||
1760 | static void | ||
1761 | consider_free_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
1762 | { | ||
1763 | struct Neighbour *n = cls; | ||
1764 | |||
1765 | n->dead_clean_task = GNUNET_SCHEDULER_NO_TASK; | ||
1766 | consider_free_neighbour (n); | ||
1767 | } | ||
1768 | |||
1769 | |||
1770 | /** | ||
1771 | * Consider freeing the given neighbour since we may not need | ||
1772 | * to keep it around anymore. | ||
1773 | * | ||
1774 | * @param n neighbour to consider discarding | ||
1775 | */ | ||
1776 | static void | ||
1777 | consider_free_neighbour (struct Neighbour *n) | ||
1778 | { | ||
1779 | struct GNUNET_TIME_Relative left; | ||
1780 | |||
1781 | if ((n->th != NULL) || (n->pitr != NULL) || (GNUNET_YES == n->is_connected)) | ||
1782 | return; /* no chance */ | ||
1783 | |||
1784 | left = GNUNET_TIME_absolute_get_remaining (get_neighbour_timeout (n)); | ||
1785 | if (left.rel_value > 0) | ||
1786 | { | ||
1787 | if (n->dead_clean_task != GNUNET_SCHEDULER_NO_TASK) | ||
1788 | GNUNET_SCHEDULER_cancel (n->dead_clean_task); | ||
1789 | n->dead_clean_task = | ||
1790 | GNUNET_SCHEDULER_add_delayed (left, &consider_free_task, n); | ||
1791 | return; | ||
1792 | } | ||
1793 | /* actually free the neighbour... */ | ||
1794 | GNUNET_assert (GNUNET_YES == | ||
1795 | GNUNET_CONTAINER_multihashmap_remove (neighbours, | ||
1796 | &n->peer.hashPubKey, n)); | ||
1797 | GNUNET_STATISTICS_set (stats, gettext_noop ("# neighbour entries allocated"), | ||
1798 | GNUNET_CONTAINER_multihashmap_size (neighbours), | ||
1799 | GNUNET_NO); | ||
1800 | free_neighbour (n); | ||
1801 | } | ||
1802 | |||
1803 | |||
1804 | /** | ||
1805 | * Function called when the transport service is ready to | ||
1806 | * receive an encrypted message for the respective peer | ||
1807 | * | ||
1808 | * @param cls neighbour to use message from | ||
1809 | * @param size number of bytes we can transmit | ||
1810 | * @param buf where to copy the message | ||
1811 | * @return number of bytes transmitted | ||
1812 | */ | ||
1813 | static size_t | ||
1814 | notify_encrypted_transmit_ready (void *cls, size_t size, void *buf) | ||
1815 | { | ||
1816 | struct Neighbour *n = cls; | ||
1817 | struct MessageEntry *m; | ||
1818 | size_t ret; | ||
1819 | char *cbuf; | ||
1820 | |||
1821 | n->th = NULL; | ||
1822 | m = n->encrypted_head; | ||
1823 | if (m == NULL) | ||
1824 | { | ||
1825 | #if DEBUG_CORE | ||
1826 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1827 | "Encrypted message queue empty, no messages added to buffer for `%4s'\n", | ||
1828 | GNUNET_i2s (&n->peer)); | ||
1829 | #endif | ||
1830 | return 0; | ||
1831 | } | ||
1832 | GNUNET_CONTAINER_DLL_remove (n->encrypted_head, n->encrypted_tail, m); | ||
1833 | ret = 0; | ||
1834 | cbuf = buf; | ||
1835 | if (buf != NULL) | ||
1836 | { | ||
1837 | GNUNET_assert (size >= m->size); | ||
1838 | memcpy (cbuf, &m[1], m->size); | ||
1839 | ret = m->size; | ||
1840 | GNUNET_BANDWIDTH_tracker_consume (&n->available_send_window, m->size); | ||
1841 | #if DEBUG_CORE | ||
1842 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1843 | "Copied message of type %u and size %u into transport buffer for `%4s'\n", | ||
1844 | (unsigned int) | ||
1845 | ntohs (((struct GNUNET_MessageHeader *) &m[1])->type), | ||
1846 | (unsigned int) ret, GNUNET_i2s (&n->peer)); | ||
1847 | #endif | ||
1848 | process_encrypted_neighbour_queue (n); | ||
1849 | } | ||
1850 | else | ||
1851 | { | ||
1852 | #if DEBUG_CORE | ||
1853 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1854 | "Transmission of message of type %u and size %u failed\n", | ||
1855 | (unsigned int) | ||
1856 | ntohs (((struct GNUNET_MessageHeader *) &m[1])->type), | ||
1857 | (unsigned int) m->size); | ||
1858 | #endif | ||
1859 | } | ||
1860 | GNUNET_free (m); | ||
1861 | consider_free_neighbour (n); | ||
1862 | GNUNET_STATISTICS_update (stats, | ||
1863 | gettext_noop | ||
1864 | ("# encrypted bytes given to transport"), ret, | ||
1865 | GNUNET_NO); | ||
1866 | return ret; | ||
1867 | } | ||
1868 | |||
1869 | |||
1870 | /** | ||
1871 | * Check if we have plaintext messages for the specified neighbour | ||
1872 | * pending, and if so, consider batching and encrypting them (and | ||
1873 | * then trigger processing of the encrypted queue if needed). | ||
1874 | * | ||
1875 | * @param n neighbour to check. | ||
1876 | */ | ||
1877 | static void | ||
1878 | process_plaintext_neighbour_queue (struct Neighbour *n); | ||
1879 | |||
1880 | |||
1881 | /** | ||
1882 | * Check if we have encrypted messages for the specified neighbour | ||
1883 | * pending, and if so, check with the transport about sending them | ||
1884 | * out. | ||
1885 | * | ||
1886 | * @param n neighbour to check. | ||
1887 | */ | ||
1888 | static void | ||
1889 | process_encrypted_neighbour_queue (struct Neighbour *n) | ||
1890 | { | ||
1891 | struct MessageEntry *m; | ||
1892 | |||
1893 | if (n->th != NULL) | ||
1894 | return; /* request already pending */ | ||
1895 | if (GNUNET_YES != n->is_connected) | ||
1896 | { | ||
1897 | GNUNET_break (0); | ||
1898 | return; | ||
1899 | } | ||
1900 | m = n->encrypted_head; | ||
1901 | if (m == NULL) | ||
1902 | { | ||
1903 | /* encrypted queue empty, try plaintext instead */ | ||
1904 | process_plaintext_neighbour_queue (n); | ||
1905 | return; | ||
1906 | } | ||
1907 | #if DEBUG_CORE > 1 | ||
1908 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1909 | "Asking transport for transmission of %u bytes to `%4s' in next %llu ms\n", | ||
1910 | (unsigned int) m->size, GNUNET_i2s (&n->peer), | ||
1911 | (unsigned long long) | ||
1912 | GNUNET_TIME_absolute_get_remaining (m->deadline).rel_value); | ||
1913 | #endif | ||
1914 | n->th = | ||
1915 | GNUNET_TRANSPORT_notify_transmit_ready (transport, &n->peer, m->size, | ||
1916 | m->priority, | ||
1917 | GNUNET_TIME_absolute_get_remaining | ||
1918 | (m->deadline), | ||
1919 | ¬ify_encrypted_transmit_ready, | ||
1920 | n); | ||
1921 | if (n->th == NULL) | ||
1922 | { | ||
1923 | /* message request too large or duplicate request */ | ||
1924 | GNUNET_break (0); | ||
1925 | /* discard encrypted message */ | ||
1926 | GNUNET_CONTAINER_DLL_remove (n->encrypted_head, n->encrypted_tail, m); | ||
1927 | GNUNET_free (m); | ||
1928 | process_encrypted_neighbour_queue (n); | ||
1929 | } | ||
1930 | } | ||
1931 | |||
1932 | |||
1933 | /** | ||
1934 | * Decrypt size bytes from in and write the result to out. Use the | ||
1935 | * key for inbound traffic of the given neighbour. This function does | ||
1936 | * NOT do any integrity-checks on the result. | ||
1937 | * | ||
1938 | * @param n neighbour we are receiving from | ||
1939 | * @param iv initialization vector to use | ||
1940 | * @param in ciphertext | ||
1941 | * @param out plaintext | ||
1942 | * @param size size of in/out | ||
1943 | * @return GNUNET_OK on success | ||
1944 | */ | ||
1945 | static int | ||
1946 | do_decrypt (struct Neighbour *n, | ||
1947 | const struct GNUNET_CRYPTO_AesInitializationVector *iv, | ||
1948 | const void *in, void *out, size_t size) | ||
1949 | { | ||
1950 | if (size != (uint16_t) size) | ||
1951 | { | ||
1952 | GNUNET_break (0); | ||
1953 | return GNUNET_NO; | ||
1954 | } | ||
1955 | if ((n->status != PEER_STATE_KEY_RECEIVED) && | ||
1956 | (n->status != PEER_STATE_KEY_CONFIRMED)) | ||
1957 | { | ||
1958 | GNUNET_break_op (0); | ||
1959 | return GNUNET_SYSERR; | ||
1960 | } | ||
1961 | if (size != | ||
1962 | GNUNET_CRYPTO_aes_decrypt (in, (uint16_t) size, &n->decrypt_key, iv, out)) | ||
1963 | { | ||
1964 | GNUNET_break (0); | ||
1965 | return GNUNET_SYSERR; | ||
1966 | } | ||
1967 | GNUNET_STATISTICS_update (stats, gettext_noop ("# bytes decrypted"), size, | ||
1968 | GNUNET_NO); | ||
1969 | #if DEBUG_CORE > 1 | ||
1970 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1971 | "Decrypted %u bytes from `%4s' using key %u, IV %u\n", | ||
1972 | (unsigned int) size, GNUNET_i2s (&n->peer), | ||
1973 | (unsigned int) n->decrypt_key.crc32, GNUNET_CRYPTO_crc32_n (iv, | ||
1974 | sizeof | ||
1975 | (*iv))); | ||
1976 | #endif | ||
1977 | return GNUNET_OK; | ||
1978 | } | ||
1979 | |||
1980 | |||
1981 | /** | ||
1982 | * Select messages for transmission. This heuristic uses a combination | ||
1983 | * of earliest deadline first (EDF) scheduling (with bounded horizon) | ||
1984 | * and priority-based discard (in case no feasible schedule exist) and | ||
1985 | * speculative optimization (defer any kind of transmission until | ||
1986 | * we either create a batch of significant size, 25% of max, or until | ||
1987 | * we are close to a deadline). Furthermore, when scheduling the | ||
1988 | * heuristic also packs as many messages into the batch as possible, | ||
1989 | * starting with those with the earliest deadline. Yes, this is fun. | ||
1990 | * | ||
1991 | * @param n neighbour to select messages from | ||
1992 | * @param size number of bytes to select for transmission | ||
1993 | * @param retry_time set to the time when we should try again | ||
1994 | * (only valid if this function returns zero) | ||
1995 | * @return number of bytes selected, or 0 if we decided to | ||
1996 | * defer scheduling overall; in that case, retry_time is set. | ||
1997 | */ | ||
1998 | static size_t | ||
1999 | select_messages (struct Neighbour *n, size_t size, | ||
2000 | struct GNUNET_TIME_Relative *retry_time) | ||
2001 | { | ||
2002 | struct MessageEntry *pos; | ||
2003 | struct MessageEntry *min; | ||
2004 | struct MessageEntry *last; | ||
2005 | unsigned int min_prio; | ||
2006 | struct GNUNET_TIME_Absolute t; | ||
2007 | struct GNUNET_TIME_Absolute now; | ||
2008 | struct GNUNET_TIME_Relative delta; | ||
2009 | uint64_t avail; | ||
2010 | struct GNUNET_TIME_Relative slack; /* how long could we wait before missing deadlines? */ | ||
2011 | size_t off; | ||
2012 | uint64_t tsize; | ||
2013 | unsigned int queue_size; | ||
2014 | int discard_low_prio; | ||
2015 | |||
2016 | GNUNET_assert (NULL != n->messages); | ||
2017 | now = GNUNET_TIME_absolute_get (); | ||
2018 | /* last entry in linked list of messages processed */ | ||
2019 | last = NULL; | ||
2020 | /* should we remove the entry with the lowest | ||
2021 | * priority from consideration for scheduling at the | ||
2022 | * end of the loop? */ | ||
2023 | queue_size = 0; | ||
2024 | tsize = 0; | ||
2025 | pos = n->messages; | ||
2026 | while (pos != NULL) | ||
2027 | { | ||
2028 | queue_size++; | ||
2029 | tsize += pos->size; | ||
2030 | pos = pos->next; | ||
2031 | } | ||
2032 | discard_low_prio = GNUNET_YES; | ||
2033 | while (GNUNET_YES == discard_low_prio) | ||
2034 | { | ||
2035 | min = NULL; | ||
2036 | min_prio = UINT_MAX; | ||
2037 | discard_low_prio = GNUNET_NO; | ||
2038 | /* calculate number of bytes available for transmission at time "t" */ | ||
2039 | avail = GNUNET_BANDWIDTH_tracker_get_available (&n->available_send_window); | ||
2040 | t = now; | ||
2041 | /* how many bytes have we (hypothetically) scheduled so far */ | ||
2042 | off = 0; | ||
2043 | /* maximum time we can wait before transmitting anything | ||
2044 | * and still make all of our deadlines */ | ||
2045 | slack = GNUNET_TIME_UNIT_FOREVER_REL; | ||
2046 | pos = n->messages; | ||
2047 | /* note that we use "*2" here because we want to look | ||
2048 | * a bit further into the future; much more makes no | ||
2049 | * sense since new message might be scheduled in the | ||
2050 | * meantime... */ | ||
2051 | while ((pos != NULL) && (off < size * 2)) | ||
2052 | { | ||
2053 | if (pos->do_transmit == GNUNET_YES) | ||
2054 | { | ||
2055 | /* already removed from consideration */ | ||
2056 | pos = pos->next; | ||
2057 | continue; | ||
2058 | } | ||
2059 | if (discard_low_prio == GNUNET_NO) | ||
2060 | { | ||
2061 | delta = GNUNET_TIME_absolute_get_difference (t, pos->deadline); | ||
2062 | if (delta.rel_value > 0) | ||
2063 | { | ||
2064 | // FIXME: HUH? Check! | ||
2065 | t = pos->deadline; | ||
2066 | avail += | ||
2067 | GNUNET_BANDWIDTH_value_get_available_until (n->bw_out, delta); | ||
2068 | } | ||
2069 | if (avail < pos->size) | ||
2070 | { | ||
2071 | // FIXME: HUH? Check! | ||
2072 | discard_low_prio = GNUNET_YES; /* we could not schedule this one! */ | ||
2073 | } | ||
2074 | else | ||
2075 | { | ||
2076 | avail -= pos->size; | ||
2077 | /* update slack, considering both its absolute deadline | ||
2078 | * and relative deadlines caused by other messages | ||
2079 | * with their respective load */ | ||
2080 | slack = | ||
2081 | GNUNET_TIME_relative_min (slack, | ||
2082 | GNUNET_BANDWIDTH_value_get_delay_for | ||
2083 | (n->bw_out, avail)); | ||
2084 | if (pos->deadline.abs_value <= now.abs_value) | ||
2085 | { | ||
2086 | /* now or never */ | ||
2087 | slack = GNUNET_TIME_UNIT_ZERO; | ||
2088 | } | ||
2089 | else if (GNUNET_YES == pos->got_slack) | ||
2090 | { | ||
2091 | /* should be soon now! */ | ||
2092 | slack = | ||
2093 | GNUNET_TIME_relative_min (slack, | ||
2094 | GNUNET_TIME_absolute_get_remaining | ||
2095 | (pos->slack_deadline)); | ||
2096 | } | ||
2097 | else | ||
2098 | { | ||
2099 | slack = | ||
2100 | GNUNET_TIME_relative_min (slack, | ||
2101 | GNUNET_TIME_absolute_get_difference | ||
2102 | (now, pos->deadline)); | ||
2103 | pos->got_slack = GNUNET_YES; | ||
2104 | pos->slack_deadline = | ||
2105 | GNUNET_TIME_absolute_min (pos->deadline, | ||
2106 | GNUNET_TIME_relative_to_absolute | ||
2107 | (GNUNET_CONSTANTS_MAX_CORK_DELAY)); | ||
2108 | } | ||
2109 | } | ||
2110 | } | ||
2111 | off += pos->size; | ||
2112 | t = GNUNET_TIME_absolute_max (pos->deadline, t); // HUH? Check! | ||
2113 | if (pos->priority <= min_prio) | ||
2114 | { | ||
2115 | /* update min for discard */ | ||
2116 | min_prio = pos->priority; | ||
2117 | min = pos; | ||
2118 | } | ||
2119 | pos = pos->next; | ||
2120 | } | ||
2121 | if (discard_low_prio) | ||
2122 | { | ||
2123 | GNUNET_assert (min != NULL); | ||
2124 | /* remove lowest-priority entry from consideration */ | ||
2125 | min->do_transmit = GNUNET_YES; /* means: discard (for now) */ | ||
2126 | } | ||
2127 | last = pos; | ||
2128 | } | ||
2129 | /* guard against sending "tiny" messages with large headers without | ||
2130 | * urgent deadlines */ | ||
2131 | if ((slack.rel_value > GNUNET_CONSTANTS_MAX_CORK_DELAY.rel_value) && | ||
2132 | (size > 4 * off) && (queue_size <= MAX_PEER_QUEUE_SIZE - 2)) | ||
2133 | { | ||
2134 | /* less than 25% of message would be filled with deadlines still | ||
2135 | * being met if we delay by one second or more; so just wait for | ||
2136 | * more data; but do not wait longer than 1s (since we don't want | ||
2137 | * to delay messages for a really long time either). */ | ||
2138 | *retry_time = GNUNET_CONSTANTS_MAX_CORK_DELAY; | ||
2139 | /* reset do_transmit values for next time */ | ||
2140 | while (pos != last) | ||
2141 | { | ||
2142 | pos->do_transmit = GNUNET_NO; | ||
2143 | pos = pos->next; | ||
2144 | } | ||
2145 | GNUNET_STATISTICS_update (stats, | ||
2146 | gettext_noop | ||
2147 | ("# transmissions delayed due to corking"), 1, | ||
2148 | GNUNET_NO); | ||
2149 | #if DEBUG_CORE | ||
2150 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2151 | "Deferring transmission for %llums due to underfull message buffer size (%u/%u)\n", | ||
2152 | (unsigned long long) retry_time->rel_value, (unsigned int) off, | ||
2153 | (unsigned int) size); | ||
2154 | #endif | ||
2155 | return 0; | ||
2156 | } | ||
2157 | /* select marked messages (up to size) for transmission */ | ||
2158 | off = 0; | ||
2159 | pos = n->messages; | ||
2160 | while (pos != last) | ||
2161 | { | ||
2162 | if ((pos->size <= size) && (pos->do_transmit == GNUNET_NO)) | ||
2163 | { | ||
2164 | pos->do_transmit = GNUNET_YES; /* mark for transmission */ | ||
2165 | off += pos->size; | ||
2166 | size -= pos->size; | ||
2167 | #if DEBUG_CORE > 1 | ||
2168 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2169 | "Selecting message of size %u for transmission\n", | ||
2170 | (unsigned int) pos->size); | ||
2171 | #endif | ||
2172 | } | ||
2173 | else | ||
2174 | { | ||
2175 | #if DEBUG_CORE > 1 | ||
2176 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2177 | "Not selecting message of size %u for transmission at this time (maximum is %u)\n", | ||
2178 | (unsigned int) pos->size, size); | ||
2179 | #endif | ||
2180 | pos->do_transmit = GNUNET_NO; /* mark for not transmitting! */ | ||
2181 | } | ||
2182 | pos = pos->next; | ||
2183 | } | ||
2184 | #if DEBUG_CORE | ||
2185 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2186 | "Selected %llu/%llu bytes of %u/%u plaintext messages for transmission to `%4s'.\n", | ||
2187 | (unsigned long long) off, (unsigned long long) tsize, queue_size, | ||
2188 | (unsigned int) MAX_PEER_QUEUE_SIZE, GNUNET_i2s (&n->peer)); | ||
2189 | #endif | ||
2190 | return off; | ||
2191 | } | ||
2192 | |||
2193 | |||
2194 | /** | ||
2195 | * Batch multiple messages into a larger buffer. | ||
2196 | * | ||
2197 | * @param n neighbour to take messages from | ||
2198 | * @param buf target buffer | ||
2199 | * @param size size of buf | ||
2200 | * @param deadline set to transmission deadline for the result | ||
2201 | * @param retry_time set to the time when we should try again | ||
2202 | * (only valid if this function returns zero) | ||
2203 | * @param priority set to the priority of the batch | ||
2204 | * @return number of bytes written to buf (can be zero) | ||
2205 | */ | ||
2206 | static size_t | ||
2207 | batch_message (struct Neighbour *n, char *buf, size_t size, | ||
2208 | struct GNUNET_TIME_Absolute *deadline, | ||
2209 | struct GNUNET_TIME_Relative *retry_time, unsigned int *priority) | ||
2210 | { | ||
2211 | char ntmb[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1]; | ||
2212 | struct NotifyTrafficMessage *ntm = (struct NotifyTrafficMessage *) ntmb; | ||
2213 | struct MessageEntry *pos; | ||
2214 | struct MessageEntry *prev; | ||
2215 | struct MessageEntry *next; | ||
2216 | size_t ret; | ||
2217 | |||
2218 | ret = 0; | ||
2219 | *priority = 0; | ||
2220 | *deadline = GNUNET_TIME_UNIT_FOREVER_ABS; | ||
2221 | *retry_time = GNUNET_TIME_UNIT_FOREVER_REL; | ||
2222 | if (0 == select_messages (n, size, retry_time)) | ||
2223 | { | ||
2224 | #if DEBUG_CORE | ||
2225 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2226 | "No messages selected, will try again in %llu ms\n", | ||
2227 | retry_time->rel_value); | ||
2228 | #endif | ||
2229 | return 0; | ||
2230 | } | ||
2231 | ntm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_OUTBOUND); | ||
2232 | ntm->ats_count = htonl (0); | ||
2233 | ntm->ats.type = htonl (0); | ||
2234 | ntm->ats.value = htonl (0); | ||
2235 | ntm->peer = n->peer; | ||
2236 | pos = n->messages; | ||
2237 | prev = NULL; | ||
2238 | while ((pos != NULL) && (size >= sizeof (struct GNUNET_MessageHeader))) | ||
2239 | { | ||
2240 | next = pos->next; | ||
2241 | if (GNUNET_YES == pos->do_transmit) | ||
2242 | { | ||
2243 | GNUNET_assert (pos->size <= size); | ||
2244 | /* do notifications */ | ||
2245 | /* FIXME: track if we have *any* client that wants | ||
2246 | * full notifications and only do this if that is | ||
2247 | * actually true */ | ||
2248 | if (pos->size < | ||
2249 | GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct NotifyTrafficMessage)) | ||
2250 | { | ||
2251 | memcpy (&ntm[1], &pos[1], pos->size); | ||
2252 | ntm->header.size = | ||
2253 | htons (sizeof (struct NotifyTrafficMessage) + | ||
2254 | sizeof (struct GNUNET_MessageHeader)); | ||
2255 | send_to_all_clients (&ntm->header, GNUNET_YES, | ||
2256 | GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND); | ||
2257 | } | ||
2258 | else | ||
2259 | { | ||
2260 | /* message too large for 'full' notifications, we do at | ||
2261 | * least the 'hdr' type */ | ||
2262 | memcpy (&ntm[1], &pos[1], sizeof (struct GNUNET_MessageHeader)); | ||
2263 | } | ||
2264 | ntm->header.size = | ||
2265 | htons (sizeof (struct NotifyTrafficMessage) + pos->size); | ||
2266 | send_to_all_clients (&ntm->header, GNUNET_YES, | ||
2267 | GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND); | ||
2268 | #if DEBUG_HANDSHAKE | ||
2269 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2270 | "Encrypting %u bytes with message of type %u and size %u\n", | ||
2271 | pos->size, | ||
2272 | (unsigned int) | ||
2273 | ntohs (((const struct GNUNET_MessageHeader *) &pos[1])->type), | ||
2274 | (unsigned int) | ||
2275 | ntohs (((const struct GNUNET_MessageHeader *) | ||
2276 | &pos[1])->size)); | ||
2277 | #endif | ||
2278 | /* copy for encrypted transmission */ | ||
2279 | memcpy (&buf[ret], &pos[1], pos->size); | ||
2280 | ret += pos->size; | ||
2281 | size -= pos->size; | ||
2282 | *priority += pos->priority; | ||
2283 | #if DEBUG_CORE > 1 | ||
2284 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2285 | "Adding plaintext message of size %u with deadline %llu ms to batch\n", | ||
2286 | (unsigned int) pos->size, | ||
2287 | (unsigned long long) | ||
2288 | GNUNET_TIME_absolute_get_remaining (pos->deadline).rel_value); | ||
2289 | #endif | ||
2290 | deadline->abs_value = | ||
2291 | GNUNET_MIN (deadline->abs_value, pos->deadline.abs_value); | ||
2292 | GNUNET_free (pos); | ||
2293 | if (prev == NULL) | ||
2294 | n->messages = next; | ||
2295 | else | ||
2296 | prev->next = next; | ||
2297 | } | ||
2298 | else | ||
2299 | { | ||
2300 | prev = pos; | ||
2301 | } | ||
2302 | pos = next; | ||
2303 | } | ||
2304 | #if DEBUG_CORE > 1 | ||
2305 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2306 | "Deadline for message batch is %llu ms\n", | ||
2307 | GNUNET_TIME_absolute_get_remaining (*deadline).rel_value); | ||
2308 | #endif | ||
2309 | return ret; | ||
2310 | } | ||
2311 | |||
2312 | |||
2313 | /** | ||
2314 | * Remove messages with deadlines that have long expired from | ||
2315 | * the queue. | ||
2316 | * | ||
2317 | * @param n neighbour to inspect | ||
2318 | */ | ||
2319 | static void | ||
2320 | discard_expired_messages (struct Neighbour *n) | ||
2321 | { | ||
2322 | struct MessageEntry *prev; | ||
2323 | struct MessageEntry *next; | ||
2324 | struct MessageEntry *pos; | ||
2325 | struct GNUNET_TIME_Absolute now; | ||
2326 | struct GNUNET_TIME_Relative delta; | ||
2327 | int disc; | ||
2328 | unsigned int queue_length; | ||
2329 | |||
2330 | disc = GNUNET_NO; | ||
2331 | now = GNUNET_TIME_absolute_get (); | ||
2332 | prev = NULL; | ||
2333 | queue_length = 0; | ||
2334 | pos = n->messages; | ||
2335 | while (pos != NULL) | ||
2336 | { | ||
2337 | queue_length++; | ||
2338 | next = pos->next; | ||
2339 | delta = GNUNET_TIME_absolute_get_difference (pos->deadline, now); | ||
2340 | if (delta.rel_value > PAST_EXPIRATION_DISCARD_TIME.rel_value) | ||
2341 | { | ||
2342 | #if DEBUG_CORE | ||
2343 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
2344 | "Message is %llu ms past due, discarding.\n", | ||
2345 | delta.rel_value); | ||
2346 | #endif | ||
2347 | if (prev == NULL) | ||
2348 | n->messages = next; | ||
2349 | else | ||
2350 | prev->next = next; | ||
2351 | GNUNET_STATISTICS_update (stats, | ||
2352 | gettext_noop | ||
2353 | ("# messages discarded (expired prior to transmission)"), | ||
2354 | 1, GNUNET_NO); | ||
2355 | disc = GNUNET_YES; | ||
2356 | GNUNET_free (pos); | ||
2357 | } | ||
2358 | else | ||
2359 | prev = pos; | ||
2360 | pos = next; | ||
2361 | } | ||
2362 | if ( (GNUNET_YES == disc) && | ||
2363 | (queue_length == MAX_PEER_QUEUE_SIZE) ) | ||
2364 | schedule_peer_messages (n); | ||
2365 | } | ||
2366 | |||
2367 | |||
2368 | /** | ||
2369 | * Signature of the main function of a task. | ||
2370 | * | ||
2371 | * @param cls closure | ||
2372 | * @param tc context information (why was this task triggered now) | ||
2373 | */ | ||
2374 | static void | ||
2375 | retry_plaintext_processing (void *cls, | ||
2376 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
2377 | { | ||
2378 | struct Neighbour *n = cls; | ||
2379 | |||
2380 | n->retry_plaintext_task = GNUNET_SCHEDULER_NO_TASK; | ||
2381 | process_plaintext_neighbour_queue (n); | ||
2382 | } | ||
2383 | |||
2384 | |||
2385 | /** | ||
2386 | * Send our key (and encrypted PING) to the other peer. | ||
2387 | * | ||
2388 | * @param n the other peer | ||
2389 | */ | ||
2390 | static void | ||
2391 | send_key (struct Neighbour *n); | ||
2392 | |||
2393 | /** | ||
2394 | * Task that will retry "send_key" if our previous attempt failed | ||
2395 | * to yield a PONG. | ||
2396 | */ | ||
2397 | static void | ||
2398 | set_key_retry_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
2399 | { | ||
2400 | struct Neighbour *n = cls; | ||
2401 | |||
2402 | #if DEBUG_CORE | ||
2403 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Retrying key transmission to `%4s'\n", | ||
2404 | GNUNET_i2s (&n->peer)); | ||
2405 | #endif | ||
2406 | n->retry_set_key_task = GNUNET_SCHEDULER_NO_TASK; | ||
2407 | n->set_key_retry_frequency = | ||
2408 | GNUNET_TIME_relative_multiply (n->set_key_retry_frequency, 2); | ||
2409 | send_key (n); | ||
2410 | } | ||
2411 | |||
2412 | |||
2413 | /** | ||
2414 | * Check if we have plaintext messages for the specified neighbour | ||
2415 | * pending, and if so, consider batching and encrypting them (and | ||
2416 | * then trigger processing of the encrypted queue if needed). | ||
2417 | * | ||
2418 | * @param n neighbour to check. | ||
2419 | */ | ||
2420 | static void | ||
2421 | process_plaintext_neighbour_queue (struct Neighbour *n) | ||
2422 | { | ||
2423 | char pbuf[GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE + sizeof (struct EncryptedMessage)]; /* plaintext */ | ||
2424 | size_t used; | ||
2425 | struct EncryptedMessage *em; /* encrypted message */ | ||
2426 | struct EncryptedMessage *ph; /* plaintext header */ | ||
2427 | struct MessageEntry *me; | ||
2428 | unsigned int priority; | ||
2429 | struct GNUNET_TIME_Absolute deadline; | ||
2430 | struct GNUNET_TIME_Relative retry_time; | ||
2431 | struct GNUNET_CRYPTO_AesInitializationVector iv; | ||
2432 | struct GNUNET_CRYPTO_AuthKey auth_key; | ||
2433 | |||
2434 | if (n->retry_plaintext_task != GNUNET_SCHEDULER_NO_TASK) | ||
2435 | { | ||
2436 | GNUNET_SCHEDULER_cancel (n->retry_plaintext_task); | ||
2437 | n->retry_plaintext_task = GNUNET_SCHEDULER_NO_TASK; | ||
2438 | } | ||
2439 | switch (n->status) | ||
2440 | { | ||
2441 | case PEER_STATE_DOWN: | ||
2442 | send_key (n); | ||
2443 | #if DEBUG_CORE | ||
2444 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2445 | "Not yet connected to `%4s', deferring processing of plaintext messages.\n", | ||
2446 | GNUNET_i2s (&n->peer)); | ||
2447 | #endif | ||
2448 | return; | ||
2449 | case PEER_STATE_KEY_SENT: | ||
2450 | if (n->retry_set_key_task == GNUNET_SCHEDULER_NO_TASK) | ||
2451 | n->retry_set_key_task = | ||
2452 | GNUNET_SCHEDULER_add_delayed (n->set_key_retry_frequency, | ||
2453 | &set_key_retry_task, n); | ||
2454 | #if DEBUG_CORE | ||
2455 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2456 | "Not yet connected to `%4s', deferring processing of plaintext messages.\n", | ||
2457 | GNUNET_i2s (&n->peer)); | ||
2458 | #endif | ||
2459 | return; | ||
2460 | case PEER_STATE_KEY_RECEIVED: | ||
2461 | if (n->retry_set_key_task == GNUNET_SCHEDULER_NO_TASK) | ||
2462 | n->retry_set_key_task = | ||
2463 | GNUNET_SCHEDULER_add_delayed (n->set_key_retry_frequency, | ||
2464 | &set_key_retry_task, n); | ||
2465 | #if DEBUG_CORE | ||
2466 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2467 | "Not yet connected to `%4s', deferring processing of plaintext messages.\n", | ||
2468 | GNUNET_i2s (&n->peer)); | ||
2469 | #endif | ||
2470 | return; | ||
2471 | case PEER_STATE_KEY_CONFIRMED: | ||
2472 | /* ready to continue */ | ||
2473 | break; | ||
2474 | } | ||
2475 | discard_expired_messages (n); | ||
2476 | if (n->messages == NULL) | ||
2477 | { | ||
2478 | #if DEBUG_CORE | ||
2479 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2480 | "Plaintext message queue for `%4s' is empty.\n", | ||
2481 | GNUNET_i2s (&n->peer)); | ||
2482 | #endif | ||
2483 | return; /* no pending messages */ | ||
2484 | } | ||
2485 | if (n->encrypted_head != NULL) | ||
2486 | { | ||
2487 | #if DEBUG_CORE > 2 | ||
2488 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2489 | "Encrypted message queue for `%4s' is still full, delaying plaintext processing.\n", | ||
2490 | GNUNET_i2s (&n->peer)); | ||
2491 | #endif | ||
2492 | return; /* wait for messages already encrypted to be | ||
2493 | * processed first! */ | ||
2494 | } | ||
2495 | ph = (struct EncryptedMessage *) pbuf; | ||
2496 | deadline = GNUNET_TIME_UNIT_FOREVER_ABS; | ||
2497 | priority = 0; | ||
2498 | used = sizeof (struct EncryptedMessage); | ||
2499 | used += | ||
2500 | batch_message (n, &pbuf[used], | ||
2501 | GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE, &deadline, | ||
2502 | &retry_time, &priority); | ||
2503 | if (used == sizeof (struct EncryptedMessage)) | ||
2504 | { | ||
2505 | #if DEBUG_CORE > 1 | ||
2506 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2507 | "No messages selected for transmission to `%4s' at this time, will try again later.\n", | ||
2508 | GNUNET_i2s (&n->peer)); | ||
2509 | #endif | ||
2510 | /* no messages selected for sending, try again later... */ | ||
2511 | n->retry_plaintext_task = | ||
2512 | GNUNET_SCHEDULER_add_delayed (retry_time, &retry_plaintext_processing, | ||
2513 | n); | ||
2514 | return; | ||
2515 | } | ||
2516 | #if DEBUG_CORE_QUOTA | ||
2517 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2518 | "Sending %u b/s as new limit to peer `%4s'\n", | ||
2519 | (unsigned int) ntohl (n->bw_in.value__), GNUNET_i2s (&n->peer)); | ||
2520 | #endif | ||
2521 | ph->iv_seed = | ||
2522 | htonl (GNUNET_CRYPTO_random_u32 | ||
2523 | (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX)); | ||
2524 | ph->sequence_number = htonl (++n->last_sequence_number_sent); | ||
2525 | ph->inbound_bw_limit = n->bw_in; | ||
2526 | ph->timestamp = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ()); | ||
2527 | |||
2528 | /* setup encryption message header */ | ||
2529 | me = GNUNET_malloc (sizeof (struct MessageEntry) + used); | ||
2530 | me->deadline = deadline; | ||
2531 | me->priority = priority; | ||
2532 | me->size = used; | ||
2533 | em = (struct EncryptedMessage *) &me[1]; | ||
2534 | em->header.size = htons (used); | ||
2535 | em->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_ENCRYPTED_MESSAGE); | ||
2536 | em->iv_seed = ph->iv_seed; | ||
2537 | derive_iv (&iv, &n->encrypt_key, ph->iv_seed, &n->peer); | ||
2538 | /* encrypt */ | ||
2539 | #if DEBUG_HANDSHAKE | ||
2540 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2541 | "Encrypting %u bytes of plaintext messages for `%4s' for transmission in %llums.\n", | ||
2542 | (unsigned int) used - ENCRYPTED_HEADER_SIZE, | ||
2543 | GNUNET_i2s (&n->peer), | ||
2544 | (unsigned long long) | ||
2545 | GNUNET_TIME_absolute_get_remaining (deadline).rel_value); | ||
2546 | #endif | ||
2547 | GNUNET_assert (GNUNET_OK == | ||
2548 | do_encrypt (n, &iv, &ph->sequence_number, &em->sequence_number, | ||
2549 | used - ENCRYPTED_HEADER_SIZE)); | ||
2550 | derive_auth_key (&auth_key, &n->encrypt_key, ph->iv_seed, | ||
2551 | n->encrypt_key_created); | ||
2552 | GNUNET_CRYPTO_hmac (&auth_key, &em->sequence_number, | ||
2553 | used - ENCRYPTED_HEADER_SIZE, &em->hmac); | ||
2554 | #if DEBUG_HANDSHAKE | ||
2555 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2556 | "Authenticated %u bytes of ciphertext %u: `%s'\n", | ||
2557 | used - ENCRYPTED_HEADER_SIZE, | ||
2558 | GNUNET_CRYPTO_crc32_n (&em->sequence_number, | ||
2559 | used - ENCRYPTED_HEADER_SIZE), | ||
2560 | GNUNET_h2s (&em->hmac)); | ||
2561 | #endif | ||
2562 | /* append to transmission list */ | ||
2563 | GNUNET_CONTAINER_DLL_insert_after (n->encrypted_head, n->encrypted_tail, | ||
2564 | n->encrypted_tail, me); | ||
2565 | process_encrypted_neighbour_queue (n); | ||
2566 | schedule_peer_messages (n); | ||
2567 | } | ||
2568 | |||
2569 | |||
2570 | /** | ||
2571 | * Function that recalculates the bandwidth quota for the | ||
2572 | * given neighbour and transmits it to the transport service. | ||
2573 | * | ||
2574 | * @param cls neighbour for the quota update | ||
2575 | * @param tc context | ||
2576 | */ | ||
2577 | static void | ||
2578 | neighbour_quota_update (void *cls, | ||
2579 | const struct GNUNET_SCHEDULER_TaskContext *tc); | ||
2580 | |||
2581 | |||
2582 | /** | ||
2583 | * Schedule the task that will recalculate the bandwidth | ||
2584 | * quota for this peer (and possibly force a disconnect of | ||
2585 | * idle peers by calculating a bandwidth of zero). | ||
2586 | */ | ||
2587 | static void | ||
2588 | schedule_quota_update (struct Neighbour *n) | ||
2589 | { | ||
2590 | GNUNET_assert (n->quota_update_task == GNUNET_SCHEDULER_NO_TASK); | ||
2591 | n->quota_update_task = | ||
2592 | GNUNET_SCHEDULER_add_delayed (QUOTA_UPDATE_FREQUENCY, | ||
2593 | &neighbour_quota_update, n); | ||
2594 | } | ||
2595 | |||
2596 | |||
2597 | /** | ||
2598 | * Initialize a new 'struct Neighbour'. | ||
2599 | * | ||
2600 | * @param pid ID of the new neighbour | ||
2601 | * @return handle for the new neighbour | ||
2602 | */ | ||
2603 | static struct Neighbour * | ||
2604 | create_neighbour (const struct GNUNET_PeerIdentity *pid) | ||
2605 | { | ||
2606 | struct Neighbour *n; | ||
2607 | struct GNUNET_TIME_Absolute now; | ||
2608 | |||
2609 | #if DEBUG_CORE | ||
2610 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2611 | "Creating neighbour entry for peer `%4s'\n", GNUNET_i2s (pid)); | ||
2612 | #endif | ||
2613 | n = GNUNET_malloc (sizeof (struct Neighbour)); | ||
2614 | n->peer = *pid; | ||
2615 | GNUNET_CRYPTO_aes_create_session_key (&n->encrypt_key); | ||
2616 | now = GNUNET_TIME_absolute_get (); | ||
2617 | n->encrypt_key_created = now; | ||
2618 | n->last_activity = now; | ||
2619 | n->set_key_retry_frequency = INITIAL_SET_KEY_RETRY_FREQUENCY; | ||
2620 | n->bw_in = GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT; | ||
2621 | n->bw_out = GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT; | ||
2622 | n->bw_out_internal_limit = GNUNET_BANDWIDTH_value_init (UINT32_MAX); | ||
2623 | n->bw_out_external_limit = GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT; | ||
2624 | n->ping_challenge = | ||
2625 | GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX); | ||
2626 | GNUNET_assert (GNUNET_OK == | ||
2627 | GNUNET_CONTAINER_multihashmap_put (neighbours, | ||
2628 | &n->peer.hashPubKey, n, | ||
2629 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
2630 | GNUNET_STATISTICS_set (stats, gettext_noop ("# neighbour entries allocated"), | ||
2631 | GNUNET_CONTAINER_multihashmap_size (neighbours), | ||
2632 | GNUNET_NO); | ||
2633 | neighbour_quota_update (n, NULL); | ||
2634 | consider_free_neighbour (n); | ||
2635 | return n; | ||
2636 | } | ||
2637 | |||
2638 | |||
2639 | /** | ||
2640 | * Handle CORE_SEND request. | ||
2641 | * | ||
2642 | * @param cls unused | ||
2643 | * @param client the client issuing the request | ||
2644 | * @param message the "struct SendMessage" | ||
2645 | */ | ||
2646 | static void | ||
2647 | handle_client_send (void *cls, struct GNUNET_SERVER_Client *client, | ||
2648 | const struct GNUNET_MessageHeader *message) | ||
2649 | { | ||
2650 | const struct SendMessage *sm; | ||
2651 | struct Neighbour *n; | ||
2652 | struct MessageEntry *prev; | ||
2653 | struct MessageEntry *pos; | ||
2654 | struct MessageEntry *e; | ||
2655 | struct MessageEntry *min_prio_entry; | ||
2656 | struct MessageEntry *min_prio_prev; | ||
2657 | unsigned int min_prio; | ||
2658 | unsigned int queue_size; | ||
2659 | uint16_t msize; | ||
2660 | |||
2661 | msize = ntohs (message->size); | ||
2662 | if (msize < | ||
2663 | sizeof (struct SendMessage) + sizeof (struct GNUNET_MessageHeader)) | ||
2664 | { | ||
2665 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
2666 | "msize is %u, should be at least %u (in %s:%d)\n", msize, | ||
2667 | sizeof (struct SendMessage) + | ||
2668 | sizeof (struct GNUNET_MessageHeader), __FILE__, __LINE__); | ||
2669 | GNUNET_break (0); | ||
2670 | if (client != NULL) | ||
2671 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
2672 | return; | ||
2673 | } | ||
2674 | sm = (const struct SendMessage *) message; | ||
2675 | msize -= sizeof (struct SendMessage); | ||
2676 | if (0 == | ||
2677 | memcmp (&sm->peer, &my_identity, sizeof (struct GNUNET_PeerIdentity))) | ||
2678 | { | ||
2679 | /* loopback */ | ||
2680 | GNUNET_SERVER_mst_receive (mst, &self, (const char *) &sm[1], msize, | ||
2681 | GNUNET_YES, GNUNET_NO); | ||
2682 | if (client != NULL) | ||
2683 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
2684 | return; | ||
2685 | } | ||
2686 | n = find_neighbour (&sm->peer); | ||
2687 | if ((n == NULL) || (GNUNET_YES != n->is_connected) || | ||
2688 | (n->status != PEER_STATE_KEY_CONFIRMED)) | ||
2689 | { | ||
2690 | /* attempt to send message to peer that is not connected anymore | ||
2691 | * (can happen due to asynchrony) */ | ||
2692 | GNUNET_STATISTICS_update (stats, | ||
2693 | gettext_noop | ||
2694 | ("# messages discarded (disconnected)"), 1, | ||
2695 | GNUNET_NO); | ||
2696 | if (client != NULL) | ||
2697 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
2698 | return; | ||
2699 | } | ||
2700 | #if DEBUG_CORE | ||
2701 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2702 | "Core received `%s' request, queueing %u bytes of plaintext data for transmission to `%4s'.\n", | ||
2703 | "SEND", (unsigned int) msize, GNUNET_i2s (&sm->peer)); | ||
2704 | #endif | ||
2705 | discard_expired_messages (n); | ||
2706 | /* bound queue size */ | ||
2707 | /* NOTE: this entire block to bound the queue size should be | ||
2708 | * obsolete with the new client-request code and the | ||
2709 | * 'schedule_peer_messages' mechanism; we still have this code in | ||
2710 | * here for now as a sanity check for the new mechanmism; | ||
2711 | * ultimately, we should probably simply reject SEND messages that | ||
2712 | * are not 'approved' (or provide a new core API for very unreliable | ||
2713 | * delivery that always sends with priority 0). Food for thought. */ | ||
2714 | min_prio = UINT32_MAX; | ||
2715 | min_prio_entry = NULL; | ||
2716 | min_prio_prev = NULL; | ||
2717 | queue_size = 0; | ||
2718 | prev = NULL; | ||
2719 | pos = n->messages; | ||
2720 | while (pos != NULL) | ||
2721 | { | ||
2722 | if (pos->priority <= min_prio) | ||
2723 | { | ||
2724 | min_prio_entry = pos; | ||
2725 | min_prio_prev = prev; | ||
2726 | min_prio = pos->priority; | ||
2727 | } | ||
2728 | queue_size++; | ||
2729 | prev = pos; | ||
2730 | pos = pos->next; | ||
2731 | } | ||
2732 | if (queue_size >= MAX_PEER_QUEUE_SIZE) | ||
2733 | { | ||
2734 | /* queue full */ | ||
2735 | if (ntohl (sm->priority) <= min_prio) | ||
2736 | { | ||
2737 | /* discard new entry; this should no longer happen! */ | ||
2738 | GNUNET_break (0); | ||
2739 | #if DEBUG_CORE | ||
2740 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2741 | "Queue full (%u/%u), discarding new request (%u bytes of type %u)\n", | ||
2742 | queue_size, (unsigned int) MAX_PEER_QUEUE_SIZE, | ||
2743 | (unsigned int) msize, (unsigned int) ntohs (message->type)); | ||
2744 | #endif | ||
2745 | GNUNET_STATISTICS_update (stats, | ||
2746 | gettext_noop ("# discarded CORE_SEND requests"), | ||
2747 | 1, GNUNET_NO); | ||
2748 | |||
2749 | if (client != NULL) | ||
2750 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
2751 | return; | ||
2752 | } | ||
2753 | GNUNET_assert (min_prio_entry != NULL); | ||
2754 | /* discard "min_prio_entry" */ | ||
2755 | #if DEBUG_CORE | ||
2756 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2757 | "Queue full, discarding existing older request\n"); | ||
2758 | #endif | ||
2759 | GNUNET_STATISTICS_update (stats, | ||
2760 | gettext_noop | ||
2761 | ("# discarded lower priority CORE_SEND requests"), | ||
2762 | 1, GNUNET_NO); | ||
2763 | if (min_prio_prev == NULL) | ||
2764 | n->messages = min_prio_entry->next; | ||
2765 | else | ||
2766 | min_prio_prev->next = min_prio_entry->next; | ||
2767 | GNUNET_free (min_prio_entry); | ||
2768 | } | ||
2769 | |||
2770 | #if DEBUG_CORE | ||
2771 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2772 | "Adding transmission request for `%4s' of size %u to queue\n", | ||
2773 | GNUNET_i2s (&sm->peer), (unsigned int) msize); | ||
2774 | #endif | ||
2775 | GNUNET_break (0 == ntohl (sm->reserved)); | ||
2776 | e = GNUNET_malloc (sizeof (struct MessageEntry) + msize); | ||
2777 | e->deadline = GNUNET_TIME_absolute_ntoh (sm->deadline); | ||
2778 | e->priority = ntohl (sm->priority); | ||
2779 | e->size = msize; | ||
2780 | if (GNUNET_YES != (int) ntohl (sm->cork)) | ||
2781 | e->got_slack = GNUNET_YES; | ||
2782 | memcpy (&e[1], &sm[1], msize); | ||
2783 | |||
2784 | /* insert, keep list sorted by deadline */ | ||
2785 | prev = NULL; | ||
2786 | pos = n->messages; | ||
2787 | while ((pos != NULL) && (pos->deadline.abs_value < e->deadline.abs_value)) | ||
2788 | { | ||
2789 | prev = pos; | ||
2790 | pos = pos->next; | ||
2791 | } | ||
2792 | if (prev == NULL) | ||
2793 | n->messages = e; | ||
2794 | else | ||
2795 | prev->next = e; | ||
2796 | e->next = pos; | ||
2797 | |||
2798 | /* consider scheduling now */ | ||
2799 | process_plaintext_neighbour_queue (n); | ||
2800 | if (client != NULL) | ||
2801 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
2802 | } | ||
2803 | |||
2804 | |||
2805 | /** | ||
2806 | * PEERINFO is giving us a HELLO for a peer. Add the public key to | ||
2807 | * the neighbour's struct and retry send_key. Or, if we did not get a | ||
2808 | * HELLO, just do nothing. | ||
2809 | * | ||
2810 | * @param cls the 'struct Neighbour' to retry sending the key for | ||
2811 | * @param peer the peer for which this is the HELLO | ||
2812 | * @param hello HELLO message of that peer | ||
2813 | * @param err_msg NULL if successful, otherwise contains error message | ||
2814 | */ | ||
2815 | static void | ||
2816 | process_hello_retry_send_key (void *cls, const struct GNUNET_PeerIdentity *peer, | ||
2817 | const struct GNUNET_HELLO_Message *hello, | ||
2818 | const char *err_msg) | ||
2819 | { | ||
2820 | struct Neighbour *n = cls; | ||
2821 | |||
2822 | if (err_msg != NULL) | ||
2823 | { | ||
2824 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2825 | _("Error in communication with PEERINFO service\n")); | ||
2826 | /* return; */ | ||
2827 | } | ||
2828 | |||
2829 | if (peer == NULL) | ||
2830 | { | ||
2831 | #if DEBUG_CORE | ||
2832 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Entered `%s' and `%s' is NULL!\n", | ||
2833 | "process_hello_retry_send_key", "peer"); | ||
2834 | #endif | ||
2835 | n->pitr = NULL; | ||
2836 | if (n->public_key != NULL) | ||
2837 | { | ||
2838 | if (n->retry_set_key_task != GNUNET_SCHEDULER_NO_TASK) | ||
2839 | { | ||
2840 | GNUNET_SCHEDULER_cancel (n->retry_set_key_task); | ||
2841 | n->retry_set_key_task = GNUNET_SCHEDULER_NO_TASK; | ||
2842 | } | ||
2843 | GNUNET_STATISTICS_update (stats, | ||
2844 | gettext_noop | ||
2845 | ("# SET_KEY messages deferred (need public key)"), | ||
2846 | -1, GNUNET_NO); | ||
2847 | send_key (n); | ||
2848 | } | ||
2849 | else | ||
2850 | { | ||
2851 | #if DEBUG_CORE | ||
2852 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2853 | "Failed to obtain public key for peer `%4s', delaying processing of SET_KEY\n", | ||
2854 | GNUNET_i2s (&n->peer)); | ||
2855 | #endif | ||
2856 | GNUNET_STATISTICS_update (stats, | ||
2857 | gettext_noop | ||
2858 | ("# Delayed connecting due to lack of public key"), | ||
2859 | 1, GNUNET_NO); | ||
2860 | if (GNUNET_SCHEDULER_NO_TASK == n->retry_set_key_task) | ||
2861 | n->retry_set_key_task = | ||
2862 | GNUNET_SCHEDULER_add_delayed (n->set_key_retry_frequency, | ||
2863 | &set_key_retry_task, n); | ||
2864 | } | ||
2865 | return; | ||
2866 | } | ||
2867 | |||
2868 | #if DEBUG_CORE | ||
2869 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Entered `%s' for peer `%4s'\n", | ||
2870 | "process_hello_retry_send_key", GNUNET_i2s (peer)); | ||
2871 | #endif | ||
2872 | if (n->public_key != NULL) | ||
2873 | { | ||
2874 | /* already have public key, why are we here? */ | ||
2875 | GNUNET_break (0); | ||
2876 | return; | ||
2877 | } | ||
2878 | |||
2879 | #if DEBUG_CORE | ||
2880 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2881 | "Received new `%s' message for `%4s', initiating key exchange.\n", | ||
2882 | "HELLO", GNUNET_i2s (peer)); | ||
2883 | #endif | ||
2884 | n->public_key = | ||
2885 | GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); | ||
2886 | if (GNUNET_OK != GNUNET_HELLO_get_key (hello, n->public_key)) | ||
2887 | { | ||
2888 | GNUNET_STATISTICS_update (stats, | ||
2889 | gettext_noop | ||
2890 | ("# Error extracting public key from HELLO"), 1, | ||
2891 | GNUNET_NO); | ||
2892 | GNUNET_free (n->public_key); | ||
2893 | n->public_key = NULL; | ||
2894 | #if DEBUG_CORE | ||
2895 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2896 | "GNUNET_HELLO_get_key returned awfully\n"); | ||
2897 | #endif | ||
2898 | return; | ||
2899 | } | ||
2900 | } | ||
2901 | |||
2902 | |||
2903 | /** | ||
2904 | * Send our key (and encrypted PING) to the other peer. | ||
2905 | * | ||
2906 | * @param n the other peer | ||
2907 | */ | ||
2908 | static void | ||
2909 | send_key (struct Neighbour *n) | ||
2910 | { | ||
2911 | struct MessageEntry *pos; | ||
2912 | struct SetKeyMessage *sm; | ||
2913 | struct MessageEntry *me; | ||
2914 | struct PingMessage pp; | ||
2915 | struct PingMessage *pm; | ||
2916 | struct GNUNET_CRYPTO_AesInitializationVector iv; | ||
2917 | |||
2918 | if (n->retry_set_key_task != GNUNET_SCHEDULER_NO_TASK) | ||
2919 | { | ||
2920 | GNUNET_SCHEDULER_cancel (n->retry_set_key_task); | ||
2921 | n->retry_set_key_task = GNUNET_SCHEDULER_NO_TASK; | ||
2922 | } | ||
2923 | if (n->pitr != NULL) | ||
2924 | { | ||
2925 | #if DEBUG_CORE | ||
2926 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2927 | "Key exchange in progress with `%4s'.\n", | ||
2928 | GNUNET_i2s (&n->peer)); | ||
2929 | #endif | ||
2930 | return; /* already in progress */ | ||
2931 | } | ||
2932 | if (GNUNET_YES != n->is_connected) | ||
2933 | { | ||
2934 | GNUNET_STATISTICS_update (stats, | ||
2935 | gettext_noop | ||
2936 | ("# Asking transport to connect (for SET_KEY)"), | ||
2937 | 1, GNUNET_NO); | ||
2938 | GNUNET_TRANSPORT_try_connect (transport, &n->peer); | ||
2939 | return; | ||
2940 | } | ||
2941 | #if DEBUG_CORE | ||
2942 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2943 | "Asked to perform key exchange with `%4s'.\n", | ||
2944 | GNUNET_i2s (&n->peer)); | ||
2945 | #endif | ||
2946 | if (n->public_key == NULL) | ||
2947 | { | ||
2948 | /* lookup n's public key, then try again */ | ||
2949 | #if DEBUG_CORE | ||
2950 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2951 | "Lacking public key for `%4s', trying to obtain one (send_key).\n", | ||
2952 | GNUNET_i2s (&n->peer)); | ||
2953 | #endif | ||
2954 | GNUNET_assert (n->pitr == NULL); | ||
2955 | n->pitr = | ||
2956 | GNUNET_PEERINFO_iterate (peerinfo, &n->peer, | ||
2957 | GNUNET_TIME_relative_multiply | ||
2958 | (GNUNET_TIME_UNIT_SECONDS, 20), | ||
2959 | &process_hello_retry_send_key, n); | ||
2960 | return; | ||
2961 | } | ||
2962 | pos = n->encrypted_head; | ||
2963 | while (pos != NULL) | ||
2964 | { | ||
2965 | if (GNUNET_YES == pos->is_setkey) | ||
2966 | { | ||
2967 | if (pos->sender_status == n->status) | ||
2968 | { | ||
2969 | #if DEBUG_CORE | ||
2970 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2971 | "`%s' message for `%4s' queued already\n", "SET_KEY", | ||
2972 | GNUNET_i2s (&n->peer)); | ||
2973 | #endif | ||
2974 | goto trigger_processing; | ||
2975 | } | ||
2976 | GNUNET_CONTAINER_DLL_remove (n->encrypted_head, n->encrypted_tail, pos); | ||
2977 | GNUNET_free (pos); | ||
2978 | #if DEBUG_CORE | ||
2979 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2980 | "Removing queued `%s' message for `%4s', will create a new one\n", | ||
2981 | "SET_KEY", GNUNET_i2s (&n->peer)); | ||
2982 | #endif | ||
2983 | break; | ||
2984 | } | ||
2985 | pos = pos->next; | ||
2986 | } | ||
2987 | |||
2988 | /* update status */ | ||
2989 | switch (n->status) | ||
2990 | { | ||
2991 | case PEER_STATE_DOWN: | ||
2992 | n->status = PEER_STATE_KEY_SENT; | ||
2993 | break; | ||
2994 | case PEER_STATE_KEY_SENT: | ||
2995 | break; | ||
2996 | case PEER_STATE_KEY_RECEIVED: | ||
2997 | break; | ||
2998 | case PEER_STATE_KEY_CONFIRMED: | ||
2999 | break; | ||
3000 | default: | ||
3001 | GNUNET_break (0); | ||
3002 | break; | ||
3003 | } | ||
3004 | |||
3005 | |||
3006 | /* first, set key message */ | ||
3007 | me = GNUNET_malloc (sizeof (struct MessageEntry) + | ||
3008 | sizeof (struct SetKeyMessage) + | ||
3009 | sizeof (struct PingMessage)); | ||
3010 | me->deadline = GNUNET_TIME_relative_to_absolute (MAX_SET_KEY_DELAY); | ||
3011 | me->priority = SET_KEY_PRIORITY; | ||
3012 | me->size = sizeof (struct SetKeyMessage) + sizeof (struct PingMessage); | ||
3013 | me->is_setkey = GNUNET_YES; | ||
3014 | me->got_slack = GNUNET_YES; /* do not defer this one! */ | ||
3015 | me->sender_status = n->status; | ||
3016 | GNUNET_CONTAINER_DLL_insert_after (n->encrypted_head, n->encrypted_tail, | ||
3017 | n->encrypted_tail, me); | ||
3018 | sm = (struct SetKeyMessage *) &me[1]; | ||
3019 | sm->header.size = htons (sizeof (struct SetKeyMessage)); | ||
3020 | sm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_SET_KEY); | ||
3021 | sm->sender_status = | ||
3022 | htonl ((int32_t) | ||
3023 | ((n->status == | ||
3024 | PEER_STATE_DOWN) ? PEER_STATE_KEY_SENT : n->status)); | ||
3025 | sm->purpose.size = | ||
3026 | htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) + | ||
3027 | sizeof (struct GNUNET_TIME_AbsoluteNBO) + | ||
3028 | sizeof (struct GNUNET_CRYPTO_RsaEncryptedData) + | ||
3029 | sizeof (struct GNUNET_PeerIdentity)); | ||
3030 | sm->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_SET_KEY); | ||
3031 | sm->creation_time = GNUNET_TIME_absolute_hton (n->encrypt_key_created); | ||
3032 | sm->target = n->peer; | ||
3033 | GNUNET_assert (GNUNET_OK == | ||
3034 | GNUNET_CRYPTO_rsa_encrypt (&n->encrypt_key, | ||
3035 | sizeof (struct | ||
3036 | GNUNET_CRYPTO_AesSessionKey), | ||
3037 | n->public_key, &sm->encrypted_key)); | ||
3038 | GNUNET_assert (GNUNET_OK == | ||
3039 | GNUNET_CRYPTO_rsa_sign (my_private_key, &sm->purpose, | ||
3040 | &sm->signature)); | ||
3041 | pm = (struct PingMessage *) &sm[1]; | ||
3042 | pm->header.size = htons (sizeof (struct PingMessage)); | ||
3043 | pm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_PING); | ||
3044 | pm->iv_seed = | ||
3045 | GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX); | ||
3046 | derive_iv (&iv, &n->encrypt_key, pm->iv_seed, &n->peer); | ||
3047 | pp.challenge = n->ping_challenge; | ||
3048 | pp.target = n->peer; | ||
3049 | #if DEBUG_HANDSHAKE | ||
3050 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3051 | "Encrypting `%s' and `%s' messages with challenge %u for `%4s' using key %u, IV %u (salt %u).\n", | ||
3052 | "SET_KEY", "PING", (unsigned int) n->ping_challenge, | ||
3053 | GNUNET_i2s (&n->peer), (unsigned int) n->encrypt_key.crc32, | ||
3054 | GNUNET_CRYPTO_crc32_n (&iv, sizeof (iv)), pm->iv_seed); | ||
3055 | #endif | ||
3056 | do_encrypt (n, &iv, &pp.target, &pm->target, | ||
3057 | sizeof (struct PingMessage) - ((void *) &pm->target - | ||
3058 | (void *) pm)); | ||
3059 | GNUNET_STATISTICS_update (stats, | ||
3060 | gettext_noop | ||
3061 | ("# SET_KEY and PING messages created"), 1, | ||
3062 | GNUNET_NO); | ||
3063 | #if DEBUG_CORE | ||
3064 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3065 | "Have %llu ms left for `%s' transmission.\n", | ||
3066 | (unsigned long long) | ||
3067 | GNUNET_TIME_absolute_get_remaining (me->deadline).rel_value, | ||
3068 | "SET_KEY"); | ||
3069 | #endif | ||
3070 | trigger_processing: | ||
3071 | /* trigger queue processing */ | ||
3072 | process_encrypted_neighbour_queue (n); | ||
3073 | if ((n->status != PEER_STATE_KEY_CONFIRMED) && | ||
3074 | (GNUNET_SCHEDULER_NO_TASK == n->retry_set_key_task)) | ||
3075 | n->retry_set_key_task = | ||
3076 | GNUNET_SCHEDULER_add_delayed (n->set_key_retry_frequency, | ||
3077 | &set_key_retry_task, n); | ||
3078 | } | ||
3079 | |||
3080 | |||
3081 | /** | ||
3082 | * We received a SET_KEY message. Validate and update | ||
3083 | * our key material and status. | ||
3084 | * | ||
3085 | * @param n the neighbour from which we received message m | ||
3086 | * @param m the set key message we received | ||
3087 | * @param ats performance data | ||
3088 | * @param ats_count number of entries in ats (excluding 0-termination) | ||
3089 | */ | ||
3090 | static void | ||
3091 | handle_set_key (struct Neighbour *n, const struct SetKeyMessage *m, | ||
3092 | const struct GNUNET_ATS_Information *ats, | ||
3093 | uint32_t ats_count); | ||
3094 | |||
3095 | |||
3096 | |||
3097 | /** | ||
3098 | * PEERINFO is giving us a HELLO for a peer. Add the public key to | ||
3099 | * the neighbour's struct and retry handling the set_key message. Or, | ||
3100 | * if we did not get a HELLO, just free the set key message. | ||
3101 | * | ||
3102 | * @param cls pointer to the set key message | ||
3103 | * @param peer the peer for which this is the HELLO | ||
3104 | * @param hello HELLO message of that peer | ||
3105 | * @param err_msg NULL if successful, otherwise contains error message | ||
3106 | */ | ||
3107 | static void | ||
3108 | process_hello_retry_handle_set_key (void *cls, | ||
3109 | const struct GNUNET_PeerIdentity *peer, | ||
3110 | const struct GNUNET_HELLO_Message *hello, | ||
3111 | const char *err_msg) | ||
3112 | { | ||
3113 | struct Neighbour *n = cls; | ||
3114 | struct SetKeyMessage *sm = n->skm; | ||
3115 | |||
3116 | if (err_msg != NULL) | ||
3117 | { | ||
3118 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3119 | _("Error in communication with PEERINFO service\n")); | ||
3120 | /* return; */ | ||
3121 | } | ||
3122 | |||
3123 | if (peer == NULL) | ||
3124 | { | ||
3125 | n->skm = NULL; | ||
3126 | n->pitr = NULL; | ||
3127 | if (n->public_key != NULL) | ||
3128 | { | ||
3129 | #if DEBUG_CORE | ||
3130 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3131 | "Received `%s' for `%4s', continuing processing of `%s' message.\n", | ||
3132 | "HELLO", GNUNET_i2s (&n->peer), "SET_KEY"); | ||
3133 | #endif | ||
3134 | handle_set_key (n, sm, NULL, 0); | ||
3135 | } | ||
3136 | else | ||
3137 | { | ||
3138 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3139 | _ | ||
3140 | ("Ignoring `%s' message due to lack of public key for peer `%4s' (failed to obtain one).\n"), | ||
3141 | "SET_KEY", GNUNET_i2s (&n->peer)); | ||
3142 | } | ||
3143 | GNUNET_free (sm); | ||
3144 | return; | ||
3145 | } | ||
3146 | if (n->public_key != NULL) | ||
3147 | return; /* multiple HELLOs match!? */ | ||
3148 | n->public_key = | ||
3149 | GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); | ||
3150 | if (GNUNET_OK != GNUNET_HELLO_get_key (hello, n->public_key)) | ||
3151 | { | ||
3152 | GNUNET_break_op (0); | ||
3153 | GNUNET_free (n->public_key); | ||
3154 | n->public_key = NULL; | ||
3155 | } | ||
3156 | } | ||
3157 | |||
3158 | |||
3159 | /** | ||
3160 | * Merge the given performance data with the data we currently | ||
3161 | * track for the given neighbour. | ||
3162 | * | ||
3163 | * @param n neighbour | ||
3164 | * @param ats new performance data | ||
3165 | * @param ats_count number of records in ats | ||
3166 | */ | ||
3167 | static void | ||
3168 | update_neighbour_performance (struct Neighbour *n, | ||
3169 | const struct GNUNET_ATS_Information | ||
3170 | *ats, uint32_t ats_count) | ||
3171 | { | ||
3172 | uint32_t i; | ||
3173 | unsigned int j; | ||
3174 | |||
3175 | if (ats_count == 0) | ||
3176 | return; | ||
3177 | for (i = 0; i < ats_count; i++) | ||
3178 | { | ||
3179 | for (j = 0; j < n->ats_count; j++) | ||
3180 | { | ||
3181 | if (n->ats[j].type == ats[i].type) | ||
3182 | { | ||
3183 | n->ats[j].value = ats[i].value; | ||
3184 | break; | ||
3185 | } | ||
3186 | } | ||
3187 | if (j == n->ats_count) | ||
3188 | { | ||
3189 | GNUNET_array_append (n->ats, n->ats_count, ats[i]); | ||
3190 | } | ||
3191 | } | ||
3192 | } | ||
3193 | |||
3194 | |||
3195 | /** | ||
3196 | * We received a PING message. Validate and transmit | ||
3197 | * PONG. | ||
3198 | * | ||
3199 | * @param n sender of the PING | ||
3200 | * @param m the encrypted PING message itself | ||
3201 | * @param ats performance data | ||
3202 | * @param ats_count number of entries in ats (excluding 0-termination) | ||
3203 | */ | ||
3204 | static void | ||
3205 | handle_ping (struct Neighbour *n, const struct PingMessage *m, | ||
3206 | const struct GNUNET_ATS_Information *ats, | ||
3207 | uint32_t ats_count) | ||
3208 | { | ||
3209 | struct PingMessage t; | ||
3210 | struct PongMessage tx; | ||
3211 | struct PongMessage *tp; | ||
3212 | struct MessageEntry *me; | ||
3213 | struct GNUNET_CRYPTO_AesInitializationVector iv; | ||
3214 | |||
3215 | #if DEBUG_CORE | ||
3216 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3217 | "Core service receives `%s' request from `%4s'.\n", "PING", | ||
3218 | GNUNET_i2s (&n->peer)); | ||
3219 | #endif | ||
3220 | derive_iv (&iv, &n->decrypt_key, m->iv_seed, &my_identity); | ||
3221 | if (GNUNET_OK != | ||
3222 | do_decrypt (n, &iv, &m->target, &t.target, | ||
3223 | sizeof (struct PingMessage) - ((void *) &m->target - | ||
3224 | (void *) m))) | ||
3225 | return; | ||
3226 | #if DEBUG_HANDSHAKE | ||
3227 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3228 | "Decrypted `%s' to `%4s' with challenge %u decrypted using key %u, IV %u (salt %u)\n", | ||
3229 | "PING", GNUNET_i2s (&t.target), (unsigned int) t.challenge, | ||
3230 | (unsigned int) n->decrypt_key.crc32, GNUNET_CRYPTO_crc32_n (&iv, | ||
3231 | sizeof | ||
3232 | (iv)), | ||
3233 | m->iv_seed); | ||
3234 | #endif | ||
3235 | GNUNET_STATISTICS_update (stats, gettext_noop ("# PING messages decrypted"), | ||
3236 | 1, GNUNET_NO); | ||
3237 | if (0 != | ||
3238 | memcmp (&t.target, &my_identity, sizeof (struct GNUNET_PeerIdentity))) | ||
3239 | { | ||
3240 | char sender[9]; | ||
3241 | char peer[9]; | ||
3242 | |||
3243 | GNUNET_snprintf (sender, sizeof (sender), "%8s", GNUNET_i2s (&n->peer)); | ||
3244 | GNUNET_snprintf (peer, sizeof (peer), "%8s", GNUNET_i2s (&t.target)); | ||
3245 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
3246 | _ | ||
3247 | ("Received PING from `%s' for different identity: I am `%s', PONG identity: `%s'\n"), | ||
3248 | sender, GNUNET_i2s (&my_identity), peer); | ||
3249 | GNUNET_break_op (0); | ||
3250 | return; | ||
3251 | } | ||
3252 | update_neighbour_performance (n, ats, ats_count); | ||
3253 | me = GNUNET_malloc (sizeof (struct MessageEntry) + | ||
3254 | sizeof (struct PongMessage)); | ||
3255 | GNUNET_CONTAINER_DLL_insert_after (n->encrypted_head, n->encrypted_tail, | ||
3256 | n->encrypted_tail, me); | ||
3257 | me->deadline = GNUNET_TIME_relative_to_absolute (MAX_PONG_DELAY); | ||
3258 | me->priority = PONG_PRIORITY; | ||
3259 | me->size = sizeof (struct PongMessage); | ||
3260 | tx.inbound_bw_limit = n->bw_in; | ||
3261 | tx.challenge = t.challenge; | ||
3262 | tx.target = t.target; | ||
3263 | tp = (struct PongMessage *) &me[1]; | ||
3264 | tp->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_PONG); | ||
3265 | tp->header.size = htons (sizeof (struct PongMessage)); | ||
3266 | tp->iv_seed = | ||
3267 | GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX); | ||
3268 | derive_pong_iv (&iv, &n->encrypt_key, tp->iv_seed, t.challenge, &n->peer); | ||
3269 | do_encrypt (n, &iv, &tx.challenge, &tp->challenge, | ||
3270 | sizeof (struct PongMessage) - ((void *) &tp->challenge - | ||
3271 | (void *) tp)); | ||
3272 | GNUNET_STATISTICS_update (stats, gettext_noop ("# PONG messages created"), 1, | ||
3273 | GNUNET_NO); | ||
3274 | #if DEBUG_HANDSHAKE | ||
3275 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3276 | "Encrypting `%s' with challenge %u using key %u, IV %u (salt %u)\n", | ||
3277 | "PONG", (unsigned int) t.challenge, | ||
3278 | (unsigned int) n->encrypt_key.crc32, GNUNET_CRYPTO_crc32_n (&iv, | ||
3279 | sizeof | ||
3280 | (iv)), | ||
3281 | tp->iv_seed); | ||
3282 | #endif | ||
3283 | /* trigger queue processing */ | ||
3284 | process_encrypted_neighbour_queue (n); | ||
3285 | } | ||
3286 | |||
3287 | |||
3288 | /** | ||
3289 | * We received a PONG message. Validate and update our status. | ||
3290 | * | ||
3291 | * @param n sender of the PONG | ||
3292 | * @param m the encrypted PONG message itself | ||
3293 | * @param ats performance data | ||
3294 | * @param ats_count number of entries in ats (excluding 0-termination) | ||
3295 | */ | ||
3296 | static void | ||
3297 | handle_pong (struct Neighbour *n, const struct PongMessage *m, | ||
3298 | const struct GNUNET_ATS_Information *ats, | ||
3299 | uint32_t ats_count) | ||
3300 | { | ||
3301 | struct PongMessage t; | ||
3302 | struct ConnectNotifyMessage *cnm; | ||
3303 | struct GNUNET_CRYPTO_AesInitializationVector iv; | ||
3304 | char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1]; | ||
3305 | struct GNUNET_ATS_Information *mats; | ||
3306 | size_t size; | ||
3307 | |||
3308 | #if DEBUG_HANDSHAKE | ||
3309 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3310 | "Core service receives `%s' response from `%4s'.\n", "PONG", | ||
3311 | GNUNET_i2s (&n->peer)); | ||
3312 | #endif | ||
3313 | /* mark as garbage, just to be sure */ | ||
3314 | memset (&t, 255, sizeof (t)); | ||
3315 | derive_pong_iv (&iv, &n->decrypt_key, m->iv_seed, n->ping_challenge, | ||
3316 | &my_identity); | ||
3317 | if (GNUNET_OK != | ||
3318 | do_decrypt (n, &iv, &m->challenge, &t.challenge, | ||
3319 | sizeof (struct PongMessage) - ((void *) &m->challenge - | ||
3320 | (void *) m))) | ||
3321 | { | ||
3322 | GNUNET_break_op (0); | ||
3323 | return; | ||
3324 | } | ||
3325 | GNUNET_STATISTICS_update (stats, gettext_noop ("# PONG messages decrypted"), | ||
3326 | 1, GNUNET_NO); | ||
3327 | #if DEBUG_HANDSHAKE | ||
3328 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3329 | "Decrypted `%s' from `%4s' with challenge %u using key %u, IV %u (salt %u)\n", | ||
3330 | "PONG", GNUNET_i2s (&t.target), (unsigned int) t.challenge, | ||
3331 | (unsigned int) n->decrypt_key.crc32, GNUNET_CRYPTO_crc32_n (&iv, | ||
3332 | sizeof | ||
3333 | (iv)), | ||
3334 | m->iv_seed); | ||
3335 | #endif | ||
3336 | if ((0 != memcmp (&t.target, &n->peer, sizeof (struct GNUNET_PeerIdentity))) | ||
3337 | || (n->ping_challenge != t.challenge)) | ||
3338 | { | ||
3339 | /* PONG malformed */ | ||
3340 | #if DEBUG_CORE | ||
3341 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3342 | "Received malformed `%s' wanted sender `%4s' with challenge %u\n", | ||
3343 | "PONG", GNUNET_i2s (&n->peer), | ||
3344 | (unsigned int) n->ping_challenge); | ||
3345 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3346 | "Received malformed `%s' received from `%4s' with challenge %u\n", | ||
3347 | "PONG", GNUNET_i2s (&t.target), (unsigned int) t.challenge); | ||
3348 | #endif | ||
3349 | GNUNET_break_op (n->ping_challenge != t.challenge); | ||
3350 | return; | ||
3351 | } | ||
3352 | switch (n->status) | ||
3353 | { | ||
3354 | case PEER_STATE_DOWN: | ||
3355 | GNUNET_break (0); /* should be impossible */ | ||
3356 | return; | ||
3357 | case PEER_STATE_KEY_SENT: | ||
3358 | GNUNET_break (0); /* should be impossible, how did we decrypt? */ | ||
3359 | return; | ||
3360 | case PEER_STATE_KEY_RECEIVED: | ||
3361 | GNUNET_STATISTICS_update (stats, | ||
3362 | gettext_noop | ||
3363 | ("# Session keys confirmed via PONG"), 1, | ||
3364 | GNUNET_NO); | ||
3365 | n->status = PEER_STATE_KEY_CONFIRMED; | ||
3366 | { | ||
3367 | struct GNUNET_MessageHeader *hdr; | ||
3368 | |||
3369 | hdr = compute_type_map_message (); | ||
3370 | send_type_map_to_neighbour (hdr, &n->peer.hashPubKey, n); | ||
3371 | GNUNET_free (hdr); | ||
3372 | } | ||
3373 | if (n->bw_out_external_limit.value__ != t.inbound_bw_limit.value__) | ||
3374 | { | ||
3375 | n->bw_out_external_limit = t.inbound_bw_limit; | ||
3376 | n->bw_out = | ||
3377 | GNUNET_BANDWIDTH_value_min (n->bw_out_external_limit, | ||
3378 | n->bw_out_internal_limit); | ||
3379 | GNUNET_BANDWIDTH_tracker_update_quota (&n->available_send_window, | ||
3380 | n->bw_out); | ||
3381 | GNUNET_TRANSPORT_set_quota (transport, &n->peer, n->bw_in, n->bw_out); | ||
3382 | } | ||
3383 | #if DEBUG_CORE | ||
3384 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3385 | "Confirmed key via `%s' message for peer `%4s'\n", "PONG", | ||
3386 | GNUNET_i2s (&n->peer)); | ||
3387 | #endif | ||
3388 | if (n->retry_set_key_task != GNUNET_SCHEDULER_NO_TASK) | ||
3389 | { | ||
3390 | GNUNET_SCHEDULER_cancel (n->retry_set_key_task); | ||
3391 | n->retry_set_key_task = GNUNET_SCHEDULER_NO_TASK; | ||
3392 | } | ||
3393 | update_neighbour_performance (n, ats, ats_count); | ||
3394 | size = | ||
3395 | sizeof (struct ConnectNotifyMessage) + | ||
3396 | (n->ats_count) * sizeof (struct GNUNET_ATS_Information); | ||
3397 | if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE) | ||
3398 | { | ||
3399 | GNUNET_break (0); | ||
3400 | /* recovery strategy: throw away performance data */ | ||
3401 | GNUNET_array_grow (n->ats, n->ats_count, 0); | ||
3402 | size = | ||
3403 | sizeof (struct PeerStatusNotifyMessage) + | ||
3404 | n->ats_count * sizeof (struct GNUNET_ATS_Information); | ||
3405 | } | ||
3406 | cnm = (struct ConnectNotifyMessage *) buf; | ||
3407 | cnm->header.size = htons (size); | ||
3408 | cnm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT); | ||
3409 | cnm->ats_count = htonl (n->ats_count); | ||
3410 | cnm->peer = n->peer; | ||
3411 | mats = &cnm->ats; | ||
3412 | memcpy (mats, n->ats, | ||
3413 | n->ats_count * sizeof (struct GNUNET_ATS_Information)); | ||
3414 | mats[n->ats_count].type = htonl (GNUNET_ATS_ARRAY_TERMINATOR); | ||
3415 | mats[n->ats_count].value = htonl (0); | ||
3416 | send_to_all_clients (&cnm->header, GNUNET_NO, | ||
3417 | GNUNET_CORE_OPTION_SEND_CONNECT); | ||
3418 | process_encrypted_neighbour_queue (n); | ||
3419 | /* fall-through! */ | ||
3420 | case PEER_STATE_KEY_CONFIRMED: | ||
3421 | n->last_activity = GNUNET_TIME_absolute_get (); | ||
3422 | if (n->keep_alive_task != GNUNET_SCHEDULER_NO_TASK) | ||
3423 | GNUNET_SCHEDULER_cancel (n->keep_alive_task); | ||
3424 | n->keep_alive_task = | ||
3425 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide | ||
3426 | (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, | ||
3427 | 2), &send_keep_alive, n); | ||
3428 | handle_peer_status_change (n); | ||
3429 | break; | ||
3430 | default: | ||
3431 | GNUNET_break (0); | ||
3432 | break; | ||
3433 | } | ||
3434 | } | ||
3435 | |||
3436 | |||
3437 | /** | ||
3438 | * We received a SET_KEY message. Validate and update | ||
3439 | * our key material and status. | ||
3440 | * | ||
3441 | * @param n the neighbour from which we received message m | ||
3442 | * @param m the set key message we received | ||
3443 | * @param ats performance data | ||
3444 | * @param ats_count number of entries in ats (excluding 0-termination) | ||
3445 | */ | ||
3446 | static void | ||
3447 | handle_set_key (struct Neighbour *n, const struct SetKeyMessage *m, | ||
3448 | const struct GNUNET_ATS_Information *ats, | ||
3449 | uint32_t ats_count) | ||
3450 | { | ||
3451 | struct SetKeyMessage *m_cpy; | ||
3452 | struct GNUNET_TIME_Absolute t; | ||
3453 | struct GNUNET_CRYPTO_AesSessionKey k; | ||
3454 | struct PingMessage *ping; | ||
3455 | struct PongMessage *pong; | ||
3456 | enum PeerStateMachine sender_status; | ||
3457 | |||
3458 | #if DEBUG_CORE | ||
3459 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3460 | "Core service receives `%s' request from `%4s'.\n", "SET_KEY", | ||
3461 | GNUNET_i2s (&n->peer)); | ||
3462 | #endif | ||
3463 | if (n->public_key == NULL) | ||
3464 | { | ||
3465 | if (n->pitr != NULL) | ||
3466 | { | ||
3467 | #if DEBUG_CORE | ||
3468 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3469 | "Ignoring `%s' message due to lack of public key for peer (still trying to obtain one).\n", | ||
3470 | "SET_KEY"); | ||
3471 | #endif | ||
3472 | return; | ||
3473 | } | ||
3474 | #if DEBUG_CORE | ||
3475 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3476 | "Lacking public key for peer, trying to obtain one (handle_set_key).\n"); | ||
3477 | #endif | ||
3478 | m_cpy = GNUNET_malloc (sizeof (struct SetKeyMessage)); | ||
3479 | memcpy (m_cpy, m, sizeof (struct SetKeyMessage)); | ||
3480 | /* lookup n's public key, then try again */ | ||
3481 | GNUNET_assert (n->skm == NULL); | ||
3482 | n->skm = m_cpy; | ||
3483 | n->pitr = | ||
3484 | GNUNET_PEERINFO_iterate (peerinfo, &n->peer, GNUNET_TIME_UNIT_MINUTES, | ||
3485 | &process_hello_retry_handle_set_key, n); | ||
3486 | GNUNET_STATISTICS_update (stats, | ||
3487 | gettext_noop | ||
3488 | ("# SET_KEY messages deferred (need public key)"), | ||
3489 | 1, GNUNET_NO); | ||
3490 | return; | ||
3491 | } | ||
3492 | if (0 != | ||
3493 | memcmp (&m->target, &my_identity, sizeof (struct GNUNET_PeerIdentity))) | ||
3494 | { | ||
3495 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3496 | _ | ||
3497 | ("Received `%s' message that was for `%s', not for me. Ignoring.\n"), | ||
3498 | "SET_KEY", GNUNET_i2s (&m->target)); | ||
3499 | return; | ||
3500 | } | ||
3501 | if ((ntohl (m->purpose.size) != | ||
3502 | sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) + | ||
3503 | sizeof (struct GNUNET_TIME_AbsoluteNBO) + | ||
3504 | sizeof (struct GNUNET_CRYPTO_RsaEncryptedData) + | ||
3505 | sizeof (struct GNUNET_PeerIdentity)) || | ||
3506 | (GNUNET_OK != | ||
3507 | GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_SET_KEY, &m->purpose, | ||
3508 | &m->signature, n->public_key))) | ||
3509 | { | ||
3510 | /* invalid signature */ | ||
3511 | GNUNET_break_op (0); | ||
3512 | return; | ||
3513 | } | ||
3514 | t = GNUNET_TIME_absolute_ntoh (m->creation_time); | ||
3515 | if (((n->status == PEER_STATE_KEY_RECEIVED) || | ||
3516 | (n->status == PEER_STATE_KEY_CONFIRMED)) && | ||
3517 | (t.abs_value < n->decrypt_key_created.abs_value)) | ||
3518 | { | ||
3519 | /* this could rarely happen due to massive re-ordering of | ||
3520 | * messages on the network level, but is most likely either | ||
3521 | * a bug or some adversary messing with us. Report. */ | ||
3522 | GNUNET_break_op (0); | ||
3523 | return; | ||
3524 | } | ||
3525 | #if DEBUG_CORE | ||
3526 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Decrypting key material.\n"); | ||
3527 | #endif | ||
3528 | if ((GNUNET_CRYPTO_rsa_decrypt | ||
3529 | (my_private_key, &m->encrypted_key, &k, | ||
3530 | sizeof (struct GNUNET_CRYPTO_AesSessionKey)) != | ||
3531 | sizeof (struct GNUNET_CRYPTO_AesSessionKey)) || | ||
3532 | (GNUNET_OK != GNUNET_CRYPTO_aes_check_session_key (&k))) | ||
3533 | { | ||
3534 | /* failed to decrypt !? */ | ||
3535 | GNUNET_break_op (0); | ||
3536 | return; | ||
3537 | } | ||
3538 | GNUNET_STATISTICS_update (stats, | ||
3539 | gettext_noop ("# SET_KEY messages decrypted"), 1, | ||
3540 | GNUNET_NO); | ||
3541 | n->decrypt_key = k; | ||
3542 | if (n->decrypt_key_created.abs_value != t.abs_value) | ||
3543 | { | ||
3544 | /* fresh key, reset sequence numbers */ | ||
3545 | n->last_sequence_number_received = 0; | ||
3546 | n->last_packets_bitmap = 0; | ||
3547 | n->decrypt_key_created = t; | ||
3548 | } | ||
3549 | update_neighbour_performance (n, ats, ats_count); | ||
3550 | sender_status = (enum PeerStateMachine) ntohl (m->sender_status); | ||
3551 | switch (n->status) | ||
3552 | { | ||
3553 | case PEER_STATE_DOWN: | ||
3554 | n->status = PEER_STATE_KEY_RECEIVED; | ||
3555 | #if DEBUG_CORE | ||
3556 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3557 | "Responding to `%s' with my own key.\n", "SET_KEY"); | ||
3558 | #endif | ||
3559 | send_key (n); | ||
3560 | break; | ||
3561 | case PEER_STATE_KEY_SENT: | ||
3562 | case PEER_STATE_KEY_RECEIVED: | ||
3563 | n->status = PEER_STATE_KEY_RECEIVED; | ||
3564 | if ((sender_status != PEER_STATE_KEY_RECEIVED) && | ||
3565 | (sender_status != PEER_STATE_KEY_CONFIRMED)) | ||
3566 | { | ||
3567 | #if DEBUG_CORE | ||
3568 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3569 | "Responding to `%s' with my own key (other peer has status %u).\n", | ||
3570 | "SET_KEY", (unsigned int) sender_status); | ||
3571 | #endif | ||
3572 | send_key (n); | ||
3573 | } | ||
3574 | break; | ||
3575 | case PEER_STATE_KEY_CONFIRMED: | ||
3576 | if ((sender_status != PEER_STATE_KEY_RECEIVED) && | ||
3577 | (sender_status != PEER_STATE_KEY_CONFIRMED)) | ||
3578 | { | ||
3579 | #if DEBUG_CORE | ||
3580 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3581 | "Responding to `%s' with my own key (other peer has status %u), I was already fully up.\n", | ||
3582 | "SET_KEY", (unsigned int) sender_status); | ||
3583 | #endif | ||
3584 | send_key (n); | ||
3585 | } | ||
3586 | break; | ||
3587 | default: | ||
3588 | GNUNET_break (0); | ||
3589 | break; | ||
3590 | } | ||
3591 | if (n->pending_ping != NULL) | ||
3592 | { | ||
3593 | ping = n->pending_ping; | ||
3594 | n->pending_ping = NULL; | ||
3595 | handle_ping (n, ping, NULL, 0); | ||
3596 | GNUNET_free (ping); | ||
3597 | } | ||
3598 | if (n->pending_pong != NULL) | ||
3599 | { | ||
3600 | pong = n->pending_pong; | ||
3601 | n->pending_pong = NULL; | ||
3602 | handle_pong (n, pong, NULL, 0); | ||
3603 | GNUNET_free (pong); | ||
3604 | } | ||
3605 | } | ||
3606 | |||
3607 | |||
3608 | /** | ||
3609 | * Send a P2P message to a client. | ||
3610 | * | ||
3611 | * @param sender who sent us the message? | ||
3612 | * @param client who should we give the message to? | ||
3613 | * @param m contains the message to transmit | ||
3614 | * @param msize number of bytes in buf to transmit | ||
3615 | */ | ||
3616 | static void | ||
3617 | send_p2p_message_to_client (struct Neighbour *sender, struct Client *client, | ||
3618 | const void *m, size_t msize) | ||
3619 | { | ||
3620 | size_t size = | ||
3621 | msize + sizeof (struct NotifyTrafficMessage) + | ||
3622 | (sender->ats_count) * sizeof (struct GNUNET_ATS_Information); | ||
3623 | char buf[size]; | ||
3624 | struct NotifyTrafficMessage *ntm; | ||
3625 | struct GNUNET_ATS_Information *ats; | ||
3626 | |||
3627 | GNUNET_assert (GNUNET_YES == sender->is_connected); | ||
3628 | GNUNET_break (sender->status == PEER_STATE_KEY_CONFIRMED); | ||
3629 | if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE) | ||
3630 | { | ||
3631 | GNUNET_break (0); | ||
3632 | /* recovery strategy: throw performance data away... */ | ||
3633 | GNUNET_array_grow (sender->ats, sender->ats_count, 0); | ||
3634 | size = | ||
3635 | msize + sizeof (struct NotifyTrafficMessage) + | ||
3636 | (sender->ats_count) * sizeof (struct GNUNET_ATS_Information); | ||
3637 | } | ||
3638 | #if DEBUG_CORE | ||
3639 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3640 | "Core service passes message from `%4s' of type %u to client.\n", | ||
3641 | GNUNET_i2s (&sender->peer), | ||
3642 | (unsigned int) | ||
3643 | ntohs (((const struct GNUNET_MessageHeader *) m)->type)); | ||
3644 | #endif | ||
3645 | ntm = (struct NotifyTrafficMessage *) buf; | ||
3646 | ntm->header.size = htons (size); | ||
3647 | ntm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND); | ||
3648 | ntm->ats_count = htonl (sender->ats_count); | ||
3649 | ntm->peer = sender->peer; | ||
3650 | ats = &ntm->ats; | ||
3651 | memcpy (ats, sender->ats, | ||
3652 | sizeof (struct GNUNET_ATS_Information) * sender->ats_count); | ||
3653 | ats[sender->ats_count].type = htonl (GNUNET_ATS_ARRAY_TERMINATOR); | ||
3654 | ats[sender->ats_count].value = htonl (0); | ||
3655 | memcpy (&ats[sender->ats_count + 1], m, msize); | ||
3656 | send_to_client (client, &ntm->header, GNUNET_YES); | ||
3657 | } | ||
3658 | |||
3659 | |||
3660 | /** | ||
3661 | * Deliver P2P message to interested clients. | ||
3662 | * | ||
3663 | * @param cls always NULL | ||
3664 | * @param client who sent us the message (struct Neighbour) | ||
3665 | * @param m the message | ||
3666 | */ | ||
3667 | static void | ||
3668 | deliver_message (void *cls, void *client, const struct GNUNET_MessageHeader *m) | ||
3669 | { | ||
3670 | struct Neighbour *sender = client; | ||
3671 | size_t msize = ntohs (m->size); | ||
3672 | char buf[256]; | ||
3673 | struct Client *cpos; | ||
3674 | uint16_t type; | ||
3675 | unsigned int tpos; | ||
3676 | int deliver_full; | ||
3677 | int dropped; | ||
3678 | |||
3679 | GNUNET_break (sender->status == PEER_STATE_KEY_CONFIRMED); | ||
3680 | type = ntohs (m->type); | ||
3681 | #if DEBUG_CORE > 1 | ||
3682 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3683 | "Received encapsulated message of type %u and size %u from `%4s'\n", | ||
3684 | (unsigned int) type, ntohs (m->size), GNUNET_i2s (&sender->peer)); | ||
3685 | #endif | ||
3686 | GNUNET_snprintf (buf, sizeof (buf), | ||
3687 | gettext_noop ("# bytes of messages of type %u received"), | ||
3688 | (unsigned int) type); | ||
3689 | GNUNET_STATISTICS_update (stats, buf, msize, GNUNET_NO); | ||
3690 | if ((GNUNET_MESSAGE_TYPE_CORE_BINARY_TYPE_MAP == type) || | ||
3691 | (GNUNET_MESSAGE_TYPE_CORE_COMPRESSED_TYPE_MAP == type)) | ||
3692 | { | ||
3693 | /* FIXME: update message type map for 'Neighbour' */ | ||
3694 | return; | ||
3695 | } | ||
3696 | dropped = GNUNET_YES; | ||
3697 | cpos = clients; | ||
3698 | while (cpos != NULL) | ||
3699 | { | ||
3700 | deliver_full = GNUNET_NO; | ||
3701 | if (0 != (cpos->options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) | ||
3702 | deliver_full = GNUNET_YES; | ||
3703 | else | ||
3704 | { | ||
3705 | for (tpos = 0; tpos < cpos->tcnt; tpos++) | ||
3706 | { | ||
3707 | if (type != cpos->types[tpos]) | ||
3708 | continue; | ||
3709 | deliver_full = GNUNET_YES; | ||
3710 | break; | ||
3711 | } | ||
3712 | } | ||
3713 | if (GNUNET_YES == deliver_full) | ||
3714 | { | ||
3715 | send_p2p_message_to_client (sender, cpos, m, msize); | ||
3716 | dropped = GNUNET_NO; | ||
3717 | } | ||
3718 | else if (cpos->options & GNUNET_CORE_OPTION_SEND_HDR_INBOUND) | ||
3719 | { | ||
3720 | send_p2p_message_to_client (sender, cpos, m, | ||
3721 | sizeof (struct GNUNET_MessageHeader)); | ||
3722 | } | ||
3723 | cpos = cpos->next; | ||
3724 | } | ||
3725 | if (dropped == GNUNET_YES) | ||
3726 | { | ||
3727 | #if DEBUG_CORE | ||
3728 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3729 | "Message of type %u from `%4s' not delivered to any client.\n", | ||
3730 | (unsigned int) type, GNUNET_i2s (&sender->peer)); | ||
3731 | #endif | ||
3732 | GNUNET_STATISTICS_update (stats, | ||
3733 | gettext_noop | ||
3734 | ("# messages not delivered to any client"), 1, | ||
3735 | GNUNET_NO); | ||
3736 | } | ||
3737 | } | ||
3738 | |||
3739 | |||
3740 | /** | ||
3741 | * We received an encrypted message. Decrypt, validate and | ||
3742 | * pass on to the appropriate clients. | ||
3743 | * | ||
3744 | * @param n target of the message | ||
3745 | * @param m encrypted message | ||
3746 | * @param ats performance data | ||
3747 | * @param ats_count number of entries in ats (excluding 0-termination) | ||
3748 | */ | ||
3749 | static void | ||
3750 | handle_encrypted_message (struct Neighbour *n, const struct EncryptedMessage *m, | ||
3751 | const struct GNUNET_ATS_Information *ats, | ||
3752 | uint32_t ats_count) | ||
3753 | { | ||
3754 | size_t size = ntohs (m->header.size); | ||
3755 | char buf[size]; | ||
3756 | struct EncryptedMessage *pt; /* plaintext */ | ||
3757 | GNUNET_HashCode ph; | ||
3758 | uint32_t snum; | ||
3759 | struct GNUNET_TIME_Absolute t; | ||
3760 | struct GNUNET_CRYPTO_AesInitializationVector iv; | ||
3761 | struct GNUNET_CRYPTO_AuthKey auth_key; | ||
3762 | |||
3763 | #if DEBUG_CORE | ||
3764 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3765 | "Core service receives `%s' request from `%4s'.\n", | ||
3766 | "ENCRYPTED_MESSAGE", GNUNET_i2s (&n->peer)); | ||
3767 | #endif | ||
3768 | /* validate hash */ | ||
3769 | derive_auth_key (&auth_key, &n->decrypt_key, m->iv_seed, | ||
3770 | n->decrypt_key_created); | ||
3771 | GNUNET_CRYPTO_hmac (&auth_key, &m->sequence_number, | ||
3772 | size - ENCRYPTED_HEADER_SIZE, &ph); | ||
3773 | #if DEBUG_HANDSHAKE | ||
3774 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3775 | "Re-Authenticated %u bytes of ciphertext (`%u'): `%s'\n", | ||
3776 | (unsigned int) size - ENCRYPTED_HEADER_SIZE, | ||
3777 | GNUNET_CRYPTO_crc32_n (&m->sequence_number, | ||
3778 | size - ENCRYPTED_HEADER_SIZE), | ||
3779 | GNUNET_h2s (&ph)); | ||
3780 | #endif | ||
3781 | |||
3782 | if (0 != memcmp (&ph, &m->hmac, sizeof (GNUNET_HashCode))) | ||
3783 | { | ||
3784 | /* checksum failed */ | ||
3785 | GNUNET_break_op (0); | ||
3786 | return; | ||
3787 | } | ||
3788 | derive_iv (&iv, &n->decrypt_key, m->iv_seed, &my_identity); | ||
3789 | /* decrypt */ | ||
3790 | if (GNUNET_OK != | ||
3791 | do_decrypt (n, &iv, &m->sequence_number, &buf[ENCRYPTED_HEADER_SIZE], | ||
3792 | size - ENCRYPTED_HEADER_SIZE)) | ||
3793 | return; | ||
3794 | pt = (struct EncryptedMessage *) buf; | ||
3795 | |||
3796 | /* validate sequence number */ | ||
3797 | snum = ntohl (pt->sequence_number); | ||
3798 | if (n->last_sequence_number_received == snum) | ||
3799 | { | ||
3800 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
3801 | "Received duplicate message, ignoring.\n"); | ||
3802 | /* duplicate, ignore */ | ||
3803 | GNUNET_STATISTICS_update (stats, | ||
3804 | gettext_noop ("# bytes dropped (duplicates)"), | ||
3805 | size, GNUNET_NO); | ||
3806 | return; | ||
3807 | } | ||
3808 | if ((n->last_sequence_number_received > snum) && | ||
3809 | (n->last_sequence_number_received - snum > 32)) | ||
3810 | { | ||
3811 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
3812 | "Received ancient out of sequence message, ignoring.\n"); | ||
3813 | /* ancient out of sequence, ignore */ | ||
3814 | GNUNET_STATISTICS_update (stats, | ||
3815 | gettext_noop | ||
3816 | ("# bytes dropped (out of sequence)"), size, | ||
3817 | GNUNET_NO); | ||
3818 | return; | ||
3819 | } | ||
3820 | if (n->last_sequence_number_received > snum) | ||
3821 | { | ||
3822 | unsigned int rotbit = 1 << (n->last_sequence_number_received - snum - 1); | ||
3823 | |||
3824 | if ((n->last_packets_bitmap & rotbit) != 0) | ||
3825 | { | ||
3826 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
3827 | "Received duplicate message, ignoring.\n"); | ||
3828 | GNUNET_STATISTICS_update (stats, | ||
3829 | gettext_noop ("# bytes dropped (duplicates)"), | ||
3830 | size, GNUNET_NO); | ||
3831 | /* duplicate, ignore */ | ||
3832 | return; | ||
3833 | } | ||
3834 | n->last_packets_bitmap |= rotbit; | ||
3835 | } | ||
3836 | if (n->last_sequence_number_received < snum) | ||
3837 | { | ||
3838 | int shift = (snum - n->last_sequence_number_received); | ||
3839 | |||
3840 | if (shift >= 8 * sizeof (n->last_packets_bitmap)) | ||
3841 | n->last_packets_bitmap = 0; | ||
3842 | else | ||
3843 | n->last_packets_bitmap <<= shift; | ||
3844 | n->last_sequence_number_received = snum; | ||
3845 | } | ||
3846 | |||
3847 | /* check timestamp */ | ||
3848 | t = GNUNET_TIME_absolute_ntoh (pt->timestamp); | ||
3849 | if (GNUNET_TIME_absolute_get_duration (t).rel_value > | ||
3850 | MAX_MESSAGE_AGE.rel_value) | ||
3851 | { | ||
3852 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
3853 | _("Message received far too old (%llu ms). Content ignored.\n"), | ||
3854 | GNUNET_TIME_absolute_get_duration (t).rel_value); | ||
3855 | GNUNET_STATISTICS_update (stats, | ||
3856 | gettext_noop | ||
3857 | ("# bytes dropped (ancient message)"), size, | ||
3858 | GNUNET_NO); | ||
3859 | return; | ||
3860 | } | ||
3861 | |||
3862 | /* process decrypted message(s) */ | ||
3863 | if (n->bw_out_external_limit.value__ != pt->inbound_bw_limit.value__) | ||
3864 | { | ||
3865 | #if DEBUG_CORE_SET_QUOTA | ||
3866 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3867 | "Received %u b/s as new inbound limit for peer `%4s'\n", | ||
3868 | (unsigned int) ntohl (pt->inbound_bw_limit.value__), | ||
3869 | GNUNET_i2s (&n->peer)); | ||
3870 | #endif | ||
3871 | n->bw_out_external_limit = pt->inbound_bw_limit; | ||
3872 | n->bw_out = | ||
3873 | GNUNET_BANDWIDTH_value_min (n->bw_out_external_limit, | ||
3874 | n->bw_out_internal_limit); | ||
3875 | GNUNET_BANDWIDTH_tracker_update_quota (&n->available_send_window, | ||
3876 | n->bw_out); | ||
3877 | GNUNET_TRANSPORT_set_quota (transport, &n->peer, n->bw_in, n->bw_out); | ||
3878 | } | ||
3879 | n->last_activity = GNUNET_TIME_absolute_get (); | ||
3880 | if (n->keep_alive_task != GNUNET_SCHEDULER_NO_TASK) | ||
3881 | GNUNET_SCHEDULER_cancel (n->keep_alive_task); | ||
3882 | n->keep_alive_task = | ||
3883 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide | ||
3884 | (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, | ||
3885 | 2), &send_keep_alive, n); | ||
3886 | GNUNET_STATISTICS_update (stats, | ||
3887 | gettext_noop ("# bytes of payload decrypted"), | ||
3888 | size - sizeof (struct EncryptedMessage), GNUNET_NO); | ||
3889 | handle_peer_status_change (n); | ||
3890 | update_neighbour_performance (n, ats, ats_count); | ||
3891 | if (GNUNET_OK != | ||
3892 | GNUNET_SERVER_mst_receive (mst, n, &buf[sizeof (struct EncryptedMessage)], | ||
3893 | size - sizeof (struct EncryptedMessage), | ||
3894 | GNUNET_YES, GNUNET_NO)) | ||
3895 | GNUNET_break_op (0); | ||
3896 | } | ||
3897 | |||
3898 | |||
3899 | /** | ||
3900 | * Function called by the transport for each received message. | ||
3901 | * | ||
3902 | * @param cls closure | ||
3903 | * @param peer (claimed) identity of the other peer | ||
3904 | * @param message the message | ||
3905 | * @param ats performance data | ||
3906 | * @param ats_count number of entries in ats (excluding 0-termination) | ||
3907 | */ | ||
3908 | static void | ||
3909 | handle_transport_receive (void *cls, const struct GNUNET_PeerIdentity *peer, | ||
3910 | const struct GNUNET_MessageHeader *message, | ||
3911 | const struct GNUNET_ATS_Information *ats, | ||
3912 | uint32_t ats_count) | ||
3913 | { | ||
3914 | struct Neighbour *n; | ||
3915 | struct GNUNET_TIME_Absolute now; | ||
3916 | int up; | ||
3917 | uint16_t type; | ||
3918 | uint16_t size; | ||
3919 | int changed; | ||
3920 | |||
3921 | #if DEBUG_CORE > 1 | ||
3922 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3923 | "Received message of type %u from `%4s', demultiplexing.\n", | ||
3924 | (unsigned int) ntohs (message->type), GNUNET_i2s (peer)); | ||
3925 | #endif | ||
3926 | if (0 == memcmp (peer, &my_identity, sizeof (struct GNUNET_PeerIdentity))) | ||
3927 | { | ||
3928 | GNUNET_break (0); | ||
3929 | return; | ||
3930 | } | ||
3931 | n = find_neighbour (peer); | ||
3932 | if ((n == NULL) || (GNUNET_NO == n->is_connected)) | ||
3933 | { | ||
3934 | /* received message from peer that is not connected!? */ | ||
3935 | GNUNET_break (0); | ||
3936 | return; | ||
3937 | } | ||
3938 | changed = GNUNET_NO; | ||
3939 | up = (n->status == PEER_STATE_KEY_CONFIRMED); | ||
3940 | type = ntohs (message->type); | ||
3941 | size = ntohs (message->size); | ||
3942 | switch (type) | ||
3943 | { | ||
3944 | case GNUNET_MESSAGE_TYPE_CORE_SET_KEY: | ||
3945 | if (size != sizeof (struct SetKeyMessage)) | ||
3946 | { | ||
3947 | GNUNET_break_op (0); | ||
3948 | return; | ||
3949 | } | ||
3950 | GNUNET_STATISTICS_update (stats, gettext_noop ("# session keys received"), | ||
3951 | 1, GNUNET_NO); | ||
3952 | handle_set_key (n, (const struct SetKeyMessage *) message, ats, ats_count); | ||
3953 | break; | ||
3954 | case GNUNET_MESSAGE_TYPE_CORE_ENCRYPTED_MESSAGE: | ||
3955 | if (size < | ||
3956 | sizeof (struct EncryptedMessage) + sizeof (struct GNUNET_MessageHeader)) | ||
3957 | { | ||
3958 | GNUNET_break_op (0); | ||
3959 | return; | ||
3960 | } | ||
3961 | if ((n->status != PEER_STATE_KEY_RECEIVED) && | ||
3962 | (n->status != PEER_STATE_KEY_CONFIRMED)) | ||
3963 | { | ||
3964 | GNUNET_STATISTICS_update (stats, | ||
3965 | gettext_noop | ||
3966 | ("# failed to decrypt message (no session key)"), | ||
3967 | 1, GNUNET_NO); | ||
3968 | send_key (n); | ||
3969 | return; | ||
3970 | } | ||
3971 | handle_encrypted_message (n, (const struct EncryptedMessage *) message, ats, | ||
3972 | ats_count); | ||
3973 | break; | ||
3974 | case GNUNET_MESSAGE_TYPE_CORE_PING: | ||
3975 | if (size != sizeof (struct PingMessage)) | ||
3976 | { | ||
3977 | GNUNET_break_op (0); | ||
3978 | return; | ||
3979 | } | ||
3980 | GNUNET_STATISTICS_update (stats, gettext_noop ("# PING messages received"), | ||
3981 | 1, GNUNET_NO); | ||
3982 | if ((n->status != PEER_STATE_KEY_RECEIVED) && | ||
3983 | (n->status != PEER_STATE_KEY_CONFIRMED)) | ||
3984 | { | ||
3985 | #if DEBUG_CORE > 1 | ||
3986 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3987 | "Core service receives `%s' request from `%4s' but have not processed key; marking as pending.\n", | ||
3988 | "PING", GNUNET_i2s (&n->peer)); | ||
3989 | #endif | ||
3990 | GNUNET_free_non_null (n->pending_ping); | ||
3991 | n->pending_ping = GNUNET_malloc (sizeof (struct PingMessage)); | ||
3992 | memcpy (n->pending_ping, message, sizeof (struct PingMessage)); | ||
3993 | return; | ||
3994 | } | ||
3995 | handle_ping (n, (const struct PingMessage *) message, ats, ats_count); | ||
3996 | break; | ||
3997 | case GNUNET_MESSAGE_TYPE_CORE_PONG: | ||
3998 | if (size != sizeof (struct PongMessage)) | ||
3999 | { | ||
4000 | GNUNET_break_op (0); | ||
4001 | return; | ||
4002 | } | ||
4003 | GNUNET_STATISTICS_update (stats, gettext_noop ("# PONG messages received"), | ||
4004 | 1, GNUNET_NO); | ||
4005 | if ((n->status != PEER_STATE_KEY_RECEIVED) && | ||
4006 | (n->status != PEER_STATE_KEY_CONFIRMED)) | ||
4007 | { | ||
4008 | #if DEBUG_CORE > 1 | ||
4009 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
4010 | "Core service receives `%s' request from `%4s' but have not processed key; marking as pending.\n", | ||
4011 | "PONG", GNUNET_i2s (&n->peer)); | ||
4012 | #endif | ||
4013 | GNUNET_free_non_null (n->pending_pong); | ||
4014 | n->pending_pong = GNUNET_malloc (sizeof (struct PongMessage)); | ||
4015 | memcpy (n->pending_pong, message, sizeof (struct PongMessage)); | ||
4016 | return; | ||
4017 | } | ||
4018 | handle_pong (n, (const struct PongMessage *) message, ats, ats_count); | ||
4019 | break; | ||
4020 | default: | ||
4021 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
4022 | _("Unsupported message of type %u received.\n"), | ||
4023 | (unsigned int) type); | ||
4024 | return; | ||
4025 | } | ||
4026 | if (n->status == PEER_STATE_KEY_CONFIRMED) | ||
4027 | { | ||
4028 | now = GNUNET_TIME_absolute_get (); | ||
4029 | n->last_activity = now; | ||
4030 | changed = GNUNET_YES; | ||
4031 | if (!up) | ||
4032 | { | ||
4033 | GNUNET_STATISTICS_update (stats, gettext_noop ("# established sessions"), | ||
4034 | 1, GNUNET_NO); | ||
4035 | n->time_established = now; | ||
4036 | } | ||
4037 | if (n->keep_alive_task != GNUNET_SCHEDULER_NO_TASK) | ||
4038 | GNUNET_SCHEDULER_cancel (n->keep_alive_task); | ||
4039 | n->keep_alive_task = | ||
4040 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide | ||
4041 | (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, | ||
4042 | 2), &send_keep_alive, n); | ||
4043 | } | ||
4044 | if (changed) | ||
4045 | handle_peer_status_change (n); | ||
4046 | } | ||
4047 | |||
4048 | |||
4049 | /** | ||
4050 | * Function that recalculates the bandwidth quota for the | ||
4051 | * given neighbour and transmits it to the transport service. | ||
4052 | * | ||
4053 | * @param cls neighbour for the quota update | ||
4054 | * @param tc context | ||
4055 | */ | ||
4056 | static void | ||
4057 | neighbour_quota_update (void *cls, | ||
4058 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
4059 | { | ||
4060 | struct Neighbour *n = cls; | ||
4061 | struct GNUNET_BANDWIDTH_Value32NBO q_in; | ||
4062 | struct GNUNET_BANDWIDTH_Value32NBO q_out; | ||
4063 | struct GNUNET_BANDWIDTH_Value32NBO q_out_min; | ||
4064 | double pref_rel; | ||
4065 | double share; | ||
4066 | unsigned long long distributable; | ||
4067 | uint64_t need_per_peer; | ||
4068 | uint64_t need_per_second; | ||
4069 | unsigned int neighbour_count; | ||
4070 | |||
4071 | #if DEBUG_CORE > 1 | ||
4072 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
4073 | "Neighbour quota update calculation running for peer `%4s'\n", | ||
4074 | GNUNET_i2s (&n->peer)); | ||
4075 | #endif | ||
4076 | n->quota_update_task = GNUNET_SCHEDULER_NO_TASK; | ||
4077 | /* calculate relative preference among all neighbours; | ||
4078 | * divides by a bit more to avoid division by zero AND to | ||
4079 | * account for possibility of new neighbours joining any time | ||
4080 | * AND to convert to double... */ | ||
4081 | neighbour_count = GNUNET_CONTAINER_multihashmap_size (neighbours); | ||
4082 | if (neighbour_count == 0) | ||
4083 | return; | ||
4084 | if (preference_sum == 0) | ||
4085 | { | ||
4086 | pref_rel = 1.0 / (double) neighbour_count; | ||
4087 | } | ||
4088 | else | ||
4089 | { | ||
4090 | pref_rel = (double) n->current_preference / preference_sum; | ||
4091 | } | ||
4092 | need_per_peer = | ||
4093 | GNUNET_BANDWIDTH_value_get_available_until (MIN_BANDWIDTH_PER_PEER, | ||
4094 | GNUNET_TIME_UNIT_SECONDS); | ||
4095 | need_per_second = need_per_peer * neighbour_count; | ||
4096 | |||
4097 | /* calculate inbound bandwidth per peer */ | ||
4098 | distributable = 0; | ||
4099 | if (bandwidth_target_in_bps > need_per_second) | ||
4100 | distributable = bandwidth_target_in_bps - need_per_second; | ||
4101 | share = distributable * pref_rel; | ||
4102 | if (share + need_per_peer > UINT32_MAX) | ||
4103 | q_in = GNUNET_BANDWIDTH_value_init (UINT32_MAX); | ||
4104 | else | ||
4105 | q_in = GNUNET_BANDWIDTH_value_init (need_per_peer + (uint32_t) share); | ||
4106 | |||
4107 | /* calculate outbound bandwidth per peer */ | ||
4108 | distributable = 0; | ||
4109 | if (bandwidth_target_out_bps > need_per_second) | ||
4110 | distributable = bandwidth_target_out_bps - need_per_second; | ||
4111 | share = distributable * pref_rel; | ||
4112 | if (share + need_per_peer > UINT32_MAX) | ||
4113 | q_out = GNUNET_BANDWIDTH_value_init (UINT32_MAX); | ||
4114 | else | ||
4115 | q_out = GNUNET_BANDWIDTH_value_init (need_per_peer + (uint32_t) share); | ||
4116 | n->bw_out_internal_limit = q_out; | ||
4117 | |||
4118 | q_out_min = | ||
4119 | GNUNET_BANDWIDTH_value_min (n->bw_out_external_limit, | ||
4120 | n->bw_out_internal_limit); | ||
4121 | GNUNET_BANDWIDTH_tracker_update_quota (&n->available_send_window, n->bw_out); | ||
4122 | |||
4123 | /* check if we want to disconnect for good due to inactivity */ | ||
4124 | if ((GNUNET_TIME_absolute_get_duration (get_neighbour_timeout (n)).rel_value > | ||
4125 | 0) && | ||
4126 | (GNUNET_TIME_absolute_get_duration (n->time_established).rel_value > | ||
4127 | GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value)) | ||
4128 | { | ||
4129 | #if DEBUG_CORE | ||
4130 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
4131 | "Forcing disconnect of `%4s' due to inactivity\n", | ||
4132 | GNUNET_i2s (&n->peer)); | ||
4133 | #endif | ||
4134 | GNUNET_STATISTICS_update (stats, | ||
4135 | gettext_noop ("# peers disconnected due to inactivity"), 1, | ||
4136 | GNUNET_NO); | ||
4137 | q_in = GNUNET_BANDWIDTH_value_init (0); /* force disconnect */ | ||
4138 | } | ||
4139 | #if DEBUG_CORE_QUOTA | ||
4140 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
4141 | "Current quota for `%4s' is %u/%llu b/s in (old: %u b/s) / %u out (%u internal)\n", | ||
4142 | GNUNET_i2s (&n->peer), (unsigned int) ntohl (q_in.value__), | ||
4143 | bandwidth_target_out_bps, (unsigned int) ntohl (n->bw_in.value__), | ||
4144 | (unsigned int) ntohl (n->bw_out.value__), | ||
4145 | (unsigned int) ntohl (n->bw_out_internal_limit.value__)); | ||
4146 | #endif | ||
4147 | if ((n->bw_in.value__ != q_in.value__) || | ||
4148 | (n->bw_out.value__ != q_out_min.value__)) | ||
4149 | { | ||
4150 | if (n->bw_in.value__ != q_in.value__) | ||
4151 | n->bw_in = q_in; | ||
4152 | if (n->bw_out.value__ != q_out_min.value__) | ||
4153 | n->bw_out = q_out_min; | ||
4154 | if (GNUNET_YES == n->is_connected) | ||
4155 | GNUNET_TRANSPORT_set_quota (transport, &n->peer, n->bw_in, n->bw_out); | ||
4156 | handle_peer_status_change (n); | ||
4157 | } | ||
4158 | schedule_quota_update (n); | ||
4159 | } | ||
4160 | |||
4161 | |||
4162 | /** | ||
4163 | * Function called by transport to notify us that | ||
4164 | * a peer connected to us (on the network level). | ||
4165 | * | ||
4166 | * @param cls closure | ||
4167 | * @param peer the peer that connected | ||
4168 | * @param ats performance data | ||
4169 | * @param ats_count number of entries in ats (excluding 0-termination) | ||
4170 | */ | ||
4171 | static void | ||
4172 | handle_transport_notify_connect (void *cls, | ||
4173 | const struct GNUNET_PeerIdentity *peer, | ||
4174 | const struct GNUNET_ATS_Information | ||
4175 | *ats, uint32_t ats_count) | ||
4176 | { | ||
4177 | struct Neighbour *n; | ||
4178 | |||
4179 | if (0 == memcmp (peer, &my_identity, sizeof (struct GNUNET_PeerIdentity))) | ||
4180 | { | ||
4181 | GNUNET_break (0); | ||
4182 | return; | ||
4183 | } | ||
4184 | n = find_neighbour (peer); | ||
4185 | if (n != NULL) | ||
4186 | { | ||
4187 | if (GNUNET_YES == n->is_connected) | ||
4188 | { | ||
4189 | /* duplicate connect notification!? */ | ||
4190 | GNUNET_break (0); | ||
4191 | return; | ||
4192 | } | ||
4193 | } | ||
4194 | else | ||
4195 | { | ||
4196 | n = create_neighbour (peer); | ||
4197 | } | ||
4198 | GNUNET_STATISTICS_update (stats, | ||
4199 | gettext_noop ("# peers connected (transport)"), 1, | ||
4200 | GNUNET_NO); | ||
4201 | n->is_connected = GNUNET_YES; | ||
4202 | update_neighbour_performance (n, ats, ats_count); | ||
4203 | GNUNET_BANDWIDTH_tracker_init (&n->available_send_window, n->bw_out, | ||
4204 | MAX_WINDOW_TIME_S); | ||
4205 | #if DEBUG_CORE | ||
4206 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received connection from `%4s'.\n", | ||
4207 | GNUNET_i2s (&n->peer)); | ||
4208 | #endif | ||
4209 | GNUNET_TRANSPORT_set_quota (transport, &n->peer, n->bw_in, n->bw_out); | ||
4210 | send_key (n); | ||
4211 | } | ||
4212 | |||
4213 | |||
4214 | /** | ||
4215 | * Function called by transport telling us that a peer | ||
4216 | * disconnected. | ||
4217 | * | ||
4218 | * @param cls closure | ||
4219 | * @param peer the peer that disconnected | ||
4220 | */ | ||
4221 | static void | ||
4222 | handle_transport_notify_disconnect (void *cls, | ||
4223 | const struct GNUNET_PeerIdentity *peer) | ||
4224 | { | ||
4225 | struct DisconnectNotifyMessage cnm; | ||
4226 | struct Neighbour *n; | ||
4227 | struct ClientActiveRequest *car; | ||
4228 | struct GNUNET_TIME_Relative left; | ||
4229 | |||
4230 | #if DEBUG_CORE | ||
4231 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
4232 | "Peer `%4s' disconnected from us; received notification from transport.\n", | ||
4233 | GNUNET_i2s (peer)); | ||
4234 | #endif | ||
4235 | n = find_neighbour (peer); | ||
4236 | if (n == NULL) | ||
4237 | { | ||
4238 | GNUNET_break (0); | ||
4239 | return; | ||
4240 | } | ||
4241 | GNUNET_break (n->is_connected == GNUNET_YES); | ||
4242 | if (n->status == PEER_STATE_KEY_CONFIRMED) | ||
4243 | { | ||
4244 | GNUNET_STATISTICS_update (stats, | ||
4245 | gettext_noop ("# peers disconnected due to transport disconnect"), 1, | ||
4246 | GNUNET_NO); | ||
4247 | cnm.header.size = htons (sizeof (struct DisconnectNotifyMessage)); | ||
4248 | cnm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_DISCONNECT); | ||
4249 | cnm.reserved = htonl (0); | ||
4250 | cnm.peer = *peer; | ||
4251 | send_to_all_clients (&cnm.header, GNUNET_NO, | ||
4252 | GNUNET_CORE_OPTION_SEND_DISCONNECT); | ||
4253 | GNUNET_STATISTICS_update (stats, gettext_noop ("# established sessions"), | ||
4254 | -1, GNUNET_NO); | ||
4255 | } | ||
4256 | |||
4257 | /* On transport disconnect transport doesn't cancel requests, so must do so here. */ | ||
4258 | if (n->th != NULL) | ||
4259 | { | ||
4260 | GNUNET_TRANSPORT_notify_transmit_ready_cancel (n->th); | ||
4261 | n->th = NULL; | ||
4262 | } | ||
4263 | if (GNUNET_SCHEDULER_NO_TASK != n->keep_alive_task) | ||
4264 | { | ||
4265 | GNUNET_SCHEDULER_cancel (n->keep_alive_task); | ||
4266 | n->keep_alive_task = GNUNET_SCHEDULER_NO_TASK; | ||
4267 | } | ||
4268 | n->is_connected = GNUNET_NO; | ||
4269 | n->status = PEER_STATE_DOWN; | ||
4270 | while (NULL != (car = n->active_client_request_head)) | ||
4271 | { | ||
4272 | GNUNET_CONTAINER_DLL_remove (n->active_client_request_head, | ||
4273 | n->active_client_request_tail, car); | ||
4274 | GNUNET_assert (GNUNET_YES == | ||
4275 | GNUNET_CONTAINER_multihashmap_remove (car->client->requests, | ||
4276 | &n->peer.hashPubKey, | ||
4277 | car)); | ||
4278 | GNUNET_free (car); | ||
4279 | } | ||
4280 | |||
4281 | GNUNET_STATISTICS_update (stats, | ||
4282 | gettext_noop ("# peers connected (transport)"), -1, | ||
4283 | GNUNET_NO); | ||
4284 | if (n->dead_clean_task != GNUNET_SCHEDULER_NO_TASK) | ||
4285 | GNUNET_SCHEDULER_cancel (n->dead_clean_task); | ||
4286 | left = | ||
4287 | GNUNET_TIME_relative_subtract (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, | ||
4288 | GNUNET_CONSTANTS_DISCONNECT_SESSION_TIMEOUT); | ||
4289 | n->last_activity = | ||
4290 | GNUNET_TIME_absolute_subtract (GNUNET_TIME_absolute_get (), left); | ||
4291 | n->dead_clean_task = | ||
4292 | GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_DISCONNECT_SESSION_TIMEOUT, | ||
4293 | &consider_free_task, n); | ||
4294 | } | ||
4295 | |||
4296 | |||
4297 | /** | ||
4298 | * Wrapper around 'free_neighbour'; helper for 'cleaning_task'. | ||
4299 | */ | ||
4300 | static int | ||
4301 | free_neighbour_helper (void *cls, const GNUNET_HashCode * key, void *value) | ||
4302 | { | ||
4303 | struct Neighbour *n = value; | ||
4304 | |||
4305 | free_neighbour (n); | ||
4306 | return GNUNET_OK; | ||
4307 | } | ||
4308 | |||
4309 | |||
4310 | /** | ||
4311 | * Last task run during shutdown. Disconnects us from | ||
4312 | * the transport. | ||
4313 | */ | ||
4314 | static void | ||
4315 | cleaning_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
4316 | { | ||
4317 | struct Client *c; | ||
4318 | |||
4319 | #if DEBUG_CORE | ||
4320 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Core service shutting down.\n"); | ||
4321 | #endif | ||
4322 | GNUNET_assert (transport != NULL); | ||
4323 | GNUNET_TRANSPORT_disconnect (transport); | ||
4324 | transport = NULL; | ||
4325 | GNUNET_CONTAINER_multihashmap_iterate (neighbours, &free_neighbour_helper, | ||
4326 | NULL); | ||
4327 | GNUNET_CONTAINER_multihashmap_destroy (neighbours); | ||
4328 | neighbours = NULL; | ||
4329 | GNUNET_STATISTICS_set (stats, gettext_noop ("# neighbour entries allocated"), | ||
4330 | 0, GNUNET_NO); | ||
4331 | GNUNET_SERVER_notification_context_destroy (notifier); | ||
4332 | notifier = NULL; | ||
4333 | while (NULL != (c = clients)) | ||
4334 | handle_client_disconnect (NULL, c->client_handle); | ||
4335 | if (my_private_key != NULL) | ||
4336 | GNUNET_CRYPTO_rsa_key_free (my_private_key); | ||
4337 | if (stats != NULL) | ||
4338 | GNUNET_STATISTICS_destroy (stats, GNUNET_NO); | ||
4339 | if (peerinfo != NULL) | ||
4340 | GNUNET_PEERINFO_disconnect (peerinfo); | ||
4341 | if (mst != NULL) | ||
4342 | GNUNET_SERVER_mst_destroy (mst); | ||
4343 | } | ||
4344 | |||
4345 | |||
4346 | /** | ||
4347 | * Initiate core service. | ||
4348 | * | ||
4349 | * @param cls closure | ||
4350 | * @param server the initialized server | ||
4351 | * @param c configuration to use | ||
4352 | */ | ||
4353 | static void | ||
4354 | run (void *cls, struct GNUNET_SERVER_Handle *server, | ||
4355 | const struct GNUNET_CONFIGURATION_Handle *c) | ||
4356 | { | ||
4357 | static const struct GNUNET_SERVER_MessageHandler handlers[] = { | ||
4358 | {&handle_client_init, NULL, | ||
4359 | GNUNET_MESSAGE_TYPE_CORE_INIT, 0}, | ||
4360 | {&handle_client_iterate_peers, NULL, | ||
4361 | GNUNET_MESSAGE_TYPE_CORE_ITERATE_PEERS, | ||
4362 | sizeof (struct GNUNET_MessageHeader)}, | ||
4363 | {&handle_client_have_peer, NULL, | ||
4364 | GNUNET_MESSAGE_TYPE_CORE_PEER_CONNECTED, | ||
4365 | sizeof (struct GNUNET_MessageHeader) + | ||
4366 | sizeof (struct GNUNET_PeerIdentity)}, | ||
4367 | {&handle_client_send_request, NULL, | ||
4368 | GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST, | ||
4369 | sizeof (struct SendMessageRequest)}, | ||
4370 | {&handle_client_send, NULL, | ||
4371 | GNUNET_MESSAGE_TYPE_CORE_SEND, 0}, | ||
4372 | {NULL, NULL, 0, 0} | ||
4373 | }; | ||
4374 | char *keyfile; | ||
4375 | |||
4376 | cfg = c; | ||
4377 | /* parse configuration */ | ||
4378 | if ((GNUNET_OK != | ||
4379 | GNUNET_CONFIGURATION_get_value_number (c, "CORE", "TOTAL_QUOTA_IN", | ||
4380 | &bandwidth_target_in_bps)) || | ||
4381 | (GNUNET_OK != | ||
4382 | GNUNET_CONFIGURATION_get_value_number (c, "CORE", "TOTAL_QUOTA_OUT", | ||
4383 | &bandwidth_target_out_bps)) || | ||
4384 | (GNUNET_OK != | ||
4385 | GNUNET_CONFIGURATION_get_value_filename (c, "GNUNETD", "HOSTKEY", | ||
4386 | &keyfile))) | ||
4387 | { | ||
4388 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
4389 | _ | ||
4390 | ("Core service is lacking key configuration settings. Exiting.\n")); | ||
4391 | GNUNET_SCHEDULER_shutdown (); | ||
4392 | return; | ||
4393 | } | ||
4394 | peerinfo = GNUNET_PEERINFO_connect (cfg); | ||
4395 | if (NULL == peerinfo) | ||
4396 | { | ||
4397 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
4398 | _("Could not access PEERINFO service. Exiting.\n")); | ||
4399 | GNUNET_SCHEDULER_shutdown (); | ||
4400 | GNUNET_free (keyfile); | ||
4401 | return; | ||
4402 | } | ||
4403 | my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); | ||
4404 | GNUNET_free (keyfile); | ||
4405 | if (my_private_key == NULL) | ||
4406 | { | ||
4407 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
4408 | _("Core service could not access hostkey. Exiting.\n")); | ||
4409 | GNUNET_PEERINFO_disconnect (peerinfo); | ||
4410 | GNUNET_SCHEDULER_shutdown (); | ||
4411 | return; | ||
4412 | } | ||
4413 | neighbours = GNUNET_CONTAINER_multihashmap_create (128); | ||
4414 | GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key); | ||
4415 | GNUNET_CRYPTO_hash (&my_public_key, sizeof (my_public_key), | ||
4416 | &my_identity.hashPubKey); | ||
4417 | self.public_key = &my_public_key; | ||
4418 | self.peer = my_identity; | ||
4419 | self.last_activity = GNUNET_TIME_UNIT_FOREVER_ABS; | ||
4420 | self.status = PEER_STATE_KEY_CONFIRMED; | ||
4421 | self.is_connected = GNUNET_YES; | ||
4422 | /* setup notification */ | ||
4423 | notifier = | ||
4424 | GNUNET_SERVER_notification_context_create (server, MAX_NOTIFY_QUEUE); | ||
4425 | GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL); | ||
4426 | /* setup transport connection */ | ||
4427 | transport = | ||
4428 | GNUNET_TRANSPORT_connect (cfg, &my_identity, NULL, | ||
4429 | &handle_transport_receive, | ||
4430 | &handle_transport_notify_connect, | ||
4431 | &handle_transport_notify_disconnect); | ||
4432 | GNUNET_assert (NULL != transport); | ||
4433 | stats = GNUNET_STATISTICS_create ("core", cfg); | ||
4434 | mst = GNUNET_SERVER_mst_create (&deliver_message, NULL); | ||
4435 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleaning_task, | ||
4436 | NULL); | ||
4437 | /* process client requests */ | ||
4438 | GNUNET_SERVER_add_handlers (server, handlers); | ||
4439 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Core service of `%4s' ready.\n"), | ||
4440 | GNUNET_i2s (&my_identity)); | ||
4441 | } | ||
4442 | |||
4443 | |||
4444 | |||
4445 | /** | ||
4446 | * The main function for the transport service. | ||
4447 | * | ||
4448 | * @param argc number of arguments from the command line | ||
4449 | * @param argv command line arguments | ||
4450 | * @return 0 ok, 1 on error | ||
4451 | */ | ||
4452 | int | ||
4453 | main (int argc, char *const *argv) | ||
4454 | { | ||
4455 | return (GNUNET_OK == | ||
4456 | GNUNET_SERVICE_run (argc, argv, "core", GNUNET_SERVICE_OPTION_NONE, | ||
4457 | &run, NULL)) ? 0 : 1; | ||
4458 | } | ||
4459 | |||
4460 | /* end of gnunet-service-core.c */ | ||