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 * Tracking bandwidth for sending to this peer.
72 struct GNUNET_BANDWIDTH_Tracker available_send_window;
75 * Tracking bandwidth for receiving from this peer.
77 struct GNUNET_BANDWIDTH_Tracker available_recv_window;
80 * How valueable were the messages of this peer recently?
82 unsigned long long current_preference;
85 * Number of entries in 'ats'.
87 unsigned int ats_count;
90 * Bit map indicating which of the 32 sequence numbers before the last
91 * were received (good for accepting out-of-order packets and
92 * estimating reliability of the connection)
94 unsigned int last_packets_bitmap;
97 * last sequence number received on this connection (highest)
99 uint32_t last_sequence_number_received;
102 * last sequence number transmitted
104 uint32_t last_sequence_number_sent;
107 * Available bandwidth in for this peer (current target).
109 struct GNUNET_BANDWIDTH_Value32NBO bw_in;
112 * Available bandwidth out for this peer (current target).
114 struct GNUNET_BANDWIDTH_Value32NBO bw_out;
117 * Internal bandwidth limit set for this peer (initially typically
118 * set to "-1"). Actual "bw_out" is MIN of
119 * "bpm_out_internal_limit" and "bw_out_external_limit".
121 struct GNUNET_BANDWIDTH_Value32NBO bw_out_internal_limit;
124 * External bandwidth limit set for this peer by the
125 * peer that we are communicating with. "bw_out" is MIN of
126 * "bw_out_internal_limit" and "bw_out_external_limit".
128 struct GNUNET_BANDWIDTH_Value32NBO bw_out_external_limit;
134 * Map of peer identities to 'struct Session'.
136 static struct GNUNET_CONTAINER_MultiHashMap *sessions;
140 * Session entry for "this" peer.
142 static struct Session self;
145 * Sum of all preferences among all neighbours.
147 static unsigned long long preference_sum;
153 * At what time should the connection to the given neighbour
154 * time out (given no further activity?)
156 * @param n neighbour in question
157 * @return absolute timeout
159 static struct GNUNET_TIME_Absolute
160 get_neighbour_timeout (struct Neighbour *n)
162 return GNUNET_TIME_absolute_add (n->last_activity,
163 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
168 * Helper function for update_preference_sum.
171 update_preference (void *cls, const GNUNET_HashCode * key, void *value)
173 unsigned long long *ps = cls;
174 struct Neighbour *n = value;
176 n->current_preference /= 2;
177 *ps += n->current_preference;
183 * A preference value for a neighbour was update. Update
184 * the preference sum accordingly.
186 * @param inc how much was a preference value increased?
189 update_preference_sum (unsigned long long inc)
191 unsigned long long os;
194 preference_sum += inc;
195 if (preference_sum >= os)
197 /* overflow! compensate by cutting all values in half! */
199 GNUNET_CONTAINER_multihashmap_iterate (neighbours, &update_preference,
201 GNUNET_STATISTICS_set (stats, gettext_noop ("# total peer preference"),
202 preference_sum, GNUNET_NO);
207 * Find the entry for the given neighbour.
209 * @param peer identity of the neighbour
210 * @return NULL if we are not connected, otherwise the
213 static struct Neighbour *
214 find_neighbour (const struct GNUNET_PeerIdentity *peer)
216 return GNUNET_CONTAINER_multihashmap_get (neighbours, &peer->hashPubKey);
221 * Function called by transport telling us that a peer
224 * @param n the peer that changed status
227 handle_peer_status_change (struct Neighbour *n)
229 struct PeerStatusNotifyMessage *psnm;
230 char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1];
231 struct GNUNET_TRANSPORT_ATS_Information *ats;
234 if ((!n->is_connected) || (n->status != PEER_STATE_KEY_CONFIRMED))
237 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%4s' changed status\n",
238 GNUNET_i2s (&n->peer));
241 sizeof (struct PeerStatusNotifyMessage) +
242 n->ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
243 if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
246 /* recovery strategy: throw away performance data */
247 GNUNET_array_grow (n->ats, n->ats_count, 0);
249 sizeof (struct PeerStatusNotifyMessage) +
250 n->ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
252 psnm = (struct PeerStatusNotifyMessage *) buf;
253 psnm->header.size = htons (size);
254 psnm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_STATUS_CHANGE);
255 psnm->timeout = GNUNET_TIME_absolute_hton (get_neighbour_timeout (n));
256 psnm->bandwidth_in = n->bw_in;
257 psnm->bandwidth_out = n->bw_out;
258 psnm->peer = n->peer;
259 psnm->ats_count = htonl (n->ats_count);
262 n->ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information));
263 ats[n->ats_count].type = htonl (0);
264 ats[n->ats_count].value = htonl (0);
265 send_to_all_clients (&psnm->header, GNUNET_YES,
266 GNUNET_CORE_OPTION_SEND_STATUS_CHANGE);
267 GNUNET_STATISTICS_update (stats, gettext_noop ("# peer status changes"), 1,
274 * Go over our message queue and if it is not too long, go
275 * over the pending requests from clients for this
276 * neighbour and send some clients a 'READY' notification.
278 * @param n which peer to process
281 schedule_peer_messages (struct Neighbour *n)
283 struct SendMessageReady smr;
284 struct ClientActiveRequest *car;
285 struct ClientActiveRequest *pos;
287 struct MessageEntry *mqe;
288 unsigned int queue_size;
290 /* check if neighbour queue is empty enough! */
300 if (queue_size >= MAX_PEER_QUEUE_SIZE)
302 #if DEBUG_CORE_CLIENT
303 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
304 "Not considering client transmission requests: queue full\n");
306 return; /* queue still full */
308 /* find highest priority request */
309 pos = n->active_client_request_head;
313 if ((car == NULL) || (pos->priority > car->priority))
320 car = n->active_client_request_head;
323 return; /* no pending requests */
324 #if DEBUG_CORE_CLIENT
325 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
326 "Permitting client transmission request to `%s'\n",
327 GNUNET_i2s (&n->peer));
330 GNUNET_CONTAINER_DLL_remove (n->active_client_request_head,
331 n->active_client_request_tail, car);
332 GNUNET_assert (GNUNET_YES ==
333 GNUNET_CONTAINER_multihashmap_remove (c->requests,
336 smr.header.size = htons (sizeof (struct SendMessageReady));
337 smr.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_SEND_READY);
338 smr.size = htons (car->msize);
339 smr.smr_id = car->smr_id;
341 send_to_client (c, &smr.header, GNUNET_NO);
348 * Free the given entry for the neighbour (it has
349 * already been removed from the list at this point).
351 * @param n neighbour to free
354 free_neighbour (struct Neighbour *n)
356 struct MessageEntry *m;
357 struct ClientActiveRequest *car;
360 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
361 "Destroying neighbour entry for peer `%4s'\n",
362 GNUNET_i2s (&n->peer));
366 GNUNET_free (n->skm);
369 while (NULL != (m = n->messages))
371 n->messages = m->next;
374 while (NULL != (m = n->encrypted_head))
376 GNUNET_CONTAINER_DLL_remove (n->encrypted_head, n->encrypted_tail, m);
379 while (NULL != (car = n->active_client_request_head))
381 GNUNET_CONTAINER_DLL_remove (n->active_client_request_head,
382 n->active_client_request_tail, car);
383 GNUNET_assert (GNUNET_YES ==
384 GNUNET_CONTAINER_multihashmap_remove (car->client->requests,
391 GNUNET_TRANSPORT_notify_transmit_ready_cancel (n->th);
394 if (n->retry_plaintext_task != GNUNET_SCHEDULER_NO_TASK)
395 GNUNET_SCHEDULER_cancel (n->retry_plaintext_task);
396 if (n->quota_update_task != GNUNET_SCHEDULER_NO_TASK)
397 GNUNET_SCHEDULER_cancel (n->quota_update_task);
398 if (n->dead_clean_task != GNUNET_SCHEDULER_NO_TASK)
399 GNUNET_SCHEDULER_cancel (n->dead_clean_task);
400 if (n->keep_alive_task != GNUNET_SCHEDULER_NO_TASK)
401 GNUNET_SCHEDULER_cancel (n->keep_alive_task);
402 if (n->status == PEER_STATE_KEY_CONFIRMED)
403 GNUNET_STATISTICS_update (stats, gettext_noop ("# established sessions"),
405 GNUNET_array_grow (n->ats, n->ats_count, 0);
406 GNUNET_free_non_null (n->pending_ping);
407 GNUNET_free_non_null (n->pending_pong);
414 * Task triggered when a neighbour entry is about to time out
415 * (and we should prevent this by sending a PING).
417 * @param cls the 'struct Neighbour'
418 * @param tc scheduler context (not used)
421 send_keep_alive (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
423 struct Neighbour *n = cls;
424 struct GNUNET_TIME_Relative retry;
425 struct GNUNET_TIME_Relative left;
426 struct MessageEntry *me;
427 struct PingMessage pp;
428 struct PingMessage *pm;
429 struct GNUNET_CRYPTO_AesInitializationVector iv;
431 n->keep_alive_task = GNUNET_SCHEDULER_NO_TASK;
433 me = GNUNET_malloc (sizeof (struct MessageEntry) +
434 sizeof (struct PingMessage));
435 me->deadline = GNUNET_TIME_relative_to_absolute (MAX_PING_DELAY);
436 me->priority = PING_PRIORITY;
437 me->size = sizeof (struct PingMessage);
438 GNUNET_CONTAINER_DLL_insert_after (n->encrypted_head, n->encrypted_tail,
439 n->encrypted_tail, me);
440 pm = (struct PingMessage *) &me[1];
441 pm->header.size = htons (sizeof (struct PingMessage));
442 pm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_PING);
444 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX);
445 derive_iv (&iv, &n->encrypt_key, pm->iv_seed, &n->peer);
446 pp.challenge = n->ping_challenge;
449 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
450 "Encrypting `%s' message with challenge %u for `%4s' using key %u, IV %u (salt %u).\n",
451 "PING", (unsigned int) n->ping_challenge, GNUNET_i2s (&n->peer),
452 (unsigned int) n->encrypt_key.crc32, GNUNET_CRYPTO_crc32_n (&iv,
457 do_encrypt (n, &iv, &pp.target, &pm->target,
458 sizeof (struct PingMessage) - ((void *) &pm->target -
460 process_encrypted_neighbour_queue (n);
461 /* reschedule PING job */
462 left = GNUNET_TIME_absolute_get_remaining (get_neighbour_timeout (n));
464 GNUNET_TIME_relative_max (GNUNET_TIME_relative_divide (left, 2),
467 GNUNET_SCHEDULER_add_delayed (retry, &send_keep_alive, n);
472 * Consider freeing the given neighbour since we may not need
473 * to keep it around anymore.
475 * @param n neighbour to consider discarding
478 consider_free_neighbour (struct Neighbour *n);
482 * Task triggered when a neighbour entry might have gotten stale.
484 * @param cls the 'struct Neighbour'
485 * @param tc scheduler context (not used)
488 consider_free_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
490 struct Neighbour *n = cls;
492 n->dead_clean_task = GNUNET_SCHEDULER_NO_TASK;
493 consider_free_neighbour (n);
498 * Consider freeing the given neighbour since we may not need
499 * to keep it around anymore.
501 * @param n neighbour to consider discarding
504 consider_free_neighbour (struct Neighbour *n)
506 struct GNUNET_TIME_Relative left;
508 if ((n->th != NULL) || (n->pitr != NULL) || (GNUNET_YES == n->is_connected))
509 return; /* no chance */
511 left = GNUNET_TIME_absolute_get_remaining (get_neighbour_timeout (n));
512 if (left.rel_value > 0)
514 if (n->dead_clean_task != GNUNET_SCHEDULER_NO_TASK)
515 GNUNET_SCHEDULER_cancel (n->dead_clean_task);
517 GNUNET_SCHEDULER_add_delayed (left, &consider_free_task, n);
520 /* actually free the neighbour... */
521 GNUNET_assert (GNUNET_YES ==
522 GNUNET_CONTAINER_multihashmap_remove (neighbours,
523 &n->peer.hashPubKey, n));
524 GNUNET_STATISTICS_set (stats, gettext_noop ("# neighbour entries allocated"),
525 GNUNET_CONTAINER_multihashmap_size (neighbours),
532 * Function called when the transport service is ready to
533 * receive an encrypted message for the respective peer
535 * @param cls neighbour to use message from
536 * @param size number of bytes we can transmit
537 * @param buf where to copy the message
538 * @return number of bytes transmitted
541 notify_encrypted_transmit_ready (void *cls, size_t size, void *buf)
543 struct Neighbour *n = cls;
544 struct MessageEntry *m;
549 m = n->encrypted_head;
553 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
554 "Encrypted message queue empty, no messages added to buffer for `%4s'\n",
555 GNUNET_i2s (&n->peer));
559 GNUNET_CONTAINER_DLL_remove (n->encrypted_head, n->encrypted_tail, m);
564 GNUNET_assert (size >= m->size);
565 memcpy (cbuf, &m[1], m->size);
567 GNUNET_BANDWIDTH_tracker_consume (&n->available_send_window, m->size);
569 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
570 "Copied message of type %u and size %u into transport buffer for `%4s'\n",
572 ntohs (((struct GNUNET_MessageHeader *) &m[1])->type),
573 (unsigned int) ret, GNUNET_i2s (&n->peer));
575 process_encrypted_neighbour_queue (n);
580 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
581 "Transmission of message of type %u and size %u failed\n",
583 ntohs (((struct GNUNET_MessageHeader *) &m[1])->type),
584 (unsigned int) m->size);
588 consider_free_neighbour (n);
589 GNUNET_STATISTICS_update (stats,
591 ("# encrypted bytes given to transport"), ret,
598 * Check if we have encrypted messages for the specified neighbour
599 * pending, and if so, check with the transport about sending them
602 * @param n neighbour to check.
605 process_encrypted_neighbour_queue (struct Neighbour *n)
607 struct MessageEntry *m;
610 return; /* request already pending */
611 if (GNUNET_YES != n->is_connected)
616 m = n->encrypted_head;
619 /* encrypted queue empty, try plaintext instead */
620 process_plaintext_neighbour_queue (n);
624 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
625 "Asking transport for transmission of %u bytes to `%4s' in next %llu ms\n",
626 (unsigned int) m->size, GNUNET_i2s (&n->peer),
628 GNUNET_TIME_absolute_get_remaining (m->deadline).rel_value);
631 GNUNET_TRANSPORT_notify_transmit_ready (transport, &n->peer, m->size,
633 GNUNET_TIME_absolute_get_remaining
635 ¬ify_encrypted_transmit_ready,
639 /* message request too large or duplicate request */
641 /* discard encrypted message */
642 GNUNET_CONTAINER_DLL_remove (n->encrypted_head, n->encrypted_tail, m);
644 process_encrypted_neighbour_queue (n);
650 * Initialize a new 'struct Neighbour'.
652 * @param pid ID of the new neighbour
653 * @return handle for the new neighbour
655 static struct Neighbour *
656 create_neighbour (const struct GNUNET_PeerIdentity *pid)
659 struct GNUNET_TIME_Absolute now;
662 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
663 "Creating neighbour entry for peer `%4s'\n", GNUNET_i2s (pid));
665 n = GNUNET_malloc (sizeof (struct Neighbour));
667 GNUNET_CRYPTO_aes_create_session_key (&n->encrypt_key);
668 now = GNUNET_TIME_absolute_get ();
669 n->encrypt_key_created = now;
670 n->last_activity = now;
671 n->set_key_retry_frequency = INITIAL_SET_KEY_RETRY_FREQUENCY;
672 n->bw_in = GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT;
673 n->bw_out = GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT;
674 n->bw_out_internal_limit = GNUNET_BANDWIDTH_value_init (UINT32_MAX);
675 n->bw_out_external_limit = GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT;
677 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX);
678 GNUNET_assert (GNUNET_OK ==
679 GNUNET_CONTAINER_multihashmap_put (neighbours,
680 &n->peer.hashPubKey, n,
681 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
682 GNUNET_STATISTICS_set (stats, gettext_noop ("# neighbour entries allocated"),
683 GNUNET_CONTAINER_multihashmap_size (neighbours),
685 neighbour_quota_update (n, NULL);
686 consider_free_neighbour (n);
692 GSC_NEIGHBOURS_init ()
694 neighbours = GNUNET_CONTAINER_multihashmap_create (128);
695 self.public_key = &my_public_key;
696 self.peer = my_identity;
697 self.last_activity = GNUNET_TIME_UNIT_FOREVER_ABS;
698 self.status = PEER_STATE_KEY_CONFIRMED;
699 self.is_connected = GNUNET_YES;
705 GSC_NEIGHBOURS_done ()
707 GNUNET_CONTAINER_multihashmap_iterate (neighbours, &free_neighbour_helper,
709 GNUNET_CONTAINER_multihashmap_destroy (neighbours);
711 GNUNET_STATISTICS_set (stats, gettext_noop ("# neighbour entries allocated"),