diff options
Diffstat (limited to 'src/core/gnunet-service-core.c')
-rw-r--r-- | src/core/gnunet-service-core.c | 2859 |
1 files changed, 2859 insertions, 0 deletions
diff --git a/src/core/gnunet-service-core.c b/src/core/gnunet-service-core.c new file mode 100644 index 000000000..e9e076bcc --- /dev/null +++ b/src/core/gnunet-service-core.c | |||
@@ -0,0 +1,2859 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2009 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 2, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file core/gnunet-service-core.c | ||
23 | * @brief high-level P2P messaging | ||
24 | * @author Christian Grothoff | ||
25 | * | ||
26 | * TODO: | ||
27 | * TESTING: | ||
28 | * - write test for basic core functions: | ||
29 | * + connect to peer | ||
30 | * + transmit (encrypted) message [with handshake] | ||
31 | * + receive (encrypted) message, forward plaintext to clients | ||
32 | * POST-TESTING: | ||
33 | * - revisit API (which arguments are used, needed)? | ||
34 | * - add code to bound queue size when handling client's SEND message | ||
35 | * - add code to bound message queue size when passing messages to clients | ||
36 | * - add code to discard_expired_messages | ||
37 | * - add code to re-transmit key if first attempt failed | ||
38 | * + timeout on connect / key exchange, etc. | ||
39 | * + timeout for automatic re-try, etc. | ||
40 | * - add code to give up re-transmission of key if many attempts fail | ||
41 | * - add code to send PINGs if we are about to time-out otherwise | ||
42 | * ? add heuristic to do another send_key in "handle_set_key" | ||
43 | * in case previous attempt failed / didn't work / persist | ||
44 | * (but don't do it always to avoid storm of SET_KEY's going | ||
45 | * back and forth!) --- alternatively, add "status" field | ||
46 | * of the other peer to the set key message, that way we'd | ||
47 | * know for sure! | ||
48 | * - check that hostkey used by transport (for HELLOs) is the | ||
49 | * same as the hostkey that we are using! | ||
50 | * - free list of clients on exit | ||
51 | * - topology management: | ||
52 | * + bootstrapping (transport offer hello, plugins) | ||
53 | * + internal neighbour selection | ||
54 | * + update bandwidth usage statistics | ||
55 | * + bandwidth allocation (transport set quota) | ||
56 | * - optimize lookup (many O(n) list traversals | ||
57 | * could ideally be changed to O(1) hash map lookups) | ||
58 | */ | ||
59 | #include "platform.h" | ||
60 | #include "gnunet_util_lib.h" | ||
61 | #include "gnunet_hello_lib.h" | ||
62 | #include "gnunet_peerinfo_service.h" | ||
63 | #include "gnunet_protocols.h" | ||
64 | #include "gnunet_signatures.h" | ||
65 | #include "gnunet_transport_service.h" | ||
66 | #include "core.h" | ||
67 | |||
68 | |||
69 | /** | ||
70 | * Receive and send buffer windows grow over time. For | ||
71 | * how long can 'unused' bandwidth accumulate before we | ||
72 | * need to cap it? (specified in ms). | ||
73 | */ | ||
74 | #define MAX_WINDOW_TIME (5 * 60 * 1000) | ||
75 | |||
76 | |||
77 | /** | ||
78 | * Amount of bytes per minute (in/out) to assume initially | ||
79 | * (before either peer has communicated any particular | ||
80 | * preference). Should be rather low. | ||
81 | */ | ||
82 | #define DEFAULT_BPM_IN_OUT 2048 | ||
83 | |||
84 | |||
85 | /** | ||
86 | * What is the maximum delay for a SET_KEY message? | ||
87 | */ | ||
88 | #define MAX_SET_KEY_DELAY GNUNET_TIME_UNIT_SECONDS | ||
89 | |||
90 | |||
91 | /** | ||
92 | * What how long do we wait for SET_KEY confirmation initially? | ||
93 | */ | ||
94 | #define INITIAL_SET_KEY_RETRY_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 3) | ||
95 | |||
96 | |||
97 | /** | ||
98 | * What is the maximum delay for a PING message? | ||
99 | */ | ||
100 | #define MAX_PING_DELAY GNUNET_TIME_UNIT_SECONDS | ||
101 | |||
102 | |||
103 | /** | ||
104 | * What is the maximum delay for a PONG message? | ||
105 | */ | ||
106 | #define MAX_PONG_DELAY GNUNET_TIME_UNIT_SECONDS | ||
107 | |||
108 | |||
109 | /** | ||
110 | * What is the priority for a SET_KEY message? | ||
111 | */ | ||
112 | #define SET_KEY_PRIORITY 0xFFFFFF | ||
113 | |||
114 | |||
115 | /** | ||
116 | * What is the priority for a PING message? | ||
117 | */ | ||
118 | #define PING_PRIORITY 0xFFFFFF | ||
119 | |||
120 | |||
121 | /** | ||
122 | * What is the priority for a PONG message? | ||
123 | */ | ||
124 | #define PONG_PRIORITY 0xFFFFFF | ||
125 | |||
126 | |||
127 | /** | ||
128 | * What is the maximum age of a message for us to consider | ||
129 | * processing it? Note that this looks at the timestamp used | ||
130 | * by the other peer, so clock skew between machines does | ||
131 | * come into play here. So this should be picked high enough | ||
132 | * so that a little bit of clock skew does not prevent peers | ||
133 | * from connecting to us. | ||
134 | */ | ||
135 | #define MAX_MESSAGE_AGE GNUNET_TIME_UNIT_DAYS | ||
136 | |||
137 | |||
138 | /** | ||
139 | * What is the maximum size for encrypted messages? Note that this | ||
140 | * number imposes a clear limit on the maximum size of any message. | ||
141 | * Set to a value close to 64k but not so close that transports will | ||
142 | * have trouble with their headers. | ||
143 | */ | ||
144 | #define MAX_ENCRYPTED_MESSAGE_SIZE (63 * 1024) | ||
145 | |||
146 | |||
147 | /** | ||
148 | * State machine for our P2P encryption handshake. Everyone starts in | ||
149 | * "DOWN", if we receive the other peer's key (other peer initiated) | ||
150 | * we start in state RECEIVED (since we will immediately send our | ||
151 | * own); otherwise we start in SENT. If we get back a PONG from | ||
152 | * within either state, we move up to CONFIRMED (the PONG will always | ||
153 | * be sent back encrypted with the key we sent to the other peer). | ||
154 | */ | ||
155 | enum PeerStateMachine | ||
156 | { | ||
157 | PEER_STATE_DOWN, | ||
158 | PEER_STATE_KEY_SENT, | ||
159 | PEER_STATE_KEY_RECEIVED, | ||
160 | PEER_STATE_KEY_CONFIRMED | ||
161 | }; | ||
162 | |||
163 | |||
164 | /** | ||
165 | * Number of bytes (at the beginning) of "struct EncryptedMessage" | ||
166 | * that are NOT encrypted. | ||
167 | */ | ||
168 | #define ENCRYPTED_HEADER_SIZE (sizeof(struct GNUNET_MessageHeader) + sizeof(uint32_t) + sizeof(GNUNET_HashCode)) | ||
169 | |||
170 | /** | ||
171 | * Encapsulation for encrypted messages exchanged between | ||
172 | * peers. Followed by the actual encrypted data. | ||
173 | */ | ||
174 | struct EncryptedMessage | ||
175 | { | ||
176 | /** | ||
177 | * Message type is either CORE_ENCRYPTED_MESSAGE. | ||
178 | */ | ||
179 | struct GNUNET_MessageHeader header; | ||
180 | |||
181 | /** | ||
182 | * Always zero. | ||
183 | */ | ||
184 | uint32_t reserved GNUNET_PACKED; | ||
185 | |||
186 | /** | ||
187 | * Hash of the plaintext, used to verify message integrity; | ||
188 | * ALSO used as the IV for the symmetric cipher! Everything | ||
189 | * after this hash will be encrypted. ENCRYPTED_HEADER_SIZE | ||
190 | * must be set to the offset of the next field. | ||
191 | */ | ||
192 | GNUNET_HashCode plaintext_hash; | ||
193 | |||
194 | /** | ||
195 | * Sequence number, in network byte order. This field | ||
196 | * must be the first encrypted/decrypted field and the | ||
197 | * first byte that is hashed for the plaintext hash. | ||
198 | */ | ||
199 | uint32_t sequence_number GNUNET_PACKED; | ||
200 | |||
201 | /** | ||
202 | * Desired bandwidth (how much we should send to this | ||
203 | * peer / how much is the sender willing to receive), | ||
204 | * in bytes per minute. | ||
205 | */ | ||
206 | uint32_t inbound_bpm_limit GNUNET_PACKED; | ||
207 | |||
208 | /** | ||
209 | * Timestamp. Used to prevent reply of ancient messages | ||
210 | * (recent messages are caught with the sequence number). | ||
211 | */ | ||
212 | struct GNUNET_TIME_AbsoluteNBO timestamp; | ||
213 | |||
214 | }; | ||
215 | |||
216 | /** | ||
217 | * We're sending an (encrypted) PING to the other peer to check if he | ||
218 | * can decrypt. The other peer should respond with a PONG with the | ||
219 | * same content, except this time encrypted with the receiver's key. | ||
220 | */ | ||
221 | struct PingMessage | ||
222 | { | ||
223 | /** | ||
224 | * Message type is either CORE_PING or CORE_PONG. | ||
225 | */ | ||
226 | struct GNUNET_MessageHeader header; | ||
227 | |||
228 | /** | ||
229 | * Random number chosen to make reply harder. | ||
230 | */ | ||
231 | uint32_t challenge GNUNET_PACKED; | ||
232 | |||
233 | /** | ||
234 | * Intended target of the PING, used primarily to check | ||
235 | * that decryption actually worked. | ||
236 | */ | ||
237 | struct GNUNET_PeerIdentity target; | ||
238 | }; | ||
239 | |||
240 | |||
241 | /** | ||
242 | * Message transmitted to set (or update) a session key. | ||
243 | */ | ||
244 | struct SetKeyMessage | ||
245 | { | ||
246 | |||
247 | /** | ||
248 | * Message type is either CORE_SET_KEY. | ||
249 | */ | ||
250 | struct GNUNET_MessageHeader header; | ||
251 | |||
252 | /** | ||
253 | * Status of the sender (should be in "enum PeerStateMachine"), nbo. | ||
254 | */ | ||
255 | int32_t sender_status GNUNET_PACKED; | ||
256 | |||
257 | /** | ||
258 | * Purpose of the signature, will be | ||
259 | * GNUNET_SIGNATURE_PURPOSE_SET_KEY. | ||
260 | */ | ||
261 | struct GNUNET_CRYPTO_RsaSignaturePurpose purpose; | ||
262 | |||
263 | /** | ||
264 | * At what time was this key created? | ||
265 | */ | ||
266 | struct GNUNET_TIME_AbsoluteNBO creation_time; | ||
267 | |||
268 | /** | ||
269 | * The encrypted session key. | ||
270 | */ | ||
271 | struct GNUNET_CRYPTO_RsaEncryptedData encrypted_key; | ||
272 | |||
273 | /** | ||
274 | * Who is the intended recipient? | ||
275 | */ | ||
276 | struct GNUNET_PeerIdentity target; | ||
277 | |||
278 | /** | ||
279 | * Signature of the stuff above (starting at purpose). | ||
280 | */ | ||
281 | struct GNUNET_CRYPTO_RsaSignature signature; | ||
282 | |||
283 | }; | ||
284 | |||
285 | |||
286 | /** | ||
287 | * Message waiting for transmission. This struct | ||
288 | * is followed by the actual content of the message. | ||
289 | */ | ||
290 | struct MessageEntry | ||
291 | { | ||
292 | |||
293 | /** | ||
294 | * We keep messages in a linked list (for now). | ||
295 | */ | ||
296 | struct MessageEntry *next; | ||
297 | |||
298 | /** | ||
299 | * By when are we supposed to transmit this message? | ||
300 | */ | ||
301 | struct GNUNET_TIME_Absolute deadline; | ||
302 | |||
303 | /** | ||
304 | * How important is this message to us? | ||
305 | */ | ||
306 | unsigned int priority; | ||
307 | |||
308 | /** | ||
309 | * How long is the message? (number of bytes following | ||
310 | * the "struct MessageEntry", but not including the | ||
311 | * size of "struct MessageEntry" itself!) | ||
312 | */ | ||
313 | uint16_t size; | ||
314 | |||
315 | /** | ||
316 | * Was this message selected for transmission in the | ||
317 | * current round? GNUNET_YES or GNUNET_NO. | ||
318 | */ | ||
319 | int16_t do_transmit; | ||
320 | |||
321 | }; | ||
322 | |||
323 | |||
324 | struct Neighbour | ||
325 | { | ||
326 | /** | ||
327 | * We keep neighbours in a linked list (for now). | ||
328 | */ | ||
329 | struct Neighbour *next; | ||
330 | |||
331 | /** | ||
332 | * Unencrypted messages destined for this peer. | ||
333 | */ | ||
334 | struct MessageEntry *messages; | ||
335 | |||
336 | /** | ||
337 | * Head of the batched, encrypted message queue (already ordered, | ||
338 | * transmit starting with the head). | ||
339 | */ | ||
340 | struct MessageEntry *encrypted_head; | ||
341 | |||
342 | /** | ||
343 | * Tail of the batched, encrypted message queue (already ordered, | ||
344 | * append new messages to tail) | ||
345 | */ | ||
346 | struct MessageEntry *encrypted_tail; | ||
347 | |||
348 | /** | ||
349 | * Handle for pending requests for transmission to this peer | ||
350 | * with the transport service. NULL if no request is pending. | ||
351 | */ | ||
352 | struct GNUNET_TRANSPORT_TransmitHandle *th; | ||
353 | |||
354 | /** | ||
355 | * Public key of the neighbour, NULL if we don't have it yet. | ||
356 | */ | ||
357 | struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key; | ||
358 | |||
359 | /** | ||
360 | * We received a PING message before we got the "public_key" | ||
361 | * (or the SET_KEY). We keep it here until we have a key | ||
362 | * to decrypt it. NULL if no PING is pending. | ||
363 | */ | ||
364 | struct PingMessage *pending_ping; | ||
365 | |||
366 | /** | ||
367 | * Identity of the neighbour. | ||
368 | */ | ||
369 | struct GNUNET_PeerIdentity peer; | ||
370 | |||
371 | /** | ||
372 | * Key we use to encrypt our messages for the other peer | ||
373 | * (initialized by us when we do the handshake). | ||
374 | */ | ||
375 | struct GNUNET_CRYPTO_AesSessionKey encrypt_key; | ||
376 | |||
377 | /** | ||
378 | * Key we use to decrypt messages from the other peer | ||
379 | * (given to us by the other peer during the handshake). | ||
380 | */ | ||
381 | struct GNUNET_CRYPTO_AesSessionKey decrypt_key; | ||
382 | |||
383 | /** | ||
384 | * ID of task used for re-trying plaintext scheduling. | ||
385 | */ | ||
386 | GNUNET_SCHEDULER_TaskIdentifier retry_plaintext_task; | ||
387 | |||
388 | /** | ||
389 | * ID of task used for re-trying SET_KEY and PING message. | ||
390 | */ | ||
391 | GNUNET_SCHEDULER_TaskIdentifier retry_set_key_task; | ||
392 | |||
393 | /** | ||
394 | * At what time did we generate our encryption key? | ||
395 | */ | ||
396 | struct GNUNET_TIME_Absolute encrypt_key_created; | ||
397 | |||
398 | /** | ||
399 | * At what time did the other peer generate the decryption key? | ||
400 | */ | ||
401 | struct GNUNET_TIME_Absolute decrypt_key_created; | ||
402 | |||
403 | /** | ||
404 | * At what time did we initially establish (as in, complete session | ||
405 | * key handshake) this connection? Should be zero if status != KEY_CONFIRMED. | ||
406 | */ | ||
407 | struct GNUNET_TIME_Absolute time_established; | ||
408 | |||
409 | /** | ||
410 | * At what time did we last receive an encrypted message from the | ||
411 | * other peer? Should be zero if status != KEY_CONFIRMED. | ||
412 | */ | ||
413 | struct GNUNET_TIME_Absolute last_activity; | ||
414 | |||
415 | /** | ||
416 | * Last latency observed from this peer. | ||
417 | */ | ||
418 | struct GNUNET_TIME_Relative last_latency; | ||
419 | |||
420 | /** | ||
421 | * At what frequency are we currently re-trying SET KEY messages? | ||
422 | */ | ||
423 | struct GNUNET_TIME_Relative set_key_retry_frequency; | ||
424 | |||
425 | /** | ||
426 | * Time of our last update to the "available_send_window". | ||
427 | */ | ||
428 | struct GNUNET_TIME_Absolute last_asw_update; | ||
429 | |||
430 | /** | ||
431 | * Time of our last update to the "available_recv_window". | ||
432 | */ | ||
433 | struct GNUNET_TIME_Absolute last_arw_update; | ||
434 | |||
435 | /** | ||
436 | * Number of bytes that we are eligible to transmit to this | ||
437 | * peer at this point. Incremented every minute by max_out_bpm, | ||
438 | * bounded by max_bpm (no back-log larger than MAX_BUF_FACT minutes, | ||
439 | * bandwidth-hogs are sampled at a frequency of about 78s!); | ||
440 | * may get negative if we have VERY high priority content. | ||
441 | */ | ||
442 | long long available_send_window; | ||
443 | |||
444 | /** | ||
445 | * How much downstream capacity of this peer has been reserved for | ||
446 | * our traffic? (Our clients can request that a certain amount of | ||
447 | * bandwidth is available for replies to them; this value is used to | ||
448 | * make sure that this reserved amount of bandwidth is actually | ||
449 | * available). | ||
450 | */ | ||
451 | long long available_recv_window; | ||
452 | |||
453 | /** | ||
454 | * How valueable were the messages of this peer recently? | ||
455 | */ | ||
456 | double current_preference; | ||
457 | |||
458 | /** | ||
459 | * Bit map indicating which of the 32 sequence numbers before the last | ||
460 | * were received (good for accepting out-of-order packets and | ||
461 | * estimating reliability of the connection) | ||
462 | */ | ||
463 | unsigned int last_packets_bitmap; | ||
464 | |||
465 | /** | ||
466 | * Number of messages in the message queue for this peer. | ||
467 | */ | ||
468 | unsigned int message_queue_size; | ||
469 | |||
470 | /** | ||
471 | * last sequence number received on this connection (highest) | ||
472 | */ | ||
473 | uint32_t last_sequence_number_received; | ||
474 | |||
475 | /** | ||
476 | * last sequence number transmitted | ||
477 | */ | ||
478 | uint32_t last_sequence_number_sent; | ||
479 | |||
480 | /** | ||
481 | * Available bandwidth in for this peer (current target). | ||
482 | */ | ||
483 | uint32_t bpm_in; | ||
484 | |||
485 | /** | ||
486 | * Available bandwidth out for this peer (current target). | ||
487 | */ | ||
488 | uint32_t bpm_out; | ||
489 | |||
490 | /** | ||
491 | * Internal bandwidth limit set for this peer (initially | ||
492 | * typcially set to "-1"). "bpm_out" is MAX of | ||
493 | * "bpm_out_internal_limit" and "bpm_out_external_limit". | ||
494 | */ | ||
495 | uint32_t bpm_out_internal_limit; | ||
496 | |||
497 | /** | ||
498 | * External bandwidth limit set for this peer by the | ||
499 | * peer that we are communicating with. "bpm_out" is MAX of | ||
500 | * "bpm_out_internal_limit" and "bpm_out_external_limit". | ||
501 | */ | ||
502 | uint32_t bpm_out_external_limit; | ||
503 | |||
504 | /** | ||
505 | * What was our PING challenge number? | ||
506 | */ | ||
507 | uint32_t ping_challenge; | ||
508 | |||
509 | /** | ||
510 | * What is our connection status? | ||
511 | */ | ||
512 | enum PeerStateMachine status; | ||
513 | |||
514 | }; | ||
515 | |||
516 | |||
517 | /** | ||
518 | * Events are messages for clients. The struct | ||
519 | * itself is followed by the actual message. | ||
520 | */ | ||
521 | struct Event | ||
522 | { | ||
523 | /** | ||
524 | * This is a linked list. | ||
525 | */ | ||
526 | struct Event *next; | ||
527 | |||
528 | /** | ||
529 | * Size of the message. | ||
530 | */ | ||
531 | size_t size; | ||
532 | |||
533 | /** | ||
534 | * Could this event be dropped if this queue | ||
535 | * is getting too large? (NOT YET USED!) | ||
536 | */ | ||
537 | int can_drop; | ||
538 | |||
539 | }; | ||
540 | |||
541 | |||
542 | /** | ||
543 | * Data structure for each client connected to the core service. | ||
544 | */ | ||
545 | struct Client | ||
546 | { | ||
547 | /** | ||
548 | * Clients are kept in a linked list. | ||
549 | */ | ||
550 | struct Client *next; | ||
551 | |||
552 | /** | ||
553 | * Handle for the client with the server API. | ||
554 | */ | ||
555 | struct GNUNET_SERVER_Client *client_handle; | ||
556 | |||
557 | /** | ||
558 | * Linked list of messages we still need to deliver to | ||
559 | * this client. | ||
560 | */ | ||
561 | struct Event *event_head; | ||
562 | |||
563 | /** | ||
564 | * Tail of the linked list of events. | ||
565 | */ | ||
566 | struct Event *event_tail; | ||
567 | |||
568 | /** | ||
569 | * Current transmit handle, NULL if no transmission request | ||
570 | * is pending. | ||
571 | */ | ||
572 | struct GNUNET_NETWORK_TransmitHandle *th; | ||
573 | |||
574 | /** | ||
575 | * Array of the types of messages this peer cares | ||
576 | * about (with "tcnt" entries). Allocated as part | ||
577 | * of this client struct, do not free! | ||
578 | */ | ||
579 | uint16_t *types; | ||
580 | |||
581 | /** | ||
582 | * Options for messages this client cares about, | ||
583 | * see GNUNET_CORE_OPTION_ values. | ||
584 | */ | ||
585 | uint32_t options; | ||
586 | |||
587 | /** | ||
588 | * Number of types of incoming messages this client | ||
589 | * specifically cares about. Size of the "types" array. | ||
590 | */ | ||
591 | unsigned int tcnt; | ||
592 | |||
593 | }; | ||
594 | |||
595 | |||
596 | /** | ||
597 | * Our public key. | ||
598 | */ | ||
599 | static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key; | ||
600 | |||
601 | /** | ||
602 | * Our identity. | ||
603 | */ | ||
604 | static struct GNUNET_PeerIdentity my_identity; | ||
605 | |||
606 | /** | ||
607 | * Our private key. | ||
608 | */ | ||
609 | static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key; | ||
610 | |||
611 | /** | ||
612 | * Our scheduler. | ||
613 | */ | ||
614 | struct GNUNET_SCHEDULER_Handle *sched; | ||
615 | |||
616 | /** | ||
617 | * Our configuration. | ||
618 | */ | ||
619 | struct GNUNET_CONFIGURATION_Handle *cfg; | ||
620 | |||
621 | /** | ||
622 | * Our server. | ||
623 | */ | ||
624 | static struct GNUNET_SERVER_Handle *server; | ||
625 | |||
626 | /** | ||
627 | * Transport service. | ||
628 | */ | ||
629 | static struct GNUNET_TRANSPORT_Handle *transport; | ||
630 | |||
631 | /** | ||
632 | * We keep neighbours in a linked list (for now). | ||
633 | */ | ||
634 | static struct Neighbour *neighbours; | ||
635 | |||
636 | /** | ||
637 | * Linked list of our clients. | ||
638 | */ | ||
639 | static struct Client *clients; | ||
640 | |||
641 | |||
642 | /** | ||
643 | * Recalculate the number of bytes we expect to | ||
644 | * receive or transmit in a given window. | ||
645 | * | ||
646 | * @param window pointer to the byte counter (updated) | ||
647 | * @param ts pointer to the timestamp (updated) | ||
648 | * @param bpm number of bytes per minute that should | ||
649 | * be added to the window. | ||
650 | */ | ||
651 | static void | ||
652 | update_window (long long *window, | ||
653 | struct GNUNET_TIME_Absolute *ts, unsigned int bpm) | ||
654 | { | ||
655 | struct GNUNET_TIME_Relative since; | ||
656 | |||
657 | since = GNUNET_TIME_absolute_get_duration (*ts); | ||
658 | if (since.value < 60 * 1000) | ||
659 | return; /* not even a minute has passed */ | ||
660 | *ts = GNUNET_TIME_absolute_get (); | ||
661 | *window += (bpm * since.value) / 60 / 1000; | ||
662 | if (*window > MAX_WINDOW_TIME * bpm) | ||
663 | *window = MAX_WINDOW_TIME * bpm; | ||
664 | } | ||
665 | |||
666 | |||
667 | /** | ||
668 | * Find the entry for the given neighbour. | ||
669 | * | ||
670 | * @param peer identity of the neighbour | ||
671 | * @return NULL if we are not connected, otherwise the | ||
672 | * neighbour's entry. | ||
673 | */ | ||
674 | static struct Neighbour * | ||
675 | find_neighbour (const struct GNUNET_PeerIdentity *peer) | ||
676 | { | ||
677 | struct Neighbour *ret; | ||
678 | |||
679 | ret = neighbours; | ||
680 | while ((ret != NULL) && | ||
681 | (0 != memcmp (&ret->peer, | ||
682 | peer, sizeof (struct GNUNET_PeerIdentity)))) | ||
683 | ret = ret->next; | ||
684 | return ret; | ||
685 | } | ||
686 | |||
687 | |||
688 | /** | ||
689 | * Find the entry for the given client. | ||
690 | * | ||
691 | * @param client handle for the client | ||
692 | * @return NULL if we are not connected, otherwise the | ||
693 | * client's struct. | ||
694 | */ | ||
695 | static struct Client * | ||
696 | find_client (const struct GNUNET_SERVER_Client *client) | ||
697 | { | ||
698 | struct Client *ret; | ||
699 | |||
700 | ret = clients; | ||
701 | while ((ret != NULL) && (client != ret->client_handle)) | ||
702 | ret = ret->next; | ||
703 | return ret; | ||
704 | } | ||
705 | |||
706 | |||
707 | /** | ||
708 | * If necessary, initiate a request with the server to | ||
709 | * transmit messages from the queue of the given client. | ||
710 | * @param client who to transfer messages to | ||
711 | */ | ||
712 | static void request_transmit (struct Client *client); | ||
713 | |||
714 | |||
715 | /** | ||
716 | * Client is ready to receive data, provide it. | ||
717 | * @param cls closure | ||
718 | * @param size number of bytes available in buf | ||
719 | * @param buf where the callee should write the message | ||
720 | * @return number of bytes written to buf | ||
721 | */ | ||
722 | static size_t | ||
723 | do_client_transmit (void *cls, size_t size, void *buf) | ||
724 | { | ||
725 | struct Client *client = cls; | ||
726 | struct Event *e; | ||
727 | char *tgt; | ||
728 | size_t ret; | ||
729 | |||
730 | client->th = NULL; | ||
731 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
732 | "Client ready to receive %u bytes.\n", size); | ||
733 | if (buf == NULL) | ||
734 | { | ||
735 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
736 | "Failed to transmit data to client (disconnect)?\n"); | ||
737 | return 0; /* we'll surely get a disconnect soon... */ | ||
738 | } | ||
739 | tgt = buf; | ||
740 | ret = 0; | ||
741 | while ((NULL != (e = client->event_head)) && (e->size <= size)) | ||
742 | { | ||
743 | memcpy (&tgt[ret], &e[1], e->size); | ||
744 | size -= e->size; | ||
745 | ret += e->size; | ||
746 | client->event_head = e->next; | ||
747 | GNUNET_free (e); | ||
748 | } | ||
749 | GNUNET_assert (ret > 0); | ||
750 | if (client->event_head == NULL) | ||
751 | client->event_tail = NULL; | ||
752 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
753 | "Transmitting %u bytes to client\n", ret); | ||
754 | request_transmit (client); | ||
755 | return ret; | ||
756 | } | ||
757 | |||
758 | |||
759 | /** | ||
760 | * If necessary, initiate a request with the server to | ||
761 | * transmit messages from the queue of the given client. | ||
762 | * @param client who to transfer messages to | ||
763 | */ | ||
764 | static void | ||
765 | request_transmit (struct Client *client) | ||
766 | { | ||
767 | |||
768 | if (NULL != client->th) | ||
769 | return; /* already pending */ | ||
770 | if (NULL == client->event_head) | ||
771 | return; /* no more events pending */ | ||
772 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
773 | "Asking server to transmit %u bytes to client\n", | ||
774 | client->event_head->size); | ||
775 | client->th | ||
776 | = GNUNET_SERVER_notify_transmit_ready (client->client_handle, | ||
777 | client->event_head->size, | ||
778 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
779 | &do_client_transmit, client); | ||
780 | } | ||
781 | |||
782 | |||
783 | /** | ||
784 | * Send a message to one of our clients. | ||
785 | * @param client target for the message | ||
786 | * @param msg message to transmit | ||
787 | * @param can_drop could this message be dropped if the | ||
788 | * client's queue is getting too large? | ||
789 | */ | ||
790 | static void | ||
791 | send_to_client (struct Client *client, | ||
792 | const struct GNUNET_MessageHeader *msg, int can_drop) | ||
793 | { | ||
794 | struct Event *e; | ||
795 | uint16_t msize; | ||
796 | |||
797 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
798 | "Preparing to send message of type %u to client.\n", | ||
799 | ntohs (msg->type)); | ||
800 | msize = ntohs (msg->size); | ||
801 | e = GNUNET_malloc (sizeof (struct Event) + msize); | ||
802 | /* append */ | ||
803 | if (client->event_tail != NULL) | ||
804 | client->event_tail->next = e; | ||
805 | else | ||
806 | client->event_head = e; | ||
807 | client->event_tail = e; | ||
808 | e->can_drop = can_drop; | ||
809 | e->size = msize; | ||
810 | memcpy (&e[1], msg, msize); | ||
811 | request_transmit (client); | ||
812 | } | ||
813 | |||
814 | |||
815 | /** | ||
816 | * Send a message to all of our current clients. | ||
817 | */ | ||
818 | static void | ||
819 | send_to_all_clients (const struct GNUNET_MessageHeader *msg, int can_drop) | ||
820 | { | ||
821 | struct Client *c; | ||
822 | |||
823 | c = clients; | ||
824 | while (c != NULL) | ||
825 | { | ||
826 | send_to_client (c, msg, can_drop); | ||
827 | c = c->next; | ||
828 | } | ||
829 | } | ||
830 | |||
831 | |||
832 | /** | ||
833 | * Handle CORE_INIT request. | ||
834 | */ | ||
835 | static void | ||
836 | handle_client_init (void *cls, | ||
837 | struct GNUNET_SERVER_Handle *server, | ||
838 | struct GNUNET_SERVER_Client *client, | ||
839 | const struct GNUNET_MessageHeader *message) | ||
840 | { | ||
841 | const struct InitMessage *im; | ||
842 | struct InitReplyMessage irm; | ||
843 | struct Client *c; | ||
844 | uint16_t msize; | ||
845 | const uint16_t *types; | ||
846 | struct Neighbour *n; | ||
847 | struct ConnectNotifyMessage cnm; | ||
848 | |||
849 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
850 | "Client connecting to core service with `%s' message\n", | ||
851 | "INIT"); | ||
852 | /* check that we don't have an entry already */ | ||
853 | c = clients; | ||
854 | while (c != NULL) | ||
855 | { | ||
856 | if (client == c->client_handle) | ||
857 | { | ||
858 | GNUNET_break (0); | ||
859 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
860 | return; | ||
861 | } | ||
862 | c = c->next; | ||
863 | } | ||
864 | msize = ntohs (message->size); | ||
865 | if (msize < sizeof (struct InitMessage)) | ||
866 | { | ||
867 | GNUNET_break (0); | ||
868 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
869 | return; | ||
870 | } | ||
871 | im = (const struct InitMessage *) message; | ||
872 | types = (const uint16_t *) &im[1]; | ||
873 | msize -= sizeof (struct InitMessage); | ||
874 | c = GNUNET_malloc (sizeof (struct Client) + msize); | ||
875 | c->client_handle = client; | ||
876 | c->next = clients; | ||
877 | clients = c; | ||
878 | memcpy (&c[1], types, msize); | ||
879 | c->types = (uint16_t *) & c[1]; | ||
880 | c->options = ntohl (im->options); | ||
881 | c->tcnt = msize / sizeof (uint16_t); | ||
882 | /* send init reply message */ | ||
883 | irm.header.size = htons (sizeof (struct InitReplyMessage)); | ||
884 | irm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_INIT_REPLY); | ||
885 | irm.reserved = htonl (0); | ||
886 | memcpy (&irm.publicKey, | ||
887 | &my_public_key, | ||
888 | sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); | ||
889 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
890 | "Sending `%s' message to client.\n", "INIT_REPLY"); | ||
891 | send_to_client (c, &irm.header, GNUNET_NO); | ||
892 | /* notify new client about existing neighbours */ | ||
893 | cnm.header.size = htons (sizeof (struct ConnectNotifyMessage)); | ||
894 | cnm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT); | ||
895 | n = neighbours; | ||
896 | while (n != NULL) | ||
897 | { | ||
898 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
899 | "Sending `%s' message to client.\n", "NOTIFY_CONNECT"); | ||
900 | cnm.bpm_available = htonl (n->bpm_out); | ||
901 | cnm.last_activity = GNUNET_TIME_absolute_hton (n->last_activity); | ||
902 | cnm.peer = n->peer; | ||
903 | send_to_client (c, &cnm.header, GNUNET_NO); | ||
904 | n = n->next; | ||
905 | } | ||
906 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
907 | } | ||
908 | |||
909 | |||
910 | /** | ||
911 | * A client disconnected, clean up. | ||
912 | * | ||
913 | * @param cls closure | ||
914 | * @param client identification of the client | ||
915 | */ | ||
916 | static void | ||
917 | handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client) | ||
918 | { | ||
919 | struct Client *pos; | ||
920 | struct Client *prev; | ||
921 | |||
922 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
923 | "Client has disconnected from core service.\n"); | ||
924 | prev = NULL; | ||
925 | pos = clients; | ||
926 | while (pos != NULL) | ||
927 | { | ||
928 | if (client == pos->client_handle) | ||
929 | { | ||
930 | if (prev == NULL) | ||
931 | clients = pos->next; | ||
932 | else | ||
933 | prev->next = pos->next; | ||
934 | if (pos->th != NULL) | ||
935 | GNUNET_NETWORK_notify_transmit_ready_cancel (pos->th); | ||
936 | GNUNET_free (pos); | ||
937 | return; | ||
938 | } | ||
939 | prev = pos; | ||
940 | pos = pos->next; | ||
941 | } | ||
942 | /* client never sent INIT */ | ||
943 | } | ||
944 | |||
945 | |||
946 | /** | ||
947 | * Handle REQUEST_CONFIGURE request. | ||
948 | */ | ||
949 | static void | ||
950 | handle_client_request_configure (void *cls, | ||
951 | struct GNUNET_SERVER_Handle *server, | ||
952 | struct GNUNET_SERVER_Client *client, | ||
953 | const struct GNUNET_MessageHeader *message) | ||
954 | { | ||
955 | const struct RequestConfigureMessage *rcm; | ||
956 | struct Neighbour *n; | ||
957 | struct ConfigurationInfoMessage cim; | ||
958 | struct Client *c; | ||
959 | int reserv; | ||
960 | |||
961 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
962 | "Core service receives `%s' request.\n", "CONFIGURE"); | ||
963 | rcm = (const struct RequestConfigureMessage *) message; | ||
964 | n = find_neighbour (&rcm->peer); | ||
965 | memset (&cim, 0, sizeof (cim)); | ||
966 | if ((n != NULL) && (n->status == PEER_STATE_KEY_CONFIRMED)) | ||
967 | { | ||
968 | n->bpm_out_internal_limit = ntohl (rcm->limit_outbound_bpm); | ||
969 | n->bpm_out = GNUNET_MAX (n->bpm_out_internal_limit, | ||
970 | n->bpm_out_external_limit); | ||
971 | reserv = ntohl (rcm->reserve_inbound); | ||
972 | if (reserv < 0) | ||
973 | { | ||
974 | n->available_recv_window += reserv; | ||
975 | } | ||
976 | else if (reserv > 0) | ||
977 | { | ||
978 | update_window (&n->available_recv_window, | ||
979 | &n->last_arw_update, n->bpm_in); | ||
980 | if (n->available_recv_window < reserv) | ||
981 | reserv = n->available_recv_window; | ||
982 | n->available_recv_window -= reserv; | ||
983 | } | ||
984 | n->current_preference += rcm->preference_change; | ||
985 | if (n->current_preference < 0) | ||
986 | n->current_preference = 0; | ||
987 | cim.reserved_amount = htonl (reserv); | ||
988 | cim.bpm_in = htonl (n->bpm_in); | ||
989 | cim.bpm_out = htonl (n->bpm_out); | ||
990 | cim.latency = GNUNET_TIME_relative_hton (n->last_latency); | ||
991 | cim.preference = n->current_preference; | ||
992 | } | ||
993 | cim.header.size = htons (sizeof (struct ConfigurationInfoMessage)); | ||
994 | cim.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_CONFIGURATION_INFO); | ||
995 | cim.peer = rcm->peer; | ||
996 | c = find_client (client); | ||
997 | if (c == NULL) | ||
998 | { | ||
999 | GNUNET_break (0); | ||
1000 | return; | ||
1001 | } | ||
1002 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1003 | "Sending `%s' message to client.\n", "CONFIGURATION_INFO"); | ||
1004 | send_to_client (c, &cim.header, GNUNET_NO); | ||
1005 | } | ||
1006 | |||
1007 | |||
1008 | /** | ||
1009 | * Check if we have encrypted messages for the specified neighbour | ||
1010 | * pending, and if so, check with the transport about sending them | ||
1011 | * out. | ||
1012 | * | ||
1013 | * @param n neighbour to check. | ||
1014 | */ | ||
1015 | static void process_encrypted_neighbour_queue (struct Neighbour *n); | ||
1016 | |||
1017 | |||
1018 | /** | ||
1019 | * Function called when the transport service is ready to | ||
1020 | * receive an encrypted message for the respective peer | ||
1021 | * | ||
1022 | * @param cls neighbour to use message from | ||
1023 | * @param size number of bytes we can transmit | ||
1024 | * @param buf where to copy the message | ||
1025 | * @return number of bytes transmitted | ||
1026 | */ | ||
1027 | static size_t | ||
1028 | notify_encrypted_transmit_ready (void *cls, size_t size, void *buf) | ||
1029 | { | ||
1030 | struct Neighbour *n = cls; | ||
1031 | struct MessageEntry *m; | ||
1032 | size_t ret; | ||
1033 | char *cbuf; | ||
1034 | |||
1035 | n->th = NULL; | ||
1036 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1037 | "Transport ready to receive %u bytes for `%4s'\n", | ||
1038 | size, GNUNET_i2s (&n->peer)); | ||
1039 | GNUNET_assert (NULL != (m = n->encrypted_head)); | ||
1040 | n->encrypted_head = m->next; | ||
1041 | if (m->next == NULL) | ||
1042 | n->encrypted_tail = NULL; | ||
1043 | ret = 0; | ||
1044 | cbuf = buf; | ||
1045 | if (buf != NULL) | ||
1046 | { | ||
1047 | GNUNET_assert (size >= m->size); | ||
1048 | memcpy (cbuf, &m[1], m->size); | ||
1049 | ret = m->size; | ||
1050 | process_encrypted_neighbour_queue (n); | ||
1051 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1052 | "Copied message of type %u and size %u into transport buffer for `%4s'\n", | ||
1053 | ntohs (((struct GNUNET_MessageHeader *) &m[1])->type), | ||
1054 | ret, GNUNET_i2s (&n->peer)); | ||
1055 | } | ||
1056 | else | ||
1057 | { | ||
1058 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1059 | "Transmission for message of type %u and size %u failed\n", | ||
1060 | ntohs (((struct GNUNET_MessageHeader *) &m[1])->type), | ||
1061 | m->size); | ||
1062 | } | ||
1063 | GNUNET_free (m); | ||
1064 | return ret; | ||
1065 | } | ||
1066 | |||
1067 | |||
1068 | /** | ||
1069 | * Check if we have plaintext messages for the specified neighbour | ||
1070 | * pending, and if so, consider batching and encrypting them (and | ||
1071 | * then trigger processing of the encrypted queue if needed). | ||
1072 | * | ||
1073 | * @param n neighbour to check. | ||
1074 | */ | ||
1075 | static void process_plaintext_neighbour_queue (struct Neighbour *n); | ||
1076 | |||
1077 | |||
1078 | /** | ||
1079 | * Check if we have encrypted messages for the specified neighbour | ||
1080 | * pending, and if so, check with the transport about sending them | ||
1081 | * out. | ||
1082 | * | ||
1083 | * @param n neighbour to check. | ||
1084 | */ | ||
1085 | static void | ||
1086 | process_encrypted_neighbour_queue (struct Neighbour *n) | ||
1087 | { | ||
1088 | if (n->th != NULL) | ||
1089 | { | ||
1090 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1091 | "Asked to process encrypted queue, but request already pending.\n"); | ||
1092 | return; /* already pending */ | ||
1093 | } | ||
1094 | if (n->encrypted_head == NULL) | ||
1095 | { | ||
1096 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1097 | "Encrypted queue empty, trying plaintext queue instead.\n"); | ||
1098 | process_plaintext_neighbour_queue (n); | ||
1099 | return; | ||
1100 | } | ||
1101 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1102 | "Asking transport for transmission of %u bytes to `%4s' in next %llu ms\n", | ||
1103 | n->encrypted_head->size, | ||
1104 | GNUNET_i2s (&n->peer), | ||
1105 | GNUNET_TIME_absolute_get_remaining (n->encrypted_head-> | ||
1106 | deadline).value); | ||
1107 | n->th = | ||
1108 | GNUNET_TRANSPORT_notify_transmit_ready (transport, &n->peer, | ||
1109 | n->encrypted_head->size, | ||
1110 | GNUNET_TIME_absolute_get_remaining | ||
1111 | (n->encrypted_head->deadline), | ||
1112 | ¬ify_encrypted_transmit_ready, | ||
1113 | n); | ||
1114 | if (n->th == NULL) | ||
1115 | { | ||
1116 | /* message request too large (oops) */ | ||
1117 | GNUNET_break (0); | ||
1118 | /* FIXME: handle error somehow! */ | ||
1119 | } | ||
1120 | } | ||
1121 | |||
1122 | |||
1123 | /** | ||
1124 | * Decrypt size bytes from in and write the result to out. Use the | ||
1125 | * key for inbound traffic of the given neighbour. This function does | ||
1126 | * NOT do any integrity-checks on the result. | ||
1127 | * | ||
1128 | * @param n neighbour we are receiving from | ||
1129 | * @param iv initialization vector to use | ||
1130 | * @param in ciphertext | ||
1131 | * @param out plaintext | ||
1132 | * @param size size of in/out | ||
1133 | * @return GNUNET_OK on success | ||
1134 | */ | ||
1135 | static int | ||
1136 | do_decrypt (struct Neighbour *n, | ||
1137 | const GNUNET_HashCode * iv, | ||
1138 | const void *in, void *out, size_t size) | ||
1139 | { | ||
1140 | if (size != (uint16_t) size) | ||
1141 | { | ||
1142 | GNUNET_break (0); | ||
1143 | return GNUNET_NO; | ||
1144 | } | ||
1145 | if ((n->status != PEER_STATE_KEY_RECEIVED) && | ||
1146 | (n->status != PEER_STATE_KEY_CONFIRMED)) | ||
1147 | { | ||
1148 | GNUNET_break_op (0); | ||
1149 | return GNUNET_SYSERR; | ||
1150 | } | ||
1151 | if (size != | ||
1152 | GNUNET_CRYPTO_aes_decrypt (&n->decrypt_key, | ||
1153 | in, | ||
1154 | (uint16_t) size, | ||
1155 | (const struct | ||
1156 | GNUNET_CRYPTO_AesInitializationVector *) iv, | ||
1157 | out)) | ||
1158 | { | ||
1159 | GNUNET_break (0); | ||
1160 | return GNUNET_SYSERR; | ||
1161 | } | ||
1162 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1163 | "Decrypted %u bytes from `%4s' using key %u\n", | ||
1164 | size, GNUNET_i2s (&n->peer), n->decrypt_key.crc32); | ||
1165 | return GNUNET_OK; | ||
1166 | } | ||
1167 | |||
1168 | |||
1169 | /** | ||
1170 | * Encrypt size bytes from in and write the result to out. Use the | ||
1171 | * key for outbound traffic of the given neighbour. | ||
1172 | * | ||
1173 | * @param n neighbour we are sending to | ||
1174 | * @param iv initialization vector to use | ||
1175 | * @param in ciphertext | ||
1176 | * @param out plaintext | ||
1177 | * @param size size of in/out | ||
1178 | * @return GNUNET_OK on success | ||
1179 | */ | ||
1180 | static int | ||
1181 | do_encrypt (struct Neighbour *n, | ||
1182 | const GNUNET_HashCode * iv, | ||
1183 | const void *in, void *out, size_t size) | ||
1184 | { | ||
1185 | if (size != (uint16_t) size) | ||
1186 | { | ||
1187 | GNUNET_break (0); | ||
1188 | return GNUNET_NO; | ||
1189 | } | ||
1190 | GNUNET_assert (size == | ||
1191 | GNUNET_CRYPTO_aes_encrypt (in, | ||
1192 | (uint16_t) size, | ||
1193 | &n->encrypt_key, | ||
1194 | (const struct | ||
1195 | GNUNET_CRYPTO_AesInitializationVector | ||
1196 | *) iv, out)); | ||
1197 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1198 | "Encrypted %u bytes for `%4s' using key %u\n", size, | ||
1199 | GNUNET_i2s (&n->peer), n->encrypt_key.crc32); | ||
1200 | return GNUNET_OK; | ||
1201 | } | ||
1202 | |||
1203 | |||
1204 | /** | ||
1205 | * Select messages for transmission. This heuristic uses a combination | ||
1206 | * of earliest deadline first (EDF) scheduling (with bounded horizon) | ||
1207 | * and priority-based discard (in case no feasible schedule exist) and | ||
1208 | * speculative optimization (defer any kind of transmission until | ||
1209 | * we either create a batch of significant size, 25% of max, or until | ||
1210 | * we are close to a deadline). Furthermore, when scheduling the | ||
1211 | * heuristic also packs as many messages into the batch as possible, | ||
1212 | * starting with those with the earliest deadline. Yes, this is fun. | ||
1213 | * | ||
1214 | * @param n neighbour to select messages from | ||
1215 | * @param size number of bytes to select for transmission | ||
1216 | * @param retry_time set to the time when we should try again | ||
1217 | * (only valid if this function returns zero) | ||
1218 | * @return number of bytes selected, or 0 if we decided to | ||
1219 | * defer scheduling overall; in that case, retry_time is set. | ||
1220 | */ | ||
1221 | static size_t | ||
1222 | select_messages (struct Neighbour *n, | ||
1223 | size_t size, struct GNUNET_TIME_Relative *retry_time) | ||
1224 | { | ||
1225 | struct MessageEntry *pos; | ||
1226 | struct MessageEntry *min; | ||
1227 | struct MessageEntry *last; | ||
1228 | unsigned int min_prio; | ||
1229 | struct GNUNET_TIME_Absolute t; | ||
1230 | struct GNUNET_TIME_Absolute now; | ||
1231 | uint64_t delta; | ||
1232 | uint64_t avail; | ||
1233 | unsigned long long slack; /* how long could we wait before missing deadlines? */ | ||
1234 | size_t off; | ||
1235 | int discard_low_prio; | ||
1236 | |||
1237 | GNUNET_assert (NULL != n->messages); | ||
1238 | now = GNUNET_TIME_absolute_get (); | ||
1239 | /* last entry in linked list of messages processed */ | ||
1240 | last = NULL; | ||
1241 | /* should we remove the entry with the lowest | ||
1242 | priority from consideration for scheduling at the | ||
1243 | end of the loop? */ | ||
1244 | discard_low_prio = GNUNET_YES; | ||
1245 | while (GNUNET_YES == discard_low_prio) | ||
1246 | { | ||
1247 | min = NULL; | ||
1248 | min_prio = -1; | ||
1249 | discard_low_prio = GNUNET_NO; | ||
1250 | /* number of bytes available for transmission at time "t" */ | ||
1251 | avail = n->available_send_window; | ||
1252 | t = n->last_asw_update; | ||
1253 | /* how many bytes have we (hyptothetically) scheduled so far */ | ||
1254 | off = 0; | ||
1255 | /* maximum time we can wait before transmitting anything | ||
1256 | and still make all of our deadlines */ | ||
1257 | slack = -1; | ||
1258 | |||
1259 | pos = n->messages; | ||
1260 | /* note that we use "*2" here because we want to look | ||
1261 | a bit further into the future; much more makes no | ||
1262 | sense since new message might be scheduled in the | ||
1263 | meantime... */ | ||
1264 | while ((pos != NULL) && (off < size * 2)) | ||
1265 | { | ||
1266 | if (pos->do_transmit == GNUNET_YES) | ||
1267 | { | ||
1268 | /* already removed from consideration */ | ||
1269 | pos = pos->next; | ||
1270 | continue; | ||
1271 | } | ||
1272 | if (discard_low_prio == GNUNET_NO) | ||
1273 | { | ||
1274 | delta = pos->deadline.value; | ||
1275 | if (delta < t.value) | ||
1276 | delta = 0; | ||
1277 | else | ||
1278 | delta = t.value - delta; | ||
1279 | avail += delta * n->bpm_out / 1000 / 60; | ||
1280 | if (avail < pos->size) | ||
1281 | { | ||
1282 | discard_low_prio = GNUNET_YES; /* we could not schedule this one! */ | ||
1283 | } | ||
1284 | else | ||
1285 | { | ||
1286 | avail -= pos->size; | ||
1287 | /* update slack, considering both its absolute deadline | ||
1288 | and relative deadlines caused by other messages | ||
1289 | with their respective load */ | ||
1290 | slack = GNUNET_MIN (slack, avail / n->bpm_out); | ||
1291 | if (pos->deadline.value < now.value) | ||
1292 | slack = 0; | ||
1293 | else | ||
1294 | slack = | ||
1295 | GNUNET_MIN (slack, pos->deadline.value - now.value); | ||
1296 | } | ||
1297 | } | ||
1298 | off += pos->size; | ||
1299 | t.value = GNUNET_MAX (pos->deadline.value, t.value); | ||
1300 | if (pos->priority <= min_prio) | ||
1301 | { | ||
1302 | /* update min for discard */ | ||
1303 | min_prio = pos->priority; | ||
1304 | min = pos; | ||
1305 | } | ||
1306 | pos = pos->next; | ||
1307 | } | ||
1308 | if (discard_low_prio) | ||
1309 | { | ||
1310 | /* remove lowest-priority entry from consideration */ | ||
1311 | min->do_transmit = GNUNET_YES; /* means: discard (for now) */ | ||
1312 | } | ||
1313 | last = pos; | ||
1314 | } | ||
1315 | /* guard against sending "tiny" messages with large headers without | ||
1316 | urgent deadlines */ | ||
1317 | if ((slack > 1000) && (size > 4 * off)) | ||
1318 | { | ||
1319 | /* less than 25% of message would be filled with | ||
1320 | deadlines still being met if we delay by one | ||
1321 | second or more; so just wait for more data */ | ||
1322 | retry_time->value = slack / 2; | ||
1323 | /* reset do_transmit values for next time */ | ||
1324 | while (pos != last) | ||
1325 | { | ||
1326 | pos->do_transmit = GNUNET_NO; | ||
1327 | pos = pos->next; | ||
1328 | } | ||
1329 | return 0; | ||
1330 | } | ||
1331 | /* select marked messages (up to size) for transmission */ | ||
1332 | off = 0; | ||
1333 | pos = n->messages; | ||
1334 | while (pos != last) | ||
1335 | { | ||
1336 | if ((pos->size <= size) && (pos->do_transmit == GNUNET_NO)) | ||
1337 | { | ||
1338 | pos->do_transmit = GNUNET_YES; /* mark for transmission */ | ||
1339 | off += pos->size; | ||
1340 | size -= pos->size; | ||
1341 | } | ||
1342 | else | ||
1343 | pos->do_transmit = GNUNET_NO; /* mark for not transmitting! */ | ||
1344 | pos = pos->next; | ||
1345 | } | ||
1346 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1347 | "Selected %u bytes of plaintext messages for transmission to `%4s'.\n", | ||
1348 | off, GNUNET_i2s (&n->peer)); | ||
1349 | return off; | ||
1350 | } | ||
1351 | |||
1352 | |||
1353 | /** | ||
1354 | * Batch multiple messages into a larger buffer. | ||
1355 | * | ||
1356 | * @param n neighbour to take messages from | ||
1357 | * @param buf target buffer | ||
1358 | * @param size size of buf | ||
1359 | * @param deadline set to transmission deadline for the result | ||
1360 | * @param retry_time set to the time when we should try again | ||
1361 | * (only valid if this function returns zero) | ||
1362 | * @param priority set to the priority of the batch | ||
1363 | * @return number of bytes written to buf (can be zero) | ||
1364 | */ | ||
1365 | static size_t | ||
1366 | batch_message (struct Neighbour *n, | ||
1367 | char *buf, | ||
1368 | size_t size, | ||
1369 | struct GNUNET_TIME_Absolute *deadline, | ||
1370 | struct GNUNET_TIME_Relative *retry_time, | ||
1371 | unsigned int *priority) | ||
1372 | { | ||
1373 | struct MessageEntry *pos; | ||
1374 | struct MessageEntry *prev; | ||
1375 | struct MessageEntry *next; | ||
1376 | size_t ret; | ||
1377 | |||
1378 | ret = 0; | ||
1379 | *priority = 0; | ||
1380 | *deadline = GNUNET_TIME_UNIT_FOREVER_ABS; | ||
1381 | *retry_time = GNUNET_TIME_UNIT_FOREVER_REL; | ||
1382 | if (0 == select_messages (n, size, retry_time)) | ||
1383 | { | ||
1384 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1385 | "No messages selected, will try again in %llu ms\n", | ||
1386 | retry_time->value); | ||
1387 | return 0; | ||
1388 | } | ||
1389 | pos = n->messages; | ||
1390 | prev = NULL; | ||
1391 | while ((pos != NULL) && (size >= sizeof (struct GNUNET_MessageHeader))) | ||
1392 | { | ||
1393 | next = pos->next; | ||
1394 | if (GNUNET_YES == pos->do_transmit) | ||
1395 | { | ||
1396 | GNUNET_assert (pos->size <= size); | ||
1397 | memcpy (&buf[ret], &pos[1], pos->size); | ||
1398 | ret += pos->size; | ||
1399 | size -= pos->size; | ||
1400 | *priority += pos->priority; | ||
1401 | deadline->value = GNUNET_MIN (deadline->value, pos->deadline.value); | ||
1402 | GNUNET_free (pos); | ||
1403 | if (prev == NULL) | ||
1404 | n->messages = next; | ||
1405 | else | ||
1406 | prev->next = next; | ||
1407 | } | ||
1408 | else | ||
1409 | { | ||
1410 | prev = pos; | ||
1411 | } | ||
1412 | pos = next; | ||
1413 | } | ||
1414 | return ret; | ||
1415 | } | ||
1416 | |||
1417 | |||
1418 | /** | ||
1419 | * Remove messages with deadlines that have long expired from | ||
1420 | * the queue. | ||
1421 | * | ||
1422 | * @param n neighbour to inspect | ||
1423 | */ | ||
1424 | static void | ||
1425 | discard_expired_messages (struct Neighbour *n) | ||
1426 | { | ||
1427 | /* FIXME */ | ||
1428 | } | ||
1429 | |||
1430 | |||
1431 | /** | ||
1432 | * Signature of the main function of a task. | ||
1433 | * | ||
1434 | * @param cls closure | ||
1435 | * @param tc context information (why was this task triggered now) | ||
1436 | */ | ||
1437 | static void | ||
1438 | retry_plaintext_processing (void *cls, | ||
1439 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
1440 | { | ||
1441 | struct Neighbour *n = cls; | ||
1442 | |||
1443 | n->retry_plaintext_task = GNUNET_SCHEDULER_NO_PREREQUISITE_TASK; | ||
1444 | process_plaintext_neighbour_queue (n); | ||
1445 | } | ||
1446 | |||
1447 | |||
1448 | /** | ||
1449 | * Send our key (and encrypted PING) to the other peer. | ||
1450 | * | ||
1451 | * @param n the other peer | ||
1452 | */ | ||
1453 | static void send_key (struct Neighbour *n); | ||
1454 | |||
1455 | |||
1456 | /** | ||
1457 | * Check if we have plaintext messages for the specified neighbour | ||
1458 | * pending, and if so, consider batching and encrypting them (and | ||
1459 | * then trigger processing of the encrypted queue if needed). | ||
1460 | * | ||
1461 | * @param n neighbour to check. | ||
1462 | */ | ||
1463 | static void | ||
1464 | process_plaintext_neighbour_queue (struct Neighbour *n) | ||
1465 | { | ||
1466 | char pbuf[MAX_ENCRYPTED_MESSAGE_SIZE]; /* plaintext */ | ||
1467 | size_t used; | ||
1468 | size_t esize; | ||
1469 | struct EncryptedMessage *em; /* encrypted message */ | ||
1470 | struct EncryptedMessage *ph; /* plaintext header */ | ||
1471 | struct MessageEntry *me; | ||
1472 | unsigned int priority; | ||
1473 | struct GNUNET_TIME_Absolute deadline; | ||
1474 | struct GNUNET_TIME_Relative retry_time; | ||
1475 | |||
1476 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1477 | "Processing plaintext message queue for `%4s', scheduling messages.\n", | ||
1478 | GNUNET_i2s (&n->peer)); | ||
1479 | if (n->retry_plaintext_task != GNUNET_SCHEDULER_NO_PREREQUISITE_TASK) | ||
1480 | { | ||
1481 | GNUNET_SCHEDULER_cancel (sched, n->retry_plaintext_task); | ||
1482 | n->retry_plaintext_task = GNUNET_SCHEDULER_NO_PREREQUISITE_TASK; | ||
1483 | } | ||
1484 | switch (n->status) | ||
1485 | { | ||
1486 | case PEER_STATE_DOWN: | ||
1487 | send_key (n); | ||
1488 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1489 | "Not yet connected, deferring processing of plaintext messages.\n"); | ||
1490 | return; | ||
1491 | case PEER_STATE_KEY_SENT: | ||
1492 | GNUNET_assert (n->retry_set_key_task != | ||
1493 | GNUNET_SCHEDULER_NO_PREREQUISITE_TASK); | ||
1494 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1495 | "Not yet connected, deferring processing of plaintext messages.\n"); | ||
1496 | return; | ||
1497 | case PEER_STATE_KEY_RECEIVED: | ||
1498 | GNUNET_assert (n->retry_set_key_task != | ||
1499 | GNUNET_SCHEDULER_NO_PREREQUISITE_TASK); | ||
1500 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1501 | "Not yet connected, deferring processing of plaintext messages.\n"); | ||
1502 | return; | ||
1503 | case PEER_STATE_KEY_CONFIRMED: | ||
1504 | /* ready to continue */ | ||
1505 | break; | ||
1506 | } | ||
1507 | if (n->messages == NULL) | ||
1508 | { | ||
1509 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1510 | "Plaintext message queue is empty.\n"); | ||
1511 | return; /* no pending messages */ | ||
1512 | } | ||
1513 | discard_expired_messages (n); | ||
1514 | if (n->encrypted_head != NULL) | ||
1515 | { | ||
1516 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1517 | "Encrypted message queue is still full, delaying plaintext processing.\n"); | ||
1518 | return; /* wait for messages already encrypted to be | ||
1519 | processed first! */ | ||
1520 | } | ||
1521 | ph = (struct EncryptedMessage *) pbuf; | ||
1522 | deadline = GNUNET_TIME_UNIT_FOREVER_ABS; | ||
1523 | priority = 0; | ||
1524 | used = sizeof (struct EncryptedMessage); | ||
1525 | |||
1526 | used += batch_message (n, | ||
1527 | &pbuf[used], | ||
1528 | MAX_ENCRYPTED_MESSAGE_SIZE - used, | ||
1529 | &deadline, &retry_time, &priority); | ||
1530 | if (used == sizeof (struct EncryptedMessage)) | ||
1531 | { | ||
1532 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1533 | "No messages selected for processing at this time, will try again later.\n"); | ||
1534 | /* no messages selected for sending, try again later... */ | ||
1535 | n->retry_plaintext_task = | ||
1536 | GNUNET_SCHEDULER_add_delayed (sched, | ||
1537 | GNUNET_NO, | ||
1538 | GNUNET_SCHEDULER_PRIORITY_IDLE, | ||
1539 | GNUNET_SCHEDULER_NO_PREREQUISITE_TASK, | ||
1540 | retry_time, | ||
1541 | &retry_plaintext_processing, n); | ||
1542 | return; | ||
1543 | } | ||
1544 | |||
1545 | ph->sequence_number = htonl (++n->last_sequence_number_sent); | ||
1546 | ph->inbound_bpm_limit = htonl (n->bpm_in); | ||
1547 | ph->timestamp = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ()); | ||
1548 | |||
1549 | /* setup encryption message header */ | ||
1550 | me = GNUNET_malloc (sizeof (struct MessageEntry) + used); | ||
1551 | me->deadline = deadline; | ||
1552 | me->priority = priority; | ||
1553 | me->size = used; | ||
1554 | em = (struct EncryptedMessage *) &me[1]; | ||
1555 | em->header.size = htons (used); | ||
1556 | em->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_ENCRYPTED_MESSAGE); | ||
1557 | em->reserved = htonl (0); | ||
1558 | esize = used - ENCRYPTED_HEADER_SIZE; | ||
1559 | GNUNET_CRYPTO_hash (&ph->sequence_number, esize, &em->plaintext_hash); | ||
1560 | /* encrypt */ | ||
1561 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1562 | "Encrypting plaintext messages for transmission.\n"); | ||
1563 | GNUNET_assert (GNUNET_OK == | ||
1564 | do_encrypt (n, | ||
1565 | &em->plaintext_hash, | ||
1566 | &ph->sequence_number, | ||
1567 | &em->sequence_number, esize)); | ||
1568 | /* append to transmission list */ | ||
1569 | if (n->encrypted_tail == NULL) | ||
1570 | n->encrypted_head = me; | ||
1571 | else | ||
1572 | n->encrypted_tail->next = me; | ||
1573 | n->encrypted_tail = me; | ||
1574 | process_encrypted_neighbour_queue (n); | ||
1575 | } | ||
1576 | |||
1577 | |||
1578 | /** | ||
1579 | * Handle CORE_SEND request. | ||
1580 | */ | ||
1581 | static void | ||
1582 | handle_client_send (void *cls, | ||
1583 | struct GNUNET_SERVER_Handle *server, | ||
1584 | struct GNUNET_SERVER_Client *client, | ||
1585 | const struct GNUNET_MessageHeader *message); | ||
1586 | |||
1587 | |||
1588 | /** | ||
1589 | * Function called to notify us that we either succeeded | ||
1590 | * or failed to connect (at the transport level) to another | ||
1591 | * peer. We should either free the message we were asked | ||
1592 | * to transmit or re-try adding it to the queue. | ||
1593 | * | ||
1594 | * @param cls closure | ||
1595 | * @param size number of bytes available in buf | ||
1596 | * @param buf where the callee should write the message | ||
1597 | * @return number of bytes written to buf | ||
1598 | */ | ||
1599 | static size_t | ||
1600 | send_connect_continuation (void *cls, size_t size, void *buf) | ||
1601 | { | ||
1602 | struct SendMessage *sm = cls; | ||
1603 | |||
1604 | if (buf == NULL) | ||
1605 | { | ||
1606 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1607 | "Asked to send message to disconnected peer `%4s' and connection failed. Discarding message.\n", | ||
1608 | GNUNET_i2s (&sm->peer)); | ||
1609 | GNUNET_free (sm); | ||
1610 | return 0; | ||
1611 | } | ||
1612 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1613 | "Connection to peer `%4s' succeeded, retrying original send request\n", | ||
1614 | GNUNET_i2s (&sm->peer)); | ||
1615 | handle_client_send (NULL, NULL, NULL, &sm->header); | ||
1616 | GNUNET_free (sm); | ||
1617 | return 0; | ||
1618 | } | ||
1619 | |||
1620 | |||
1621 | /** | ||
1622 | * Handle CORE_SEND request. | ||
1623 | */ | ||
1624 | static void | ||
1625 | handle_client_send (void *cls, | ||
1626 | struct GNUNET_SERVER_Handle *server, | ||
1627 | struct GNUNET_SERVER_Client *client, | ||
1628 | const struct GNUNET_MessageHeader *message) | ||
1629 | { | ||
1630 | const struct SendMessage *sm; | ||
1631 | struct SendMessage *smc; | ||
1632 | const struct GNUNET_MessageHeader *mh; | ||
1633 | struct Neighbour *n; | ||
1634 | struct MessageEntry *pred; | ||
1635 | struct MessageEntry *pos; | ||
1636 | struct MessageEntry *e; | ||
1637 | uint16_t msize; | ||
1638 | |||
1639 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1640 | "Core service receives `%s' request.\n", "SEND"); | ||
1641 | msize = ntohs (message->size); | ||
1642 | if (msize < | ||
1643 | sizeof (struct SendMessage) + sizeof (struct GNUNET_MessageHeader)) | ||
1644 | { | ||
1645 | GNUNET_break (0); | ||
1646 | if (client != NULL) | ||
1647 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
1648 | return; | ||
1649 | } | ||
1650 | sm = (const struct SendMessage *) message; | ||
1651 | msize -= sizeof (struct SendMessage); | ||
1652 | mh = (const struct GNUNET_MessageHeader *) &sm[1]; | ||
1653 | if (msize != ntohs (mh->size)) | ||
1654 | { | ||
1655 | GNUNET_break (0); | ||
1656 | if (client != NULL) | ||
1657 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
1658 | return; | ||
1659 | } | ||
1660 | n = find_neighbour (&sm->peer); | ||
1661 | if (n == NULL) | ||
1662 | { | ||
1663 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1664 | "Not yet connected to `%4s', will try to establish connection\n", | ||
1665 | GNUNET_i2s (&sm->peer)); | ||
1666 | msize += sizeof (struct SendMessage); | ||
1667 | /* ask transport to connect to the peer */ | ||
1668 | /* FIXME: this code does not handle the | ||
1669 | case where we get multiple SendMessages before | ||
1670 | transport responds to this request; | ||
1671 | => need to track pending requests! */ | ||
1672 | smc = GNUNET_malloc (msize); | ||
1673 | memcpy (smc, sm, msize); | ||
1674 | GNUNET_TRANSPORT_notify_transmit_ready (transport, | ||
1675 | &sm->peer, | ||
1676 | 0, | ||
1677 | GNUNET_TIME_absolute_get_remaining | ||
1678 | (GNUNET_TIME_absolute_ntoh | ||
1679 | (sm->deadline)), | ||
1680 | &send_connect_continuation, | ||
1681 | smc); | ||
1682 | if (client != NULL) | ||
1683 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
1684 | return; | ||
1685 | } | ||
1686 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1687 | "Core queues %u bytes of plaintext data for transmission to `%4s'.\n", | ||
1688 | msize, GNUNET_i2s (&sm->peer)); | ||
1689 | /* FIXME: consider bounding queue size */ | ||
1690 | e = GNUNET_malloc (sizeof (struct MessageEntry) + msize); | ||
1691 | e->deadline = GNUNET_TIME_absolute_ntoh (sm->deadline); | ||
1692 | e->priority = ntohl (sm->priority); | ||
1693 | e->size = msize; | ||
1694 | memcpy (&e[1], mh, msize); | ||
1695 | |||
1696 | /* insert, keep list sorted by deadline */ | ||
1697 | pred = NULL; | ||
1698 | pos = n->messages; | ||
1699 | while ((pos != NULL) && (pos->deadline.value < e->deadline.value)) | ||
1700 | { | ||
1701 | pred = pos; | ||
1702 | pos = pos->next; | ||
1703 | } | ||
1704 | if (pred == NULL) | ||
1705 | n->messages = e; | ||
1706 | else | ||
1707 | pred->next = e; | ||
1708 | e->next = pos; | ||
1709 | |||
1710 | /* consider scheduling now */ | ||
1711 | process_plaintext_neighbour_queue (n); | ||
1712 | if (client != NULL) | ||
1713 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
1714 | } | ||
1715 | |||
1716 | |||
1717 | /** | ||
1718 | * List of handlers for the messages understood by this | ||
1719 | * service. | ||
1720 | */ | ||
1721 | static struct GNUNET_SERVER_MessageHandler handlers[] = { | ||
1722 | {&handle_client_init, NULL, | ||
1723 | GNUNET_MESSAGE_TYPE_CORE_INIT, 0}, | ||
1724 | {&handle_client_request_configure, NULL, | ||
1725 | GNUNET_MESSAGE_TYPE_CORE_REQUEST_CONFIGURE, | ||
1726 | sizeof (struct RequestConfigureMessage)}, | ||
1727 | {&handle_client_send, NULL, | ||
1728 | GNUNET_MESSAGE_TYPE_CORE_SEND, 0}, | ||
1729 | {NULL, NULL, 0, 0} | ||
1730 | }; | ||
1731 | |||
1732 | |||
1733 | /** | ||
1734 | * PEERINFO is giving us a HELLO for a peer. Add the | ||
1735 | * public key to the neighbour's struct and retry | ||
1736 | * send_key. Or, if we did not get a HELLO, just do | ||
1737 | * nothing. | ||
1738 | * | ||
1739 | * @param cls NULL | ||
1740 | * @param peer the peer for which this is the HELLO | ||
1741 | * @param hello HELLO message of that peer | ||
1742 | * @param trust amount of trust we currently have in that peer | ||
1743 | */ | ||
1744 | static void | ||
1745 | process_hello_retry_send_key (void *cls, | ||
1746 | const struct GNUNET_PeerIdentity *peer, | ||
1747 | const struct GNUNET_HELLO_Message *hello, | ||
1748 | uint32_t trust) | ||
1749 | { | ||
1750 | struct Neighbour *n; | ||
1751 | |||
1752 | if (peer == NULL) | ||
1753 | return; | ||
1754 | n = find_neighbour (peer); | ||
1755 | if (n == NULL) | ||
1756 | return; | ||
1757 | if (n->public_key != NULL) | ||
1758 | return; | ||
1759 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1760 | "Received new HELLO for `%4s', initiating key exchange.\n", | ||
1761 | GNUNET_i2s (peer)); | ||
1762 | n->public_key = | ||
1763 | GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); | ||
1764 | if (GNUNET_OK != GNUNET_HELLO_get_key (hello, n->public_key)) | ||
1765 | { | ||
1766 | GNUNET_free (n->public_key); | ||
1767 | n->public_key = NULL; | ||
1768 | return; | ||
1769 | } | ||
1770 | send_key (n); | ||
1771 | } | ||
1772 | |||
1773 | |||
1774 | /** | ||
1775 | * Task that will retry "send_key" if our previous attempt failed | ||
1776 | * to yield a PONG. | ||
1777 | */ | ||
1778 | static void | ||
1779 | set_key_retry_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
1780 | { | ||
1781 | struct Neighbour *n = cls; | ||
1782 | |||
1783 | GNUNET_assert (n->status != PEER_STATE_KEY_CONFIRMED); | ||
1784 | n->retry_set_key_task = GNUNET_SCHEDULER_NO_PREREQUISITE_TASK; | ||
1785 | n->set_key_retry_frequency = | ||
1786 | GNUNET_TIME_relative_multiply (n->set_key_retry_frequency, 2); | ||
1787 | send_key (n); | ||
1788 | } | ||
1789 | |||
1790 | |||
1791 | /** | ||
1792 | * Send our key (and encrypted PING) to the other peer. | ||
1793 | * | ||
1794 | * @param n the other peer | ||
1795 | */ | ||
1796 | static void | ||
1797 | send_key (struct Neighbour *n) | ||
1798 | { | ||
1799 | struct SetKeyMessage *sm; | ||
1800 | struct MessageEntry *me; | ||
1801 | struct PingMessage pp; | ||
1802 | struct PingMessage *pm; | ||
1803 | |||
1804 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1805 | "Asked to perform key exchange with `%4s'.\n", | ||
1806 | GNUNET_i2s (&n->peer)); | ||
1807 | if (n->public_key == NULL) | ||
1808 | { | ||
1809 | /* lookup n's public key, then try again */ | ||
1810 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1811 | "Lacking public key for `%4s', trying to obtain one.\n", | ||
1812 | GNUNET_i2s (&n->peer)); | ||
1813 | GNUNET_PEERINFO_for_all (cfg, | ||
1814 | sched, | ||
1815 | &n->peer, | ||
1816 | 0, | ||
1817 | GNUNET_TIME_UNIT_MINUTES, | ||
1818 | &process_hello_retry_send_key, NULL); | ||
1819 | return; | ||
1820 | } | ||
1821 | /* first, set key message */ | ||
1822 | me = GNUNET_malloc (sizeof (struct MessageEntry) + | ||
1823 | sizeof (struct SetKeyMessage)); | ||
1824 | me->deadline = GNUNET_TIME_relative_to_absolute (MAX_SET_KEY_DELAY); | ||
1825 | me->priority = SET_KEY_PRIORITY; | ||
1826 | me->size = sizeof (struct SetKeyMessage); | ||
1827 | if (n->encrypted_head == NULL) | ||
1828 | n->encrypted_head = me; | ||
1829 | else | ||
1830 | n->encrypted_tail->next = me; | ||
1831 | n->encrypted_tail = me; | ||
1832 | sm = (struct SetKeyMessage *) &me[1]; | ||
1833 | sm->header.size = htons (sizeof (struct SetKeyMessage)); | ||
1834 | sm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_SET_KEY); | ||
1835 | sm->sender_status = htonl ((int32_t) ((n->status == PEER_STATE_DOWN) ? | ||
1836 | PEER_STATE_KEY_SENT : n->status)); | ||
1837 | sm->purpose.size = | ||
1838 | htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) + | ||
1839 | sizeof (struct GNUNET_TIME_AbsoluteNBO) + | ||
1840 | sizeof (struct GNUNET_CRYPTO_RsaEncryptedData) + | ||
1841 | sizeof (struct GNUNET_PeerIdentity)); | ||
1842 | sm->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_SET_KEY); | ||
1843 | sm->creation_time = GNUNET_TIME_absolute_hton (n->encrypt_key_created); | ||
1844 | sm->target = n->peer; | ||
1845 | GNUNET_assert (GNUNET_OK == | ||
1846 | GNUNET_CRYPTO_rsa_encrypt (&n->encrypt_key, | ||
1847 | sizeof (struct | ||
1848 | GNUNET_CRYPTO_AesSessionKey), | ||
1849 | n->public_key, | ||
1850 | &sm->encrypted_key)); | ||
1851 | GNUNET_assert (GNUNET_OK == | ||
1852 | GNUNET_CRYPTO_rsa_sign (my_private_key, &sm->purpose, | ||
1853 | &sm->signature)); | ||
1854 | |||
1855 | /* second, encrypted PING message */ | ||
1856 | me = GNUNET_malloc (sizeof (struct MessageEntry) + | ||
1857 | sizeof (struct PingMessage)); | ||
1858 | me->deadline = GNUNET_TIME_relative_to_absolute (MAX_PING_DELAY); | ||
1859 | me->priority = PING_PRIORITY; | ||
1860 | me->size = sizeof (struct PingMessage); | ||
1861 | n->encrypted_tail->next = me; | ||
1862 | n->encrypted_tail = me; | ||
1863 | pm = (struct PingMessage *) &me[1]; | ||
1864 | pm->header.size = htons (sizeof (struct PingMessage)); | ||
1865 | pm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_PING); | ||
1866 | pp.challenge = htonl (n->ping_challenge); | ||
1867 | pp.target = n->peer; | ||
1868 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1869 | "Encrypting `%s' and `%s' messages for `%4s'.\n", | ||
1870 | "SET_KEY", "PING", GNUNET_i2s (&n->peer)); | ||
1871 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1872 | "Sending `%s' to `%4s' with challenge %u encrypted using key %u\n", | ||
1873 | "PING", | ||
1874 | GNUNET_i2s (&n->peer), n->ping_challenge, n->encrypt_key.crc32); | ||
1875 | do_encrypt (n, | ||
1876 | &n->peer.hashPubKey, | ||
1877 | &pp.challenge, | ||
1878 | &pm->challenge, | ||
1879 | sizeof (struct PingMessage) - | ||
1880 | sizeof (struct GNUNET_MessageHeader)); | ||
1881 | /* update status */ | ||
1882 | switch (n->status) | ||
1883 | { | ||
1884 | case PEER_STATE_DOWN: | ||
1885 | n->status = PEER_STATE_KEY_SENT; | ||
1886 | break; | ||
1887 | case PEER_STATE_KEY_SENT: | ||
1888 | break; | ||
1889 | case PEER_STATE_KEY_RECEIVED: | ||
1890 | break; | ||
1891 | case PEER_STATE_KEY_CONFIRMED: | ||
1892 | GNUNET_break (0); | ||
1893 | break; | ||
1894 | default: | ||
1895 | GNUNET_break (0); | ||
1896 | break; | ||
1897 | } | ||
1898 | /* trigger queue processing */ | ||
1899 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1900 | "Triggering processing of encrypted message queue.\n"); | ||
1901 | process_encrypted_neighbour_queue (n); | ||
1902 | if (n->status != PEER_STATE_KEY_CONFIRMED) | ||
1903 | n->retry_set_key_task | ||
1904 | = GNUNET_SCHEDULER_add_delayed (sched, | ||
1905 | GNUNET_NO, | ||
1906 | GNUNET_SCHEDULER_PRIORITY_KEEP, | ||
1907 | GNUNET_SCHEDULER_NO_PREREQUISITE_TASK, | ||
1908 | n->set_key_retry_frequency, | ||
1909 | &set_key_retry_task, n); | ||
1910 | } | ||
1911 | |||
1912 | |||
1913 | /** | ||
1914 | * We received a SET_KEY message. Validate and update | ||
1915 | * our key material and status. | ||
1916 | * | ||
1917 | * @param n the neighbour from which we received message m | ||
1918 | * @param m the set key message we received | ||
1919 | */ | ||
1920 | static void | ||
1921 | handle_set_key (struct Neighbour *n, const struct SetKeyMessage *m); | ||
1922 | |||
1923 | |||
1924 | /** | ||
1925 | * PEERINFO is giving us a HELLO for a peer. Add the public key to | ||
1926 | * the neighbour's struct and retry handling the set_key message. Or, | ||
1927 | * if we did not get a HELLO, just free the set key message. | ||
1928 | * | ||
1929 | * @param cls pointer to the set key message | ||
1930 | * @param peer the peer for which this is the HELLO | ||
1931 | * @param hello HELLO message of that peer | ||
1932 | * @param trust amount of trust we currently have in that peer | ||
1933 | */ | ||
1934 | static void | ||
1935 | process_hello_retry_handle_set_key (void *cls, | ||
1936 | const struct GNUNET_PeerIdentity *peer, | ||
1937 | const struct GNUNET_HELLO_Message *hello, | ||
1938 | uint32_t trust) | ||
1939 | { | ||
1940 | struct SetKeyMessage *sm = cls; | ||
1941 | struct Neighbour *n; | ||
1942 | |||
1943 | if (peer == NULL) | ||
1944 | { | ||
1945 | GNUNET_free (sm); | ||
1946 | return; | ||
1947 | } | ||
1948 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1949 | "Looking for peer `%4s' to handle `%s' message.\n", | ||
1950 | GNUNET_i2s (peer), "SET_KEY"); | ||
1951 | n = find_neighbour (peer); | ||
1952 | if (n == NULL) | ||
1953 | { | ||
1954 | GNUNET_break (0); | ||
1955 | return; | ||
1956 | } | ||
1957 | if (n->public_key != NULL) | ||
1958 | return; /* multiple HELLOs match!? */ | ||
1959 | n->public_key = | ||
1960 | GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); | ||
1961 | if (GNUNET_OK != GNUNET_HELLO_get_key (hello, n->public_key)) | ||
1962 | { | ||
1963 | GNUNET_free (n->public_key); | ||
1964 | n->public_key = NULL; | ||
1965 | return; | ||
1966 | } | ||
1967 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1968 | "Received `%s' for `%4s', continuing processing of `%s' message.\n", | ||
1969 | "HELLO", GNUNET_i2s (peer), "SET_KEY"); | ||
1970 | handle_set_key (n, sm); | ||
1971 | } | ||
1972 | |||
1973 | |||
1974 | /** | ||
1975 | * We received a PING message. Validate and transmit | ||
1976 | * PONG. | ||
1977 | * | ||
1978 | * @param n sender of the PING | ||
1979 | * @param m the encrypted PING message itself | ||
1980 | */ | ||
1981 | static void | ||
1982 | handle_ping (struct Neighbour *n, const struct PingMessage *m) | ||
1983 | { | ||
1984 | struct PingMessage t; | ||
1985 | struct PingMessage *tp; | ||
1986 | struct MessageEntry *me; | ||
1987 | |||
1988 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1989 | "Core service receives `%s' request from `%4s'.\n", | ||
1990 | "PING", GNUNET_i2s (&n->peer)); | ||
1991 | if (GNUNET_OK != | ||
1992 | do_decrypt (n, | ||
1993 | &my_identity.hashPubKey, | ||
1994 | &m->challenge, | ||
1995 | &t.challenge, | ||
1996 | sizeof (struct PingMessage) - | ||
1997 | sizeof (struct GNUNET_MessageHeader))) | ||
1998 | return; | ||
1999 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2000 | "Decrypted `%s' to `%4s' with challenge %u decrypted using key %u\n", | ||
2001 | "PING", | ||
2002 | GNUNET_i2s (&t.target), | ||
2003 | ntohl (t.challenge), n->decrypt_key.crc32); | ||
2004 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2005 | "Target of `%s' request is `%4s'.\n", | ||
2006 | "PING", GNUNET_i2s (&t.target)); | ||
2007 | if (0 != memcmp (&t.target, | ||
2008 | &my_identity, sizeof (struct GNUNET_PeerIdentity))) | ||
2009 | { | ||
2010 | GNUNET_break_op (0); | ||
2011 | return; | ||
2012 | } | ||
2013 | me = GNUNET_malloc (sizeof (struct MessageEntry) + | ||
2014 | sizeof (struct PingMessage)); | ||
2015 | if (n->encrypted_tail != NULL) | ||
2016 | n->encrypted_tail->next = me; | ||
2017 | else | ||
2018 | { | ||
2019 | n->encrypted_tail = me; | ||
2020 | n->encrypted_head = me; | ||
2021 | } | ||
2022 | me->deadline = GNUNET_TIME_relative_to_absolute (MAX_PONG_DELAY); | ||
2023 | me->priority = PONG_PRIORITY; | ||
2024 | me->size = sizeof (struct PingMessage); | ||
2025 | tp = (struct PingMessage *) &me[1]; | ||
2026 | tp->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_PONG); | ||
2027 | tp->header.size = htons (sizeof (struct PingMessage)); | ||
2028 | do_encrypt (n, | ||
2029 | &my_identity.hashPubKey, | ||
2030 | &t.challenge, | ||
2031 | &tp->challenge, | ||
2032 | sizeof (struct PingMessage) - | ||
2033 | sizeof (struct GNUNET_MessageHeader)); | ||
2034 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2035 | "Encrypting `%s' with challenge %u using key %u\n", "PONG", | ||
2036 | ntohl (t.challenge), n->encrypt_key.crc32); | ||
2037 | /* trigger queue processing */ | ||
2038 | process_encrypted_neighbour_queue (n); | ||
2039 | } | ||
2040 | |||
2041 | |||
2042 | /** | ||
2043 | * We received a SET_KEY message. Validate and update | ||
2044 | * our key material and status. | ||
2045 | * | ||
2046 | * @param n the neighbour from which we received message m | ||
2047 | * @param m the set key message we received | ||
2048 | */ | ||
2049 | static void | ||
2050 | handle_set_key (struct Neighbour *n, const struct SetKeyMessage *m) | ||
2051 | { | ||
2052 | struct SetKeyMessage *m_cpy; | ||
2053 | struct GNUNET_TIME_Absolute t; | ||
2054 | struct GNUNET_CRYPTO_AesSessionKey k; | ||
2055 | struct PingMessage *ping; | ||
2056 | enum PeerStateMachine sender_status; | ||
2057 | |||
2058 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2059 | "Core service receives `%s' request from `%4s'.\n", | ||
2060 | "SET_KEY", GNUNET_i2s (&n->peer)); | ||
2061 | if (n->public_key == NULL) | ||
2062 | { | ||
2063 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2064 | "Lacking public key for peer, trying to obtain one.\n"); | ||
2065 | m_cpy = GNUNET_malloc (sizeof (struct SetKeyMessage)); | ||
2066 | memcpy (m_cpy, m, sizeof (struct SetKeyMessage)); | ||
2067 | /* lookup n's public key, then try again */ | ||
2068 | GNUNET_PEERINFO_for_all (cfg, | ||
2069 | sched, | ||
2070 | &n->peer, | ||
2071 | 0, | ||
2072 | GNUNET_TIME_UNIT_MINUTES, | ||
2073 | &process_hello_retry_handle_set_key, m_cpy); | ||
2074 | return; | ||
2075 | } | ||
2076 | if ((ntohl (m->purpose.size) != | ||
2077 | sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) + | ||
2078 | sizeof (struct GNUNET_TIME_AbsoluteNBO) + | ||
2079 | sizeof (struct GNUNET_CRYPTO_RsaEncryptedData) + | ||
2080 | sizeof (struct GNUNET_PeerIdentity)) || | ||
2081 | (GNUNET_OK != | ||
2082 | GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_SET_KEY, | ||
2083 | &m->purpose, &m->signature, n->public_key))) | ||
2084 | { | ||
2085 | /* invalid signature */ | ||
2086 | GNUNET_break_op (0); | ||
2087 | return; | ||
2088 | } | ||
2089 | t = GNUNET_TIME_absolute_ntoh (m->creation_time); | ||
2090 | if (((n->status == PEER_STATE_KEY_RECEIVED) || | ||
2091 | (n->status == PEER_STATE_KEY_CONFIRMED)) && | ||
2092 | (t.value < n->decrypt_key_created.value)) | ||
2093 | { | ||
2094 | /* this could rarely happen due to massive re-ordering of | ||
2095 | messages on the network level, but is most likely either | ||
2096 | a bug or some adversary messing with us. Report. */ | ||
2097 | GNUNET_break_op (0); | ||
2098 | return; | ||
2099 | } | ||
2100 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Decrypting key material.\n"); | ||
2101 | if ((GNUNET_CRYPTO_rsa_decrypt (my_private_key, | ||
2102 | &m->encrypted_key, | ||
2103 | &k, | ||
2104 | sizeof (struct GNUNET_CRYPTO_AesSessionKey)) | ||
2105 | != sizeof (struct GNUNET_CRYPTO_AesSessionKey)) || | ||
2106 | (GNUNET_OK != GNUNET_CRYPTO_aes_check_session_key (&k))) | ||
2107 | { | ||
2108 | /* failed to decrypt !? */ | ||
2109 | GNUNET_break_op (0); | ||
2110 | return; | ||
2111 | } | ||
2112 | |||
2113 | n->decrypt_key = k; | ||
2114 | if (n->decrypt_key_created.value != t.value) | ||
2115 | { | ||
2116 | /* fresh key, reset sequence numbers */ | ||
2117 | n->last_sequence_number_received = 0; | ||
2118 | n->last_packets_bitmap = 0; | ||
2119 | n->decrypt_key_created = t; | ||
2120 | } | ||
2121 | sender_status = (enum PeerStateMachine) ntohl (m->sender_status); | ||
2122 | switch (n->status) | ||
2123 | { | ||
2124 | case PEER_STATE_DOWN: | ||
2125 | n->status = PEER_STATE_KEY_RECEIVED; | ||
2126 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2127 | "Responding to `%s' with my own key.\n", "SET_KEY"); | ||
2128 | send_key (n); | ||
2129 | break; | ||
2130 | case PEER_STATE_KEY_SENT: | ||
2131 | case PEER_STATE_KEY_RECEIVED: | ||
2132 | n->status = PEER_STATE_KEY_RECEIVED; | ||
2133 | if ((sender_status != PEER_STATE_KEY_RECEIVED) && | ||
2134 | (sender_status != PEER_STATE_KEY_CONFIRMED)) | ||
2135 | { | ||
2136 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2137 | "Responding to `%s' with my own key (other peer has status %u).\n", | ||
2138 | "SET_KEY", sender_status); | ||
2139 | send_key (n); | ||
2140 | } | ||
2141 | break; | ||
2142 | case PEER_STATE_KEY_CONFIRMED: | ||
2143 | if ((sender_status != PEER_STATE_KEY_RECEIVED) && | ||
2144 | (sender_status != PEER_STATE_KEY_CONFIRMED)) | ||
2145 | { | ||
2146 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2147 | "Responding to `%s' with my own key (other peer has status %u), I was already fully up.\n", | ||
2148 | "SET_KEY", sender_status); | ||
2149 | send_key (n); | ||
2150 | } | ||
2151 | break; | ||
2152 | default: | ||
2153 | GNUNET_break (0); | ||
2154 | break; | ||
2155 | } | ||
2156 | if (n->pending_ping != NULL) | ||
2157 | { | ||
2158 | ping = n->pending_ping; | ||
2159 | n->pending_ping = NULL; | ||
2160 | handle_ping (n, ping); | ||
2161 | GNUNET_free (ping); | ||
2162 | } | ||
2163 | } | ||
2164 | |||
2165 | |||
2166 | /** | ||
2167 | * We received a PONG message. Validate and update | ||
2168 | * our status. | ||
2169 | * | ||
2170 | * @param n sender of the PONG | ||
2171 | * @param m the encrypted PONG message itself | ||
2172 | */ | ||
2173 | static void | ||
2174 | handle_pong (struct Neighbour *n, const struct PingMessage *m) | ||
2175 | { | ||
2176 | struct PingMessage t; | ||
2177 | |||
2178 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2179 | "Core service receives `%s' request from `%4s'.\n", | ||
2180 | "PONG", GNUNET_i2s (&n->peer)); | ||
2181 | if (GNUNET_OK != | ||
2182 | do_decrypt (n, | ||
2183 | &n->peer.hashPubKey, | ||
2184 | &m->challenge, | ||
2185 | &t.challenge, | ||
2186 | sizeof (struct PingMessage) - | ||
2187 | sizeof (struct GNUNET_MessageHeader))) | ||
2188 | return; | ||
2189 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2190 | "Decrypted `%s' from `%4s' with challenge %u using key %u\n", | ||
2191 | "PONG", | ||
2192 | GNUNET_i2s (&t.target), | ||
2193 | ntohl (t.challenge), n->decrypt_key.crc32); | ||
2194 | if ((0 != memcmp (&t.target, | ||
2195 | &n->peer, | ||
2196 | sizeof (struct GNUNET_PeerIdentity))) || | ||
2197 | (n->ping_challenge != ntohl (t.challenge))) | ||
2198 | { | ||
2199 | /* PONG malformed */ | ||
2200 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2201 | "Received malfromed `%s' wanted sender `%4s' with challenge %u\n", | ||
2202 | "PONG", GNUNET_i2s (&n->peer), n->ping_challenge); | ||
2203 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2204 | "Received malfromed `%s' received from `%4s' with challenge %u\n", | ||
2205 | "PONG", GNUNET_i2s (&t.target), ntohl (t.challenge)); | ||
2206 | GNUNET_break_op (0); | ||
2207 | return; | ||
2208 | } | ||
2209 | switch (n->status) | ||
2210 | { | ||
2211 | case PEER_STATE_DOWN: | ||
2212 | GNUNET_break (0); /* should be impossible */ | ||
2213 | return; | ||
2214 | case PEER_STATE_KEY_SENT: | ||
2215 | GNUNET_break (0); /* should be impossible, how did we decrypt? */ | ||
2216 | return; | ||
2217 | case PEER_STATE_KEY_RECEIVED: | ||
2218 | n->status = PEER_STATE_KEY_CONFIRMED; | ||
2219 | if (n->retry_set_key_task != GNUNET_SCHEDULER_NO_PREREQUISITE_TASK) | ||
2220 | { | ||
2221 | GNUNET_SCHEDULER_cancel (sched, n->retry_set_key_task); | ||
2222 | n->retry_set_key_task = GNUNET_SCHEDULER_NO_PREREQUISITE_TASK; | ||
2223 | } | ||
2224 | process_encrypted_neighbour_queue (n); | ||
2225 | break; | ||
2226 | case PEER_STATE_KEY_CONFIRMED: | ||
2227 | /* duplicate PONG? */ | ||
2228 | break; | ||
2229 | default: | ||
2230 | GNUNET_break (0); | ||
2231 | break; | ||
2232 | } | ||
2233 | } | ||
2234 | |||
2235 | |||
2236 | /** | ||
2237 | * Send a P2P message to a client. | ||
2238 | * | ||
2239 | * @param sender who sent us the message? | ||
2240 | * @param client who should we give the message to? | ||
2241 | * @param m contains the message to transmit | ||
2242 | * @param msize number of bytes in buf to transmit | ||
2243 | */ | ||
2244 | static void | ||
2245 | send_p2p_message_to_client (struct Neighbour *sender, | ||
2246 | struct Client *client, | ||
2247 | const void *m, size_t msize) | ||
2248 | { | ||
2249 | char buf[msize + sizeof (struct NotifyTrafficMessage)]; | ||
2250 | struct NotifyTrafficMessage *ntm; | ||
2251 | |||
2252 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2253 | "Core service passes P2P message of type %u to client.\n", | ||
2254 | ntohs (((const struct GNUNET_MessageHeader *) m)->type)); | ||
2255 | ntm = (struct NotifyTrafficMessage *) buf; | ||
2256 | ntm->header.size = htons (msize + sizeof (struct NotifyTrafficMessage)); | ||
2257 | ntm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND); | ||
2258 | ntm->reserved = htonl (0); | ||
2259 | ntm->peer = sender->peer; | ||
2260 | memcpy (&ntm[1], m, msize); | ||
2261 | send_to_client (client, &ntm->header, GNUNET_YES); | ||
2262 | } | ||
2263 | |||
2264 | |||
2265 | /** | ||
2266 | * Deliver P2P message to interested clients. | ||
2267 | * | ||
2268 | * @param sender who sent us the message? | ||
2269 | * @param m the message | ||
2270 | * @param msize size of the message (including header) | ||
2271 | */ | ||
2272 | static void | ||
2273 | deliver_message (struct Neighbour *sender, | ||
2274 | const struct GNUNET_MessageHeader *m, size_t msize) | ||
2275 | { | ||
2276 | struct Client *cpos; | ||
2277 | uint16_t type; | ||
2278 | unsigned int tpos; | ||
2279 | int deliver_full; | ||
2280 | |||
2281 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2282 | "Passing decrypted P2P message to interested clients.\n"); | ||
2283 | type = ntohs (m->type); | ||
2284 | cpos = clients; | ||
2285 | while (cpos != NULL) | ||
2286 | { | ||
2287 | deliver_full = GNUNET_NO; | ||
2288 | if (cpos->options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND) | ||
2289 | deliver_full = GNUNET_YES; | ||
2290 | else | ||
2291 | { | ||
2292 | for (tpos = 0; tpos < cpos->tcnt; tpos++) | ||
2293 | { | ||
2294 | if (type != cpos->types[tpos]) | ||
2295 | continue; | ||
2296 | deliver_full = GNUNET_YES; | ||
2297 | break; | ||
2298 | } | ||
2299 | } | ||
2300 | if (GNUNET_YES == deliver_full) | ||
2301 | send_p2p_message_to_client (sender, cpos, m, msize); | ||
2302 | else if (cpos->options & GNUNET_CORE_OPTION_SEND_HDR_INBOUND) | ||
2303 | send_p2p_message_to_client (sender, cpos, m, | ||
2304 | sizeof (struct GNUNET_MessageHeader)); | ||
2305 | cpos = cpos->next; | ||
2306 | } | ||
2307 | } | ||
2308 | |||
2309 | |||
2310 | /** | ||
2311 | * Align P2P message and then deliver to interested clients. | ||
2312 | * | ||
2313 | * @param sender who sent us the message? | ||
2314 | * @param buffer unaligned (!) buffer containing message | ||
2315 | * @param msize size of the message (including header) | ||
2316 | */ | ||
2317 | static void | ||
2318 | align_and_deliver (struct Neighbour *sender, const char *buffer, size_t msize) | ||
2319 | { | ||
2320 | char abuf[msize]; | ||
2321 | |||
2322 | /* TODO: call to statistics? */ | ||
2323 | memcpy (abuf, buffer, msize); | ||
2324 | deliver_message (sender, (const struct GNUNET_MessageHeader *) abuf, msize); | ||
2325 | } | ||
2326 | |||
2327 | |||
2328 | /** | ||
2329 | * Deliver P2P messages to interested clients. | ||
2330 | * | ||
2331 | * @param sender who sent us the message? | ||
2332 | * @param buffer buffer containing messages, can be modified | ||
2333 | * @param buffer_size size of the buffer (overall) | ||
2334 | * @param offset offset where messages in the buffer start | ||
2335 | */ | ||
2336 | static void | ||
2337 | deliver_messages (struct Neighbour *sender, | ||
2338 | const char *buffer, size_t buffer_size, size_t offset) | ||
2339 | { | ||
2340 | struct GNUNET_MessageHeader *mhp; | ||
2341 | struct GNUNET_MessageHeader mh; | ||
2342 | uint16_t msize; | ||
2343 | int need_align; | ||
2344 | |||
2345 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2346 | "Delivering %u bytes of plaintext to interested clients.\n", | ||
2347 | buffer_size); | ||
2348 | while (offset + sizeof (struct GNUNET_MessageHeader) <= buffer_size) | ||
2349 | { | ||
2350 | if (0 != offset % sizeof (uint16_t)) | ||
2351 | { | ||
2352 | /* outch, need to copy to access header */ | ||
2353 | memcpy (&mh, &buffer[offset], sizeof (struct GNUNET_MessageHeader)); | ||
2354 | mhp = &mh; | ||
2355 | } | ||
2356 | else | ||
2357 | { | ||
2358 | /* can access header directly */ | ||
2359 | mhp = (struct GNUNET_MessageHeader *) &buffer[offset]; | ||
2360 | } | ||
2361 | msize = ntohs (mhp->size); | ||
2362 | if (msize + offset > buffer_size) | ||
2363 | { | ||
2364 | /* malformed message, header says it is larger than what | ||
2365 | would fit into the overall buffer */ | ||
2366 | GNUNET_break_op (0); | ||
2367 | break; | ||
2368 | } | ||
2369 | #if HAVE_UNALIGNED_64_ACCESS | ||
2370 | need_align = (0 != offset % 4) ? GNUNET_YES : GNUNET_NO; | ||
2371 | #else | ||
2372 | need_align = (0 != offset % 8) ? GNUNET_YES : GNUNET_NO; | ||
2373 | #endif | ||
2374 | if (GNUNET_YES == need_align) | ||
2375 | align_and_deliver (sender, &buffer[offset], msize); | ||
2376 | else | ||
2377 | deliver_message (sender, | ||
2378 | (const struct GNUNET_MessageHeader *) | ||
2379 | &buffer[offset], msize); | ||
2380 | offset += msize; | ||
2381 | } | ||
2382 | } | ||
2383 | |||
2384 | |||
2385 | /** | ||
2386 | * We received an encrypted message. Decrypt, validate and | ||
2387 | * pass on to the appropriate clients. | ||
2388 | */ | ||
2389 | static void | ||
2390 | handle_encrypted_message (struct Neighbour *n, | ||
2391 | const struct EncryptedMessage *m) | ||
2392 | { | ||
2393 | size_t size = ntohs (m->header.size); | ||
2394 | char buf[size]; | ||
2395 | struct EncryptedMessage *pt; /* plaintext */ | ||
2396 | GNUNET_HashCode ph; | ||
2397 | size_t off; | ||
2398 | uint32_t snum; | ||
2399 | struct GNUNET_TIME_Absolute t; | ||
2400 | |||
2401 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2402 | "Core service receives `%s' request from `%4s'.\n", | ||
2403 | "ENCRYPTED_MESSAGE", GNUNET_i2s (&n->peer)); | ||
2404 | /* decrypt */ | ||
2405 | if (GNUNET_OK != | ||
2406 | do_decrypt (n, | ||
2407 | &m->plaintext_hash, | ||
2408 | &m->sequence_number, | ||
2409 | &buf[ENCRYPTED_HEADER_SIZE], size - ENCRYPTED_HEADER_SIZE)) | ||
2410 | return; | ||
2411 | pt = (struct EncryptedMessage *) buf; | ||
2412 | |||
2413 | /* validate hash */ | ||
2414 | GNUNET_CRYPTO_hash (&pt->sequence_number, | ||
2415 | size - ENCRYPTED_HEADER_SIZE, &ph); | ||
2416 | if (0 != memcmp (&ph, &m->plaintext_hash, sizeof (GNUNET_HashCode))) | ||
2417 | { | ||
2418 | /* checksum failed */ | ||
2419 | GNUNET_break_op (0); | ||
2420 | return; | ||
2421 | } | ||
2422 | |||
2423 | /* validate sequence number */ | ||
2424 | snum = ntohl (pt->sequence_number); | ||
2425 | if (n->last_sequence_number_received == snum) | ||
2426 | { | ||
2427 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2428 | "Received duplicate message, ignoring.\n"); | ||
2429 | /* duplicate, ignore */ | ||
2430 | return; | ||
2431 | } | ||
2432 | if ((n->last_sequence_number_received > snum) && | ||
2433 | (n->last_sequence_number_received - snum > 32)) | ||
2434 | { | ||
2435 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2436 | "Received ancient out of sequence message, ignoring.\n"); | ||
2437 | /* ancient out of sequence, ignore */ | ||
2438 | return; | ||
2439 | } | ||
2440 | if (n->last_sequence_number_received > snum) | ||
2441 | { | ||
2442 | unsigned int rotbit = | ||
2443 | 1 << (n->last_sequence_number_received - snum - 1); | ||
2444 | if ((n->last_packets_bitmap & rotbit) != 0) | ||
2445 | { | ||
2446 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2447 | "Received duplicate message, ignoring.\n"); | ||
2448 | /* duplicate, ignore */ | ||
2449 | return; | ||
2450 | } | ||
2451 | n->last_packets_bitmap |= rotbit; | ||
2452 | } | ||
2453 | if (n->last_sequence_number_received < snum) | ||
2454 | { | ||
2455 | n->last_packets_bitmap <<= (snum - n->last_sequence_number_received); | ||
2456 | n->last_sequence_number_received = snum; | ||
2457 | } | ||
2458 | |||
2459 | /* check timestamp */ | ||
2460 | t = GNUNET_TIME_absolute_ntoh (pt->timestamp); | ||
2461 | if (GNUNET_TIME_absolute_get_duration (t).value > MAX_MESSAGE_AGE.value) | ||
2462 | { | ||
2463 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
2464 | _ | ||
2465 | ("Message received far too old (%llu ms). Content ignored.\n"), | ||
2466 | GNUNET_TIME_absolute_get_duration (t).value); | ||
2467 | return; | ||
2468 | } | ||
2469 | |||
2470 | /* process decrypted message(s) */ | ||
2471 | n->bpm_out_external_limit = ntohl (pt->inbound_bpm_limit); | ||
2472 | n->bpm_out = GNUNET_MAX (n->bpm_out_external_limit, | ||
2473 | n->bpm_out_internal_limit); | ||
2474 | n->last_activity = GNUNET_TIME_absolute_get (); | ||
2475 | off = sizeof (struct EncryptedMessage); | ||
2476 | deliver_messages (n, buf, size, off); | ||
2477 | } | ||
2478 | |||
2479 | |||
2480 | /** | ||
2481 | * Function called by the transport for each received message. | ||
2482 | * | ||
2483 | * @param cls closure | ||
2484 | * @param latency estimated latency for communicating with the | ||
2485 | * given peer | ||
2486 | * @param peer (claimed) identity of the other peer | ||
2487 | * @param message the message | ||
2488 | */ | ||
2489 | static void | ||
2490 | handle_transport_receive (void *cls, | ||
2491 | struct GNUNET_TIME_Relative latency, | ||
2492 | const struct GNUNET_PeerIdentity *peer, | ||
2493 | const struct GNUNET_MessageHeader *message) | ||
2494 | { | ||
2495 | struct Neighbour *n; | ||
2496 | struct GNUNET_TIME_Absolute now; | ||
2497 | int up; | ||
2498 | uint16_t type; | ||
2499 | uint16_t size; | ||
2500 | |||
2501 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2502 | "Received message of type %u from `%4s', demultiplexing.\n", | ||
2503 | ntohs (message->type), GNUNET_i2s (peer)); | ||
2504 | n = find_neighbour (peer); | ||
2505 | if (n == NULL) | ||
2506 | { | ||
2507 | GNUNET_break (0); | ||
2508 | return; | ||
2509 | } | ||
2510 | n->last_latency = latency; | ||
2511 | up = n->status == PEER_STATE_KEY_CONFIRMED; | ||
2512 | type = ntohs (message->type); | ||
2513 | size = ntohs (message->size); | ||
2514 | switch (type) | ||
2515 | { | ||
2516 | case GNUNET_MESSAGE_TYPE_CORE_SET_KEY: | ||
2517 | if (size != sizeof (struct SetKeyMessage)) | ||
2518 | { | ||
2519 | GNUNET_break_op (0); | ||
2520 | return; | ||
2521 | } | ||
2522 | handle_set_key (n, (const struct SetKeyMessage *) message); | ||
2523 | break; | ||
2524 | case GNUNET_MESSAGE_TYPE_CORE_ENCRYPTED_MESSAGE: | ||
2525 | if (size < sizeof (struct EncryptedMessage) + | ||
2526 | sizeof (struct GNUNET_MessageHeader)) | ||
2527 | { | ||
2528 | GNUNET_break_op (0); | ||
2529 | return; | ||
2530 | } | ||
2531 | if ((n->status != PEER_STATE_KEY_RECEIVED) && | ||
2532 | (n->status != PEER_STATE_KEY_CONFIRMED)) | ||
2533 | { | ||
2534 | GNUNET_break_op (0); | ||
2535 | return; | ||
2536 | } | ||
2537 | handle_encrypted_message (n, (const struct EncryptedMessage *) message); | ||
2538 | break; | ||
2539 | case GNUNET_MESSAGE_TYPE_CORE_PING: | ||
2540 | if (size != sizeof (struct PingMessage)) | ||
2541 | { | ||
2542 | GNUNET_break_op (0); | ||
2543 | return; | ||
2544 | } | ||
2545 | if ((n->status != PEER_STATE_KEY_RECEIVED) && | ||
2546 | (n->status != PEER_STATE_KEY_CONFIRMED)) | ||
2547 | { | ||
2548 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2549 | "Core service receives `%s' request from `%4s' but have not processed key; marking as pending.\n", | ||
2550 | "PING", GNUNET_i2s (&n->peer)); | ||
2551 | GNUNET_free_non_null (n->pending_ping); | ||
2552 | n->pending_ping = GNUNET_malloc (sizeof (struct PingMessage)); | ||
2553 | memcpy (n->pending_ping, message, sizeof (struct PingMessage)); | ||
2554 | return; | ||
2555 | } | ||
2556 | handle_ping (n, (const struct PingMessage *) message); | ||
2557 | break; | ||
2558 | case GNUNET_MESSAGE_TYPE_CORE_PONG: | ||
2559 | if (size != sizeof (struct PingMessage)) | ||
2560 | { | ||
2561 | GNUNET_break_op (0); | ||
2562 | return; | ||
2563 | } | ||
2564 | if ((n->status != PEER_STATE_KEY_SENT) && | ||
2565 | (n->status != PEER_STATE_KEY_RECEIVED) && | ||
2566 | (n->status != PEER_STATE_KEY_CONFIRMED)) | ||
2567 | { | ||
2568 | /* could not decrypt pong, oops! */ | ||
2569 | GNUNET_break_op (0); | ||
2570 | return; | ||
2571 | } | ||
2572 | handle_pong (n, (const struct PingMessage *) message); | ||
2573 | break; | ||
2574 | default: | ||
2575 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
2576 | _("Unsupported message of type %u received.\n"), type); | ||
2577 | return; | ||
2578 | } | ||
2579 | if (n->status == PEER_STATE_KEY_CONFIRMED) | ||
2580 | { | ||
2581 | now = GNUNET_TIME_absolute_get (); | ||
2582 | n->last_activity = now; | ||
2583 | if (!up) | ||
2584 | n->time_established = now; | ||
2585 | } | ||
2586 | } | ||
2587 | |||
2588 | |||
2589 | /** | ||
2590 | * Function called by transport to notify us that | ||
2591 | * a peer connected to us (on the network level). | ||
2592 | * | ||
2593 | * @param cls closure | ||
2594 | * @param peer the peer that connected | ||
2595 | * @param latency current latency of the connection | ||
2596 | */ | ||
2597 | static void | ||
2598 | handle_transport_notify_connect (void *cls, | ||
2599 | const struct GNUNET_PeerIdentity *peer, | ||
2600 | struct GNUNET_TIME_Relative latency) | ||
2601 | { | ||
2602 | struct Neighbour *n; | ||
2603 | struct GNUNET_TIME_Absolute now; | ||
2604 | struct ConnectNotifyMessage cnm; | ||
2605 | |||
2606 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2607 | "Received connection from `%4s'.\n", GNUNET_i2s (peer)); | ||
2608 | n = find_neighbour (peer); | ||
2609 | if (n != NULL) | ||
2610 | { | ||
2611 | /* duplicate connect notification!? */ | ||
2612 | GNUNET_break (0); | ||
2613 | return; | ||
2614 | } | ||
2615 | now = GNUNET_TIME_absolute_get (); | ||
2616 | n = GNUNET_malloc (sizeof (struct Neighbour)); | ||
2617 | n->next = neighbours; | ||
2618 | neighbours = n; | ||
2619 | n->peer = *peer; | ||
2620 | n->last_latency = latency; | ||
2621 | GNUNET_CRYPTO_aes_create_session_key (&n->encrypt_key); | ||
2622 | n->encrypt_key_created = now; | ||
2623 | n->set_key_retry_frequency = INITIAL_SET_KEY_RETRY_FREQUENCY; | ||
2624 | n->last_asw_update = now; | ||
2625 | n->last_arw_update = now; | ||
2626 | n->bpm_in = DEFAULT_BPM_IN_OUT; | ||
2627 | n->bpm_out = DEFAULT_BPM_IN_OUT; | ||
2628 | n->bpm_out_internal_limit = (uint32_t) - 1; | ||
2629 | n->bpm_out_external_limit = DEFAULT_BPM_IN_OUT; | ||
2630 | n->ping_challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, | ||
2631 | (uint32_t) - 1); | ||
2632 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2633 | "Created entry for new neighbour `%4s'.\n", | ||
2634 | GNUNET_i2s (&n->peer)); | ||
2635 | cnm.header.size = htons (sizeof (struct ConnectNotifyMessage)); | ||
2636 | cnm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT); | ||
2637 | cnm.bpm_available = htonl (DEFAULT_BPM_IN_OUT); | ||
2638 | cnm.peer = *peer; | ||
2639 | cnm.last_activity = GNUNET_TIME_absolute_hton (now); | ||
2640 | send_to_all_clients (&cnm.header, GNUNET_YES); | ||
2641 | } | ||
2642 | |||
2643 | |||
2644 | /** | ||
2645 | * Free the given entry for the neighbour (it has | ||
2646 | * already been removed from the list at this point). | ||
2647 | * @param n neighbour to free | ||
2648 | */ | ||
2649 | static void | ||
2650 | free_neighbour (struct Neighbour *n) | ||
2651 | { | ||
2652 | struct MessageEntry *m; | ||
2653 | |||
2654 | while (NULL != (m = n->messages)) | ||
2655 | { | ||
2656 | n->messages = m->next; | ||
2657 | GNUNET_free (m); | ||
2658 | } | ||
2659 | while (NULL != (m = n->encrypted_head)) | ||
2660 | { | ||
2661 | n->encrypted_head = m->next; | ||
2662 | GNUNET_free (m); | ||
2663 | } | ||
2664 | if (NULL != n->th) | ||
2665 | GNUNET_TRANSPORT_notify_transmit_ready_cancel (n->th); | ||
2666 | if (n->retry_plaintext_task != GNUNET_SCHEDULER_NO_PREREQUISITE_TASK) | ||
2667 | GNUNET_SCHEDULER_cancel (sched, n->retry_plaintext_task); | ||
2668 | if (n->retry_set_key_task != GNUNET_SCHEDULER_NO_PREREQUISITE_TASK) | ||
2669 | GNUNET_SCHEDULER_cancel (sched, n->retry_set_key_task); | ||
2670 | GNUNET_free_non_null (n->public_key); | ||
2671 | GNUNET_free_non_null (n->pending_ping); | ||
2672 | GNUNET_free (n); | ||
2673 | } | ||
2674 | |||
2675 | |||
2676 | /** | ||
2677 | * Function called by transport telling us that a peer | ||
2678 | * disconnected. | ||
2679 | * | ||
2680 | * @param cls closure | ||
2681 | * @param peer the peer that disconnected | ||
2682 | */ | ||
2683 | static void | ||
2684 | handle_transport_notify_disconnect (void *cls, | ||
2685 | const struct GNUNET_PeerIdentity *peer) | ||
2686 | { | ||
2687 | struct ConnectNotifyMessage cnm; | ||
2688 | struct Neighbour *n; | ||
2689 | struct Neighbour *p; | ||
2690 | |||
2691 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2692 | "Peer `%4s' disconnected from us.\n", GNUNET_i2s (peer)); | ||
2693 | p = NULL; | ||
2694 | n = neighbours; | ||
2695 | while ((n != NULL) && | ||
2696 | (0 != memcmp (&n->peer, peer, sizeof (struct GNUNET_PeerIdentity)))) | ||
2697 | { | ||
2698 | p = n; | ||
2699 | n = n->next; | ||
2700 | } | ||
2701 | if (n == NULL) | ||
2702 | { | ||
2703 | GNUNET_break (0); | ||
2704 | return; | ||
2705 | } | ||
2706 | if (p == NULL) | ||
2707 | neighbours = n->next; | ||
2708 | else | ||
2709 | p->next = n->next; | ||
2710 | cnm.header.size = htons (sizeof (struct ConnectNotifyMessage)); | ||
2711 | cnm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_DISCONNECT); | ||
2712 | cnm.bpm_available = htonl (0); | ||
2713 | cnm.peer = *peer; | ||
2714 | cnm.last_activity = GNUNET_TIME_absolute_hton (n->last_activity); | ||
2715 | send_to_all_clients (&cnm.header, GNUNET_YES); | ||
2716 | free_neighbour (n); | ||
2717 | } | ||
2718 | |||
2719 | |||
2720 | /** | ||
2721 | * Last task run during shutdown. Disconnects us from | ||
2722 | * the transport. | ||
2723 | */ | ||
2724 | static void | ||
2725 | cleaning_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
2726 | { | ||
2727 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Core service shutting down.\n"); | ||
2728 | GNUNET_assert (transport != NULL); | ||
2729 | GNUNET_TRANSPORT_disconnect (transport); | ||
2730 | transport = NULL; | ||
2731 | } | ||
2732 | |||
2733 | |||
2734 | /** | ||
2735 | * Initiate core service. | ||
2736 | * | ||
2737 | * @param cls closure | ||
2738 | * @param s scheduler to use | ||
2739 | * @param serv the initialized server | ||
2740 | * @param c configuration to use | ||
2741 | */ | ||
2742 | static void | ||
2743 | run (void *cls, | ||
2744 | struct GNUNET_SCHEDULER_Handle *s, | ||
2745 | struct GNUNET_SERVER_Handle *serv, struct GNUNET_CONFIGURATION_Handle *c) | ||
2746 | { | ||
2747 | #if 0 | ||
2748 | unsigned long long qin; | ||
2749 | unsigned long long qout; | ||
2750 | unsigned long long tneigh; | ||
2751 | #endif | ||
2752 | char *keyfile; | ||
2753 | |||
2754 | sched = s; | ||
2755 | cfg = c; | ||
2756 | /* parse configuration */ | ||
2757 | if ( | ||
2758 | #if 0 | ||
2759 | (GNUNET_OK != | ||
2760 | GNUNET_CONFIGURATION_get_value_number (c, | ||
2761 | "CORE", | ||
2762 | "XX", | ||
2763 | &qin)) || | ||
2764 | (GNUNET_OK != | ||
2765 | GNUNET_CONFIGURATION_get_value_number (c, | ||
2766 | "CORE", | ||
2767 | "YY", | ||
2768 | &qout)) || | ||
2769 | (GNUNET_OK != | ||
2770 | GNUNET_CONFIGURATION_get_value_number (c, | ||
2771 | "CORE", | ||
2772 | "ZZ_LIMIT", &tneigh)) || | ||
2773 | #endif | ||
2774 | (GNUNET_OK != | ||
2775 | GNUNET_CONFIGURATION_get_value_filename (c, | ||
2776 | "GNUNETD", | ||
2777 | "HOSTKEY", &keyfile))) | ||
2778 | { | ||
2779 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
2780 | _ | ||
2781 | ("Core service is lacking key configuration settings. Exiting.\n")); | ||
2782 | GNUNET_SCHEDULER_shutdown (s); | ||
2783 | return; | ||
2784 | } | ||
2785 | my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); | ||
2786 | GNUNET_free (keyfile); | ||
2787 | if (my_private_key == NULL) | ||
2788 | { | ||
2789 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
2790 | _("Core service could not access hostkey. Exiting.\n")); | ||
2791 | GNUNET_SCHEDULER_shutdown (s); | ||
2792 | return; | ||
2793 | } | ||
2794 | GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key); | ||
2795 | GNUNET_CRYPTO_hash (&my_public_key, | ||
2796 | sizeof (my_public_key), &my_identity.hashPubKey); | ||
2797 | /* setup notification */ | ||
2798 | server = serv; | ||
2799 | GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL); | ||
2800 | /* setup transport connection */ | ||
2801 | transport = GNUNET_TRANSPORT_connect (sched, | ||
2802 | cfg, | ||
2803 | NULL, | ||
2804 | &handle_transport_receive, | ||
2805 | &handle_transport_notify_connect, | ||
2806 | &handle_transport_notify_disconnect); | ||
2807 | GNUNET_assert (NULL != transport); | ||
2808 | GNUNET_SCHEDULER_add_delayed (sched, | ||
2809 | GNUNET_YES, | ||
2810 | GNUNET_SCHEDULER_PRIORITY_IDLE, | ||
2811 | GNUNET_SCHEDULER_NO_PREREQUISITE_TASK, | ||
2812 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
2813 | &cleaning_task, NULL); | ||
2814 | /* process client requests */ | ||
2815 | GNUNET_SERVER_add_handlers (server, handlers); | ||
2816 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
2817 | _("Core service of `%4s' ready.\n"), GNUNET_i2s (&my_identity)); | ||
2818 | } | ||
2819 | |||
2820 | |||
2821 | /** | ||
2822 | * Function called during shutdown. Clean up our state. | ||
2823 | */ | ||
2824 | static void | ||
2825 | cleanup (void *cls, struct GNUNET_CONFIGURATION_Handle *cfg) | ||
2826 | { | ||
2827 | struct Neighbour *n; | ||
2828 | |||
2829 | if (my_private_key != NULL) | ||
2830 | GNUNET_CRYPTO_rsa_key_free (my_private_key); | ||
2831 | while (NULL != (n = neighbours)) | ||
2832 | { | ||
2833 | neighbours = n->next; | ||
2834 | free_neighbour (n); | ||
2835 | } | ||
2836 | /* | ||
2837 | FIXME: | ||
2838 | - free clients | ||
2839 | */ | ||
2840 | } | ||
2841 | |||
2842 | |||
2843 | /** | ||
2844 | * The main function for the transport service. | ||
2845 | * | ||
2846 | * @param argc number of arguments from the command line | ||
2847 | * @param argv command line arguments | ||
2848 | * @return 0 ok, 1 on error | ||
2849 | */ | ||
2850 | int | ||
2851 | main (int argc, char *const *argv) | ||
2852 | { | ||
2853 | return (GNUNET_OK == | ||
2854 | GNUNET_SERVICE_run (argc, | ||
2855 | argv, | ||
2856 | "core", &run, NULL, &cleanup, NULL)) ? 0 : 1; | ||
2857 | } | ||
2858 | |||
2859 | /* end of gnunet-service-core.c */ | ||