1 /* code for managing of 'encrypted' sessions (key exchange done) */
5 * Record kept for each request for transmission issued by a
6 * client that is still pending.
8 struct ClientActiveRequest;
11 * Data kept per session.
16 * Identity of the other peer.
18 struct GNUNET_PeerIdentity peer;
21 * Head of list of requests from clients for transmission to
24 struct ClientActiveRequest *active_client_request_head;
27 * Tail of list of requests from clients for transmission to
30 struct ClientActiveRequest *active_client_request_tail;
33 * Performance data for the peer.
35 struct GNUNET_TRANSPORT_ATS_Information *ats;
38 * Information about the key exchange with the other peer.
40 struct GSC_KeyExchangeInfo *kxinfo;
43 * ID of task used for sending keep-alive pings.
45 GNUNET_SCHEDULER_TaskIdentifier keep_alive_task;
48 * ID of task used for cleaning up dead neighbour entries.
50 GNUNET_SCHEDULER_TaskIdentifier dead_clean_task;
53 * ID of task used for updating bandwidth quota for this neighbour.
55 GNUNET_SCHEDULER_TaskIdentifier quota_update_task;
58 * At what time did we initially establish (as in, complete session
59 * key handshake) this connection? Should be zero if status != KEY_CONFIRMED.
61 struct GNUNET_TIME_Absolute time_established;
64 * At what time did we last receive an encrypted message from the
65 * other peer? Should be zero if status != KEY_CONFIRMED.
67 struct GNUNET_TIME_Absolute last_activity;
70 * How valueable were the messages of this peer recently?
72 unsigned long long current_preference;
75 * Number of entries in 'ats'.
77 unsigned int ats_count;
80 * Bit map indicating which of the 32 sequence numbers before the last
81 * were received (good for accepting out-of-order packets and
82 * estimating reliability of the connection)
84 unsigned int last_packets_bitmap;
87 * last sequence number received on this connection (highest)
89 uint32_t last_sequence_number_received;
92 * last sequence number transmitted
94 uint32_t last_sequence_number_sent;
97 * Available bandwidth in for this peer (current target).
99 struct GNUNET_BANDWIDTH_Value32NBO bw_in;
102 * Available bandwidth out for this peer (current target).
104 struct GNUNET_BANDWIDTH_Value32NBO bw_out;
107 * Internal bandwidth limit set for this peer (initially typically
108 * set to "-1"). Actual "bw_out" is MIN of
109 * "bpm_out_internal_limit" and "bw_out_external_limit".
111 struct GNUNET_BANDWIDTH_Value32NBO bw_out_internal_limit;
114 * External bandwidth limit set for this peer by the
115 * peer that we are communicating with. "bw_out" is MIN of
116 * "bw_out_internal_limit" and "bw_out_external_limit".
118 struct GNUNET_BANDWIDTH_Value32NBO bw_out_external_limit;
124 * Map of peer identities to 'struct Session'.
126 static struct GNUNET_CONTAINER_MultiHashMap *sessions;
130 * Session entry for "this" peer.
132 static struct Session self;
135 * Sum of all preferences among all neighbours.
137 static unsigned long long preference_sum;
143 * At what time should the connection to the given neighbour
144 * time out (given no further activity?)
146 * @param n neighbour in question
147 * @return absolute timeout
149 static struct GNUNET_TIME_Absolute
150 get_neighbour_timeout (struct Neighbour *n)
152 return GNUNET_TIME_absolute_add (n->last_activity,
153 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
158 * Helper function for update_preference_sum.
161 update_preference (void *cls, const GNUNET_HashCode * key, void *value)
163 unsigned long long *ps = cls;
164 struct Neighbour *n = value;
166 n->current_preference /= 2;
167 *ps += n->current_preference;
173 * A preference value for a neighbour was update. Update
174 * the preference sum accordingly.
176 * @param inc how much was a preference value increased?
179 update_preference_sum (unsigned long long inc)
181 unsigned long long os;
184 preference_sum += inc;
185 if (preference_sum >= os)
187 /* overflow! compensate by cutting all values in half! */
189 GNUNET_CONTAINER_multihashmap_iterate (neighbours, &update_preference,
191 GNUNET_STATISTICS_set (stats, gettext_noop ("# total peer preference"),
192 preference_sum, GNUNET_NO);
197 * Find the entry for the given neighbour.
199 * @param peer identity of the neighbour
200 * @return NULL if we are not connected, otherwise the
203 static struct Neighbour *
204 find_neighbour (const struct GNUNET_PeerIdentity *peer)
206 return GNUNET_CONTAINER_multihashmap_get (neighbours, &peer->hashPubKey);
211 * Function called by transport telling us that a peer
214 * @param n the peer that changed status
217 handle_peer_status_change (struct Neighbour *n)
219 struct PeerStatusNotifyMessage *psnm;
220 char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1];
221 struct GNUNET_TRANSPORT_ATS_Information *ats;
224 if ((!n->is_connected) || (n->status != PEER_STATE_KEY_CONFIRMED))
227 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%4s' changed status\n",
228 GNUNET_i2s (&n->peer));
231 sizeof (struct PeerStatusNotifyMessage) +
232 n->ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
233 if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
236 /* recovery strategy: throw away performance data */
237 GNUNET_array_grow (n->ats, n->ats_count, 0);
239 sizeof (struct PeerStatusNotifyMessage) +
240 n->ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
242 psnm = (struct PeerStatusNotifyMessage *) buf;
243 psnm->header.size = htons (size);
244 psnm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_STATUS_CHANGE);
245 psnm->timeout = GNUNET_TIME_absolute_hton (get_neighbour_timeout (n));
246 psnm->bandwidth_in = n->bw_in;
247 psnm->bandwidth_out = n->bw_out;
248 psnm->peer = n->peer;
249 psnm->ats_count = htonl (n->ats_count);
252 n->ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information));
253 ats[n->ats_count].type = htonl (0);
254 ats[n->ats_count].value = htonl (0);
255 send_to_all_clients (&psnm->header, GNUNET_YES,
256 GNUNET_CORE_OPTION_SEND_STATUS_CHANGE);
257 GNUNET_STATISTICS_update (stats, gettext_noop ("# peer status changes"), 1,
264 * Go over our message queue and if it is not too long, go
265 * over the pending requests from clients for this
266 * neighbour and send some clients a 'READY' notification.
268 * @param n which peer to process
271 schedule_peer_messages (struct Neighbour *n)
273 struct SendMessageReady smr;
274 struct ClientActiveRequest *car;
275 struct ClientActiveRequest *pos;
277 struct MessageEntry *mqe;
278 unsigned int queue_size;
280 /* check if neighbour queue is empty enough! */
290 if (queue_size >= MAX_PEER_QUEUE_SIZE)
292 #if DEBUG_CORE_CLIENT
293 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
294 "Not considering client transmission requests: queue full\n");
296 return; /* queue still full */
298 /* find highest priority request */
299 pos = n->active_client_request_head;
303 if ((car == NULL) || (pos->priority > car->priority))
310 car = n->active_client_request_head;
313 return; /* no pending requests */
314 #if DEBUG_CORE_CLIENT
315 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
316 "Permitting client transmission request to `%s'\n",
317 GNUNET_i2s (&n->peer));
320 GNUNET_CONTAINER_DLL_remove (n->active_client_request_head,
321 n->active_client_request_tail, car);
322 GNUNET_assert (GNUNET_YES ==
323 GNUNET_CONTAINER_multihashmap_remove (c->requests,
326 smr.header.size = htons (sizeof (struct SendMessageReady));
327 smr.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_SEND_READY);
328 smr.size = htons (car->msize);
329 smr.smr_id = car->smr_id;
331 send_to_client (c, &smr.header, GNUNET_NO);
338 * Free the given entry for the neighbour (it has
339 * already been removed from the list at this point).
341 * @param n neighbour to free
344 free_neighbour (struct Neighbour *n)
346 struct MessageEntry *m;
347 struct ClientActiveRequest *car;
350 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
351 "Destroying neighbour entry for peer `%4s'\n",
352 GNUNET_i2s (&n->peer));
356 GNUNET_free (n->skm);
359 while (NULL != (m = n->messages))
361 n->messages = m->next;
364 while (NULL != (m = n->encrypted_head))
366 GNUNET_CONTAINER_DLL_remove (n->encrypted_head, n->encrypted_tail, m);
369 while (NULL != (car = n->active_client_request_head))
371 GNUNET_CONTAINER_DLL_remove (n->active_client_request_head,
372 n->active_client_request_tail, car);
373 GNUNET_assert (GNUNET_YES ==
374 GNUNET_CONTAINER_multihashmap_remove (car->client->requests,
381 GNUNET_TRANSPORT_notify_transmit_ready_cancel (n->th);
384 if (n->retry_plaintext_task != GNUNET_SCHEDULER_NO_TASK)
385 GNUNET_SCHEDULER_cancel (n->retry_plaintext_task);
386 if (n->quota_update_task != GNUNET_SCHEDULER_NO_TASK)
387 GNUNET_SCHEDULER_cancel (n->quota_update_task);
388 if (n->dead_clean_task != GNUNET_SCHEDULER_NO_TASK)
389 GNUNET_SCHEDULER_cancel (n->dead_clean_task);
390 if (n->keep_alive_task != GNUNET_SCHEDULER_NO_TASK)
391 GNUNET_SCHEDULER_cancel (n->keep_alive_task);
392 if (n->status == PEER_STATE_KEY_CONFIRMED)
393 GNUNET_STATISTICS_update (stats, gettext_noop ("# established sessions"),
395 GNUNET_array_grow (n->ats, n->ats_count, 0);
396 GNUNET_free_non_null (n->pending_ping);
397 GNUNET_free_non_null (n->pending_pong);
404 * Task triggered when a neighbour entry is about to time out
405 * (and we should prevent this by sending a PING).
407 * @param cls the 'struct Neighbour'
408 * @param tc scheduler context (not used)
411 send_keep_alive (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
413 struct Neighbour *n = cls;
414 struct GNUNET_TIME_Relative retry;
415 struct GNUNET_TIME_Relative left;
416 struct MessageEntry *me;
417 struct PingMessage pp;
418 struct PingMessage *pm;
419 struct GNUNET_CRYPTO_AesInitializationVector iv;
421 n->keep_alive_task = GNUNET_SCHEDULER_NO_TASK;
423 me = GNUNET_malloc (sizeof (struct MessageEntry) +
424 sizeof (struct PingMessage));
425 me->deadline = GNUNET_TIME_relative_to_absolute (MAX_PING_DELAY);
426 me->priority = PING_PRIORITY;
427 me->size = sizeof (struct PingMessage);
428 GNUNET_CONTAINER_DLL_insert_after (n->encrypted_head, n->encrypted_tail,
429 n->encrypted_tail, me);
430 pm = (struct PingMessage *) &me[1];
431 pm->header.size = htons (sizeof (struct PingMessage));
432 pm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_PING);
434 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX);
435 derive_iv (&iv, &n->encrypt_key, pm->iv_seed, &n->peer);
436 pp.challenge = n->ping_challenge;
439 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
440 "Encrypting `%s' message with challenge %u for `%4s' using key %u, IV %u (salt %u).\n",
441 "PING", (unsigned int) n->ping_challenge, GNUNET_i2s (&n->peer),
442 (unsigned int) n->encrypt_key.crc32, GNUNET_CRYPTO_crc32_n (&iv,
447 do_encrypt (n, &iv, &pp.target, &pm->target,
448 sizeof (struct PingMessage) - ((void *) &pm->target -
450 process_encrypted_neighbour_queue (n);
451 /* reschedule PING job */
452 left = GNUNET_TIME_absolute_get_remaining (get_neighbour_timeout (n));
454 GNUNET_TIME_relative_max (GNUNET_TIME_relative_divide (left, 2),
457 GNUNET_SCHEDULER_add_delayed (retry, &send_keep_alive, n);
462 * Consider freeing the given neighbour since we may not need
463 * to keep it around anymore.
465 * @param n neighbour to consider discarding
468 consider_free_neighbour (struct Neighbour *n);
472 * Task triggered when a neighbour entry might have gotten stale.
474 * @param cls the 'struct Neighbour'
475 * @param tc scheduler context (not used)
478 consider_free_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
480 struct Neighbour *n = cls;
482 n->dead_clean_task = GNUNET_SCHEDULER_NO_TASK;
483 consider_free_neighbour (n);
488 * Consider freeing the given neighbour since we may not need
489 * to keep it around anymore.
491 * @param n neighbour to consider discarding
494 consider_free_neighbour (struct Neighbour *n)
496 struct GNUNET_TIME_Relative left;
498 if ((n->th != NULL) || (n->pitr != NULL) || (GNUNET_YES == n->is_connected))
499 return; /* no chance */
501 left = GNUNET_TIME_absolute_get_remaining (get_neighbour_timeout (n));
502 if (left.rel_value > 0)
504 if (n->dead_clean_task != GNUNET_SCHEDULER_NO_TASK)
505 GNUNET_SCHEDULER_cancel (n->dead_clean_task);
507 GNUNET_SCHEDULER_add_delayed (left, &consider_free_task, n);
510 /* actually free the neighbour... */
511 GNUNET_assert (GNUNET_YES ==
512 GNUNET_CONTAINER_multihashmap_remove (neighbours,
513 &n->peer.hashPubKey, n));
514 GNUNET_STATISTICS_set (stats, gettext_noop ("# neighbour entries allocated"),
515 GNUNET_CONTAINER_multihashmap_size (neighbours),
522 * Function called when the transport service is ready to
523 * receive an encrypted message for the respective peer
525 * @param cls neighbour to use message from
526 * @param size number of bytes we can transmit
527 * @param buf where to copy the message
528 * @return number of bytes transmitted
531 notify_encrypted_transmit_ready (void *cls, size_t size, void *buf)
533 struct Neighbour *n = cls;
534 struct MessageEntry *m;
539 m = n->encrypted_head;
543 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
544 "Encrypted message queue empty, no messages added to buffer for `%4s'\n",
545 GNUNET_i2s (&n->peer));
549 GNUNET_CONTAINER_DLL_remove (n->encrypted_head, n->encrypted_tail, m);
554 GNUNET_assert (size >= m->size);
555 memcpy (cbuf, &m[1], m->size);
557 GNUNET_BANDWIDTH_tracker_consume (&n->available_send_window, m->size);
559 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
560 "Copied message of type %u and size %u into transport buffer for `%4s'\n",
562 ntohs (((struct GNUNET_MessageHeader *) &m[1])->type),
563 (unsigned int) ret, GNUNET_i2s (&n->peer));
565 process_encrypted_neighbour_queue (n);
570 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
571 "Transmission of message of type %u and size %u failed\n",
573 ntohs (((struct GNUNET_MessageHeader *) &m[1])->type),
574 (unsigned int) m->size);
578 consider_free_neighbour (n);
579 GNUNET_STATISTICS_update (stats,
581 ("# encrypted bytes given to transport"), ret,
588 * Check if we have encrypted messages for the specified neighbour
589 * pending, and if so, check with the transport about sending them
592 * @param n neighbour to check.
595 process_encrypted_neighbour_queue (struct Neighbour *n)
597 struct MessageEntry *m;
600 return; /* request already pending */
601 if (GNUNET_YES != n->is_connected)
606 m = n->encrypted_head;
609 /* encrypted queue empty, try plaintext instead */
610 process_plaintext_neighbour_queue (n);
614 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
615 "Asking transport for transmission of %u bytes to `%4s' in next %llu ms\n",
616 (unsigned int) m->size, GNUNET_i2s (&n->peer),
618 GNUNET_TIME_absolute_get_remaining (m->deadline).rel_value);
621 GNUNET_TRANSPORT_notify_transmit_ready (transport, &n->peer, m->size,
623 GNUNET_TIME_absolute_get_remaining
625 ¬ify_encrypted_transmit_ready,
629 /* message request too large or duplicate request */
631 /* discard encrypted message */
632 GNUNET_CONTAINER_DLL_remove (n->encrypted_head, n->encrypted_tail, m);
634 process_encrypted_neighbour_queue (n);
640 * Initialize a new 'struct Neighbour'.
642 * @param pid ID of the new neighbour
643 * @return handle for the new neighbour
645 static struct Neighbour *
646 create_neighbour (const struct GNUNET_PeerIdentity *pid)
649 struct GNUNET_TIME_Absolute now;
652 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
653 "Creating neighbour entry for peer `%4s'\n", GNUNET_i2s (pid));
655 n = GNUNET_malloc (sizeof (struct Neighbour));
657 GNUNET_CRYPTO_aes_create_session_key (&n->encrypt_key);
658 now = GNUNET_TIME_absolute_get ();
659 n->encrypt_key_created = now;
660 n->last_activity = now;
661 n->set_key_retry_frequency = INITIAL_SET_KEY_RETRY_FREQUENCY;
662 n->bw_in = GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT;
663 n->bw_out = GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT;
664 n->bw_out_internal_limit = GNUNET_BANDWIDTH_value_init (UINT32_MAX);
665 n->bw_out_external_limit = GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT;
667 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX);
668 GNUNET_assert (GNUNET_OK ==
669 GNUNET_CONTAINER_multihashmap_put (neighbours,
670 &n->peer.hashPubKey, n,
671 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
672 GNUNET_STATISTICS_set (stats, gettext_noop ("# neighbour entries allocated"),
673 GNUNET_CONTAINER_multihashmap_size (neighbours),
675 neighbour_quota_update (n, NULL);
676 consider_free_neighbour (n);
682 GSC_NEIGHBOURS_init ()
684 neighbours = GNUNET_CONTAINER_multihashmap_create (128);
685 self.public_key = &my_public_key;
686 self.peer = my_identity;
687 self.last_activity = GNUNET_TIME_UNIT_FOREVER_ABS;
688 self.status = PEER_STATE_KEY_CONFIRMED;
689 self.is_connected = GNUNET_YES;
695 GSC_NEIGHBOURS_done ()
697 GNUNET_CONTAINER_multihashmap_iterate (neighbours, &free_neighbour_helper,
699 GNUNET_CONTAINER_multihashmap_destroy (neighbours);
701 GNUNET_STATISTICS_set (stats, gettext_noop ("# neighbour entries allocated"),