2 This file is part of GNUnet.
3 (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
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.
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.
22 * @file core/gnunet-service-core_sessions.c
23 * @brief code for managing of 'encrypted' sessions (key exchange done)
24 * @author Christian Grothoff
27 #include "gnunet_service_core.h"
28 #include "gnunet_service_core_neighbours.h"
29 #include "gnunet_service_core_kx.h"
30 #include "gnunet_service_core_sessions.h"
33 * Record kept for each request for transmission issued by a
34 * client that is still pending.
36 struct GSC_ClientActiveRequest;
39 * Data kept per session.
44 * Identity of the other peer.
46 struct GNUNET_PeerIdentity peer;
49 * Head of list of requests from clients for transmission to
52 struct GSC_ClientActiveRequest *active_client_request_head;
55 * Tail of list of requests from clients for transmission to
58 struct GSC_ClientActiveRequest *active_client_request_tail;
61 * Performance data for the peer.
63 struct GNUNET_TRANSPORT_ATS_Information *ats;
66 * Information about the key exchange with the other peer.
68 struct GSC_KeyExchangeInfo *kxinfo;
71 * ID of task used for cleaning up dead neighbour entries.
73 GNUNET_SCHEDULER_TaskIdentifier dead_clean_task;
76 * ID of task used for updating bandwidth quota for this neighbour.
78 GNUNET_SCHEDULER_TaskIdentifier quota_update_task;
81 * At what time did we initially establish (as in, complete session
82 * key handshake) this connection? Should be zero if status != KEY_CONFIRMED.
84 struct GNUNET_TIME_Absolute time_established;
87 * At what time did we last receive an encrypted message from the
88 * other peer? Should be zero if status != KEY_CONFIRMED.
90 struct GNUNET_TIME_Absolute last_activity;
93 * How valueable were the messages of this peer recently?
95 unsigned long long current_preference;
98 * Number of entries in 'ats'.
100 unsigned int ats_count;
103 * Bit map indicating which of the 32 sequence numbers before the last
104 * were received (good for accepting out-of-order packets and
105 * estimating reliability of the connection)
107 unsigned int last_packets_bitmap;
110 * last sequence number received on this connection (highest)
112 uint32_t last_sequence_number_received;
115 * last sequence number transmitted
117 uint32_t last_sequence_number_sent;
120 * Available bandwidth in for this peer (current target).
122 struct GNUNET_BANDWIDTH_Value32NBO bw_in;
125 * Available bandwidth out for this peer (current target).
127 struct GNUNET_BANDWIDTH_Value32NBO bw_out;
130 * Internal bandwidth limit set for this peer (initially typically
131 * set to "-1"). Actual "bw_out" is MIN of
132 * "bpm_out_internal_limit" and "bw_out_external_limit".
134 struct GNUNET_BANDWIDTH_Value32NBO bw_out_internal_limit;
137 * External bandwidth limit set for this peer by the
138 * peer that we are communicating with. "bw_out" is MIN of
139 * "bw_out_internal_limit" and "bw_out_external_limit".
141 struct GNUNET_BANDWIDTH_Value32NBO bw_out_external_limit;
147 * Map of peer identities to 'struct Session'.
149 static struct GNUNET_CONTAINER_MultiHashMap *sessions;
153 * Session entry for "this" peer.
155 static struct Session self;
158 * Sum of all preferences among all neighbours.
160 static unsigned long long preference_sum;
166 * At what time should the connection to the given neighbour
167 * time out (given no further activity?)
169 * @param n neighbour in question
170 * @return absolute timeout
172 static struct GNUNET_TIME_Absolute
173 get_neighbour_timeout (struct Neighbour *n)
175 return GNUNET_TIME_absolute_add (n->last_activity,
176 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
181 * Helper function for update_preference_sum.
184 update_preference (void *cls, const GNUNET_HashCode * key, void *value)
186 unsigned long long *ps = cls;
187 struct Neighbour *n = value;
189 n->current_preference /= 2;
190 *ps += n->current_preference;
196 * A preference value for a neighbour was update. Update
197 * the preference sum accordingly.
199 * @param inc how much was a preference value increased?
202 update_preference_sum (unsigned long long inc)
204 unsigned long long os;
207 preference_sum += inc;
208 if (preference_sum >= os)
210 /* overflow! compensate by cutting all values in half! */
212 GNUNET_CONTAINER_multihashmap_iterate (neighbours, &update_preference,
214 GNUNET_STATISTICS_set (stats, gettext_noop ("# total peer preference"),
215 preference_sum, GNUNET_NO);
220 * Find the entry for the given neighbour.
222 * @param peer identity of the neighbour
223 * @return NULL if we are not connected, otherwise the
226 static struct Neighbour *
227 find_neighbour (const struct GNUNET_PeerIdentity *peer)
229 return GNUNET_CONTAINER_multihashmap_get (neighbours, &peer->hashPubKey);
234 * Function called by transport telling us that a peer
237 * @param n the peer that changed status
240 handle_peer_status_change (struct Neighbour *n)
242 struct PeerStatusNotifyMessage *psnm;
243 char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1];
244 struct GNUNET_TRANSPORT_ATS_Information *ats;
247 if ((!n->is_connected) || (n->status != PEER_STATE_KEY_CONFIRMED))
250 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%4s' changed status\n",
251 GNUNET_i2s (&n->peer));
254 sizeof (struct PeerStatusNotifyMessage) +
255 n->ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
256 if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
259 /* recovery strategy: throw away performance data */
260 GNUNET_array_grow (n->ats, n->ats_count, 0);
262 sizeof (struct PeerStatusNotifyMessage) +
263 n->ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
265 psnm = (struct PeerStatusNotifyMessage *) buf;
266 psnm->header.size = htons (size);
267 psnm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_STATUS_CHANGE);
268 psnm->timeout = GNUNET_TIME_absolute_hton (get_neighbour_timeout (n));
269 psnm->bandwidth_in = n->bw_in;
270 psnm->bandwidth_out = n->bw_out;
271 psnm->peer = n->peer;
272 psnm->ats_count = htonl (n->ats_count);
275 n->ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information));
276 ats[n->ats_count].type = htonl (0);
277 ats[n->ats_count].value = htonl (0);
278 send_to_all_clients (&psnm->header, GNUNET_YES,
279 GNUNET_CORE_OPTION_SEND_STATUS_CHANGE);
280 GNUNET_STATISTICS_update (stats, gettext_noop ("# peer status changes"), 1,
287 * Go over our message queue and if it is not too long, go
288 * over the pending requests from clients for this
289 * neighbour and send some clients a 'READY' notification.
291 * @param n which peer to process
294 schedule_peer_messages (struct Neighbour *n)
296 struct GSC_ClientActiveRequest *car;
297 struct GSC_ClientActiveRequest *pos;
299 struct MessageEntry *mqe;
300 unsigned int queue_size;
302 /* check if neighbour queue is empty enough! */
312 if (queue_size >= MAX_PEER_QUEUE_SIZE)
314 #if DEBUG_CORE_CLIENT
315 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
316 "Not considering client transmission requests: queue full\n");
318 return; /* queue still full */
320 /* find highest priority request */
321 pos = n->active_client_request_head;
325 if ((car == NULL) || (pos->priority > car->priority))
332 car = n->active_client_request_head;
335 return; /* no pending requests */
336 #if DEBUG_CORE_CLIENT
337 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
338 "Permitting client transmission request to `%s'\n",
339 GNUNET_i2s (&n->peer));
341 GSC_CLIENTS_solicite_request (car);
347 * Free the given entry for the neighbour (it has
348 * already been removed from the list at this point).
350 * @param n neighbour to free
353 free_neighbour (struct Neighbour *n)
355 struct MessageEntry *m;
356 struct GSC_ClientActiveRequest *car;
359 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
360 "Destroying neighbour entry for peer `%4s'\n",
361 GNUNET_i2s (&n->peer));
365 GNUNET_free (n->skm);
368 while (NULL != (m = n->messages))
370 n->messages = m->next;
373 while (NULL != (m = n->encrypted_head))
375 GNUNET_CONTAINER_DLL_remove (n->encrypted_head, n->encrypted_tail, m);
378 while (NULL != (car = n->active_client_request_head))
380 GNUNET_CONTAINER_DLL_remove (n->active_client_request_head,
381 n->active_client_request_tail, car);
382 GNUNET_assert (GNUNET_YES ==
383 GNUNET_CONTAINER_multihashmap_remove (car->client->requests,
390 GNUNET_TRANSPORT_notify_transmit_ready_cancel (n->th);
393 if (n->retry_plaintext_task != GNUNET_SCHEDULER_NO_TASK)
394 GNUNET_SCHEDULER_cancel (n->retry_plaintext_task);
395 if (n->quota_update_task != GNUNET_SCHEDULER_NO_TASK)
396 GNUNET_SCHEDULER_cancel (n->quota_update_task);
397 if (n->dead_clean_task != GNUNET_SCHEDULER_NO_TASK)
398 GNUNET_SCHEDULER_cancel (n->keep_alive_task);
399 if (n->status == PEER_STATE_KEY_CONFIRMED)
400 GNUNET_STATISTICS_update (stats, gettext_noop ("# established sessions"),
402 GNUNET_array_grow (n->ats, n->ats_count, 0);
403 GNUNET_free_non_null (n->pending_ping);
404 GNUNET_free_non_null (n->pending_pong);
411 * Consider freeing the given neighbour since we may not need
412 * to keep it around anymore.
414 * @param n neighbour to consider discarding
417 consider_free_neighbour (struct Neighbour *n);
421 * Task triggered when a neighbour entry might have gotten stale.
423 * @param cls the 'struct Neighbour'
424 * @param tc scheduler context (not used)
427 consider_free_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
429 struct Neighbour *n = cls;
431 n->dead_clean_task = GNUNET_SCHEDULER_NO_TASK;
432 consider_free_neighbour (n);
437 * Consider freeing the given neighbour since we may not need
438 * to keep it around anymore.
440 * @param n neighbour to consider discarding
443 consider_free_neighbour (struct Neighbour *n)
445 struct GNUNET_TIME_Relative left;
447 if ((n->th != NULL) || (n->pitr != NULL) || (GNUNET_YES == n->is_connected))
448 return; /* no chance */
450 left = GNUNET_TIME_absolute_get_remaining (get_neighbour_timeout (n));
451 if (left.rel_value > 0)
453 if (n->dead_clean_task != GNUNET_SCHEDULER_NO_TASK)
454 GNUNET_SCHEDULER_cancel (n->dead_clean_task);
456 GNUNET_SCHEDULER_add_delayed (left, &consider_free_task, n);
459 /* actually free the neighbour... */
460 GNUNET_assert (GNUNET_YES ==
461 GNUNET_CONTAINER_multihashmap_remove (neighbours,
462 &n->peer.hashPubKey, n));
463 GNUNET_STATISTICS_set (stats, gettext_noop ("# neighbour entries allocated"),
464 GNUNET_CONTAINER_multihashmap_size (neighbours),
471 * Function called when the transport service is ready to
472 * receive an encrypted message for the respective peer
474 * @param cls neighbour to use message from
475 * @param size number of bytes we can transmit
476 * @param buf where to copy the message
477 * @return number of bytes transmitted
480 notify_encrypted_transmit_ready (void *cls, size_t size, void *buf)
482 struct Neighbour *n = cls;
483 struct MessageEntry *m;
488 m = n->encrypted_head;
492 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
493 "Encrypted message queue empty, no messages added to buffer for `%4s'\n",
494 GNUNET_i2s (&n->peer));
498 GNUNET_CONTAINER_DLL_remove (n->encrypted_head, n->encrypted_tail, m);
503 GNUNET_assert (size >= m->size);
504 memcpy (cbuf, &m[1], m->size);
506 GNUNET_BANDWIDTH_tracker_consume (&n->available_send_window, m->size);
508 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
509 "Copied message of type %u and size %u into transport buffer for `%4s'\n",
511 ntohs (((struct GNUNET_MessageHeader *) &m[1])->type),
512 (unsigned int) ret, GNUNET_i2s (&n->peer));
514 process_encrypted_neighbour_queue (n);
519 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
520 "Transmission of message of type %u and size %u failed\n",
522 ntohs (((struct GNUNET_MessageHeader *) &m[1])->type),
523 (unsigned int) m->size);
527 consider_free_neighbour (n);
528 GNUNET_STATISTICS_update (stats,
530 ("# encrypted bytes given to transport"), ret,
540 * Select messages for transmission. This heuristic uses a combination
541 * of earliest deadline first (EDF) scheduling (with bounded horizon)
542 * and priority-based discard (in case no feasible schedule exist) and
543 * speculative optimization (defer any kind of transmission until
544 * we either create a batch of significant size, 25% of max, or until
545 * we are close to a deadline). Furthermore, when scheduling the
546 * heuristic also packs as many messages into the batch as possible,
547 * starting with those with the earliest deadline. Yes, this is fun.
549 * @param n neighbour to select messages from
550 * @param size number of bytes to select for transmission
551 * @param retry_time set to the time when we should try again
552 * (only valid if this function returns zero)
553 * @return number of bytes selected, or 0 if we decided to
554 * defer scheduling overall; in that case, retry_time is set.
557 select_messages (struct Neighbour *n, size_t size,
558 struct GNUNET_TIME_Relative *retry_time)
560 struct MessageEntry *pos;
561 struct MessageEntry *min;
562 struct MessageEntry *last;
563 unsigned int min_prio;
564 struct GNUNET_TIME_Absolute t;
565 struct GNUNET_TIME_Absolute now;
566 struct GNUNET_TIME_Relative delta;
568 struct GNUNET_TIME_Relative slack; /* how long could we wait before missing deadlines? */
571 unsigned int queue_size;
572 int discard_low_prio;
574 GNUNET_assert (NULL != n->messages);
575 now = GNUNET_TIME_absolute_get ();
576 /* last entry in linked list of messages processed */
578 /* should we remove the entry with the lowest
579 * priority from consideration for scheduling at the
580 * end of the loop? */
590 discard_low_prio = GNUNET_YES;
591 while (GNUNET_YES == discard_low_prio)
595 discard_low_prio = GNUNET_NO;
596 /* calculate number of bytes available for transmission at time "t" */
597 avail = GNUNET_BANDWIDTH_tracker_get_available (&n->available_send_window);
599 /* how many bytes have we (hypothetically) scheduled so far */
601 /* maximum time we can wait before transmitting anything
602 * and still make all of our deadlines */
603 slack = GNUNET_TIME_UNIT_FOREVER_REL;
605 /* note that we use "*2" here because we want to look
606 * a bit further into the future; much more makes no
607 * sense since new message might be scheduled in the
609 while ((pos != NULL) && (off < size * 2))
611 if (pos->do_transmit == GNUNET_YES)
613 /* already removed from consideration */
617 if (discard_low_prio == GNUNET_NO)
619 delta = GNUNET_TIME_absolute_get_difference (t, pos->deadline);
620 if (delta.rel_value > 0)
622 // FIXME: HUH? Check!
625 GNUNET_BANDWIDTH_value_get_available_until (n->bw_out, delta);
627 if (avail < pos->size)
629 // FIXME: HUH? Check!
630 discard_low_prio = GNUNET_YES; /* we could not schedule this one! */
635 /* update slack, considering both its absolute deadline
636 * and relative deadlines caused by other messages
637 * with their respective load */
639 GNUNET_TIME_relative_min (slack,
640 GNUNET_BANDWIDTH_value_get_delay_for
642 if (pos->deadline.abs_value <= now.abs_value)
645 slack = GNUNET_TIME_UNIT_ZERO;
647 else if (GNUNET_YES == pos->got_slack)
649 /* should be soon now! */
651 GNUNET_TIME_relative_min (slack,
652 GNUNET_TIME_absolute_get_remaining
653 (pos->slack_deadline));
658 GNUNET_TIME_relative_min (slack,
659 GNUNET_TIME_absolute_get_difference
660 (now, pos->deadline));
661 pos->got_slack = GNUNET_YES;
662 pos->slack_deadline =
663 GNUNET_TIME_absolute_min (pos->deadline,
664 GNUNET_TIME_relative_to_absolute
665 (GNUNET_CONSTANTS_MAX_CORK_DELAY));
670 t = GNUNET_TIME_absolute_max (pos->deadline, t); // HUH? Check!
671 if (pos->priority <= min_prio)
673 /* update min for discard */
674 min_prio = pos->priority;
679 if (discard_low_prio)
681 GNUNET_assert (min != NULL);
682 /* remove lowest-priority entry from consideration */
683 min->do_transmit = GNUNET_YES; /* means: discard (for now) */
687 /* guard against sending "tiny" messages with large headers without
688 * urgent deadlines */
689 if ((slack.rel_value > GNUNET_CONSTANTS_MAX_CORK_DELAY.rel_value) &&
690 (size > 4 * off) && (queue_size <= MAX_PEER_QUEUE_SIZE - 2))
692 /* less than 25% of message would be filled with deadlines still
693 * being met if we delay by one second or more; so just wait for
694 * more data; but do not wait longer than 1s (since we don't want
695 * to delay messages for a really long time either). */
696 *retry_time = GNUNET_CONSTANTS_MAX_CORK_DELAY;
697 /* reset do_transmit values for next time */
700 pos->do_transmit = GNUNET_NO;
703 GNUNET_STATISTICS_update (stats,
705 ("# transmissions delayed due to corking"), 1,
708 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
709 "Deferring transmission for %llums due to underfull message buffer size (%u/%u)\n",
710 (unsigned long long) retry_time->rel_value, (unsigned int) off,
711 (unsigned int) size);
715 /* select marked messages (up to size) for transmission */
720 if ((pos->size <= size) && (pos->do_transmit == GNUNET_NO))
722 pos->do_transmit = GNUNET_YES; /* mark for transmission */
726 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
727 "Selecting message of size %u for transmission\n",
728 (unsigned int) pos->size);
734 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
735 "Not selecting message of size %u for transmission at this time (maximum is %u)\n",
736 (unsigned int) pos->size, size);
738 pos->do_transmit = GNUNET_NO; /* mark for not transmitting! */
743 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
744 "Selected %llu/%llu bytes of %u/%u plaintext messages for transmission to `%4s'.\n",
745 (unsigned long long) off, (unsigned long long) tsize, queue_size,
746 (unsigned int) MAX_PEER_QUEUE_SIZE, GNUNET_i2s (&n->peer));
753 * Batch multiple messages into a larger buffer.
755 * @param n neighbour to take messages from
756 * @param buf target buffer
757 * @param size size of buf
758 * @param deadline set to transmission deadline for the result
759 * @param retry_time set to the time when we should try again
760 * (only valid if this function returns zero)
761 * @param priority set to the priority of the batch
762 * @return number of bytes written to buf (can be zero)
765 batch_message (struct Neighbour *n, char *buf, size_t size,
766 struct GNUNET_TIME_Absolute *deadline,
767 struct GNUNET_TIME_Relative *retry_time, unsigned int *priority)
769 char ntmb[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1];
770 struct NotifyTrafficMessage *ntm = (struct NotifyTrafficMessage *) ntmb;
771 struct MessageEntry *pos;
772 struct MessageEntry *prev;
773 struct MessageEntry *next;
778 *deadline = GNUNET_TIME_UNIT_FOREVER_ABS;
779 *retry_time = GNUNET_TIME_UNIT_FOREVER_REL;
780 if (0 == select_messages (n, size, retry_time))
783 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
784 "No messages selected, will try again in %llu ms\n",
785 retry_time->rel_value);
789 ntm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_OUTBOUND);
790 ntm->ats_count = htonl (0);
791 ntm->ats.type = htonl (0);
792 ntm->ats.value = htonl (0);
796 while ((pos != NULL) && (size >= sizeof (struct GNUNET_MessageHeader)))
799 if (GNUNET_YES == pos->do_transmit)
801 GNUNET_assert (pos->size <= size);
802 /* do notifications */
803 /* FIXME: track if we have *any* client that wants
804 * full notifications and only do this if that is
807 GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct NotifyTrafficMessage))
809 memcpy (&ntm[1], &pos[1], pos->size);
811 htons (sizeof (struct NotifyTrafficMessage) +
812 sizeof (struct GNUNET_MessageHeader));
813 send_to_all_clients (&ntm->header, GNUNET_YES,
814 GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND);
818 /* message too large for 'full' notifications, we do at
819 * least the 'hdr' type */
820 memcpy (&ntm[1], &pos[1], sizeof (struct GNUNET_MessageHeader));
823 htons (sizeof (struct NotifyTrafficMessage) + pos->size);
824 send_to_all_clients (&ntm->header, GNUNET_YES,
825 GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND);
827 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
828 "Encrypting %u bytes with message of type %u and size %u\n",
831 ntohs (((const struct GNUNET_MessageHeader *) &pos[1])->type),
833 ntohs (((const struct GNUNET_MessageHeader *)
836 /* copy for encrypted transmission */
837 memcpy (&buf[ret], &pos[1], pos->size);
840 *priority += pos->priority;
842 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
843 "Adding plaintext message of size %u with deadline %llu ms to batch\n",
844 (unsigned int) pos->size,
846 GNUNET_TIME_absolute_get_remaining (pos->deadline).rel_value);
848 deadline->abs_value =
849 GNUNET_MIN (deadline->abs_value, pos->deadline.abs_value);
863 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
864 "Deadline for message batch is %llu ms\n",
865 GNUNET_TIME_absolute_get_remaining (*deadline).rel_value);
872 * Remove messages with deadlines that have long expired from
875 * @param n neighbour to inspect
878 discard_expired_messages (struct Neighbour *n)
880 struct MessageEntry *prev;
881 struct MessageEntry *next;
882 struct MessageEntry *pos;
883 struct GNUNET_TIME_Absolute now;
884 struct GNUNET_TIME_Relative delta;
886 unsigned int queue_length;
889 now = GNUNET_TIME_absolute_get ();
897 delta = GNUNET_TIME_absolute_get_difference (pos->deadline, now);
898 if (delta.rel_value > PAST_EXPIRATION_DISCARD_TIME.rel_value)
901 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
902 "Message is %llu ms past due, discarding.\n",
909 GNUNET_STATISTICS_update (stats,
911 ("# messages discarded (expired prior to transmission)"),
920 if ( (GNUNET_YES == disc) &&
921 (queue_length == MAX_PEER_QUEUE_SIZE) )
922 schedule_peer_messages (n);
927 * Signature of the main function of a task.
930 * @param tc context information (why was this task triggered now)
933 retry_plaintext_processing (void *cls,
934 const struct GNUNET_SCHEDULER_TaskContext *tc)
936 struct Neighbour *n = cls;
938 n->retry_plaintext_task = GNUNET_SCHEDULER_NO_TASK;
939 process_plaintext_neighbour_queue (n);
944 * Check if we have plaintext messages for the specified neighbour
945 * pending, and if so, consider batching and encrypting them (and
946 * then trigger processing of the encrypted queue if needed).
948 * @param n neighbour to check.
951 process_plaintext_neighbour_queue (struct Neighbour *n)
953 char pbuf[GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE + sizeof (struct EncryptedMessage)]; /* plaintext */
955 struct EncryptedMessage *em; /* encrypted message */
956 struct EncryptedMessage *ph; /* plaintext header */
957 struct MessageEntry *me;
958 unsigned int priority;
959 struct GNUNET_TIME_Absolute deadline;
960 struct GNUNET_TIME_Relative retry_time;
961 struct GNUNET_CRYPTO_AesInitializationVector iv;
962 struct GNUNET_CRYPTO_AuthKey auth_key;
964 if (n->retry_plaintext_task != GNUNET_SCHEDULER_NO_TASK)
966 GNUNET_SCHEDULER_cancel (n->retry_plaintext_task);
967 n->retry_plaintext_task = GNUNET_SCHEDULER_NO_TASK;
971 case PEER_STATE_DOWN:
974 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
975 "Not yet connected to `%4s', deferring processing of plaintext messages.\n",
976 GNUNET_i2s (&n->peer));
979 case PEER_STATE_KEY_SENT:
980 if (n->retry_set_key_task == GNUNET_SCHEDULER_NO_TASK)
981 n->retry_set_key_task =
982 GNUNET_SCHEDULER_add_delayed (n->set_key_retry_frequency,
983 &set_key_retry_task, n);
985 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
986 "Not yet connected to `%4s', deferring processing of plaintext messages.\n",
987 GNUNET_i2s (&n->peer));
990 case PEER_STATE_KEY_RECEIVED:
991 if (n->retry_set_key_task == GNUNET_SCHEDULER_NO_TASK)
992 n->retry_set_key_task =
993 GNUNET_SCHEDULER_add_delayed (n->set_key_retry_frequency,
994 &set_key_retry_task, n);
996 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
997 "Not yet connected to `%4s', deferring processing of plaintext messages.\n",
998 GNUNET_i2s (&n->peer));
1001 case PEER_STATE_KEY_CONFIRMED:
1002 /* ready to continue */
1005 discard_expired_messages (n);
1006 if (n->messages == NULL)
1009 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1010 "Plaintext message queue for `%4s' is empty.\n",
1011 GNUNET_i2s (&n->peer));
1013 return; /* no pending messages */
1015 if (n->encrypted_head != NULL)
1018 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1019 "Encrypted message queue for `%4s' is still full, delaying plaintext processing.\n",
1020 GNUNET_i2s (&n->peer));
1022 return; /* wait for messages already encrypted to be
1023 * processed first! */
1025 ph = (struct EncryptedMessage *) pbuf;
1026 deadline = GNUNET_TIME_UNIT_FOREVER_ABS;
1028 used = sizeof (struct EncryptedMessage);
1030 batch_message (n, &pbuf[used],
1031 GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE, &deadline,
1032 &retry_time, &priority);
1033 if (used == sizeof (struct EncryptedMessage))
1036 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1037 "No messages selected for transmission to `%4s' at this time, will try again later.\n",
1038 GNUNET_i2s (&n->peer));
1040 /* no messages selected for sending, try again later... */
1041 n->retry_plaintext_task =
1042 GNUNET_SCHEDULER_add_delayed (retry_time, &retry_plaintext_processing,
1046 GSC_KX_encrypt_and_transmit (n->kx,
1047 &pbuf[struct EncryptedMessage],
1048 used - sizeof (struct EncryptedMessage));
1049 schedule_peer_messages (n);
1056 * Check if we have encrypted messages for the specified neighbour
1057 * pending, and if so, check with the transport about sending them
1060 * @param n neighbour to check.
1063 process_encrypted_neighbour_queue (struct Neighbour *n)
1065 struct MessageEntry *m;
1068 return; /* request already pending */
1069 if (GNUNET_YES != n->is_connected)
1074 m = n->encrypted_head;
1077 /* encrypted queue empty, try plaintext instead */
1078 process_plaintext_neighbour_queue (n);
1082 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1083 "Asking transport for transmission of %u bytes to `%4s' in next %llu ms\n",
1084 (unsigned int) m->size, GNUNET_i2s (&n->peer),
1085 (unsigned long long)
1086 GNUNET_TIME_absolute_get_remaining (m->deadline).rel_value);
1089 GNUNET_TRANSPORT_notify_transmit_ready (transport, &n->peer, m->size,
1091 GNUNET_TIME_absolute_get_remaining
1093 ¬ify_encrypted_transmit_ready,
1097 /* message request too large or duplicate request */
1099 /* discard encrypted message */
1100 GNUNET_CONTAINER_DLL_remove (n->encrypted_head, n->encrypted_tail, m);
1102 process_encrypted_neighbour_queue (n);
1108 * Initialize a new 'struct Neighbour'.
1110 * @param pid ID of the new neighbour
1111 * @return handle for the new neighbour
1113 static struct Neighbour *
1114 create_neighbour (const struct GNUNET_PeerIdentity *pid)
1116 struct Neighbour *n;
1117 struct GNUNET_TIME_Absolute now;
1120 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1121 "Creating neighbour entry for peer `%4s'\n", GNUNET_i2s (pid));
1123 n = GNUNET_malloc (sizeof (struct Neighbour));
1125 n->last_activity = GNUNET_TIME_absolute_get ();
1126 n->bw_in = GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT;
1127 n->bw_out = GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT;
1128 n->bw_out_internal_limit = GNUNET_BANDWIDTH_value_init (UINT32_MAX);
1129 n->bw_out_external_limit = GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT;
1131 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX);
1132 GNUNET_assert (GNUNET_OK ==
1133 GNUNET_CONTAINER_multihashmap_put (neighbours,
1134 &n->peer.hashPubKey, n,
1135 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1136 GNUNET_STATISTICS_set (stats, gettext_noop ("# neighbour entries allocated"),
1137 GNUNET_CONTAINER_multihashmap_size (neighbours),
1139 neighbour_quota_update (n, NULL);
1140 consider_free_neighbour (n);
1147 * We have a new client, notify it about all current sessions.
1149 * @param client the new client
1152 GSC_SESSIONS_notify_client_about_sessions (struct GSC_Client *client)
1154 /* notify new client about existing neighbours */
1155 GNUNET_CONTAINER_multihashmap_iterate (neighbours,
1156 ¬ify_client_about_neighbour, client);
1161 * Queue a request from a client for transmission to a particular peer.
1163 * @param car request to queue; this handle is then shared between
1164 * the caller (CLIENTS subsystem) and SESSIONS and must not
1165 * be released by either until either 'GNUNET_SESSIONS_dequeue',
1166 * 'GNUNET_SESSIONS_transmit' or 'GNUNET_CLIENTS_failed'
1167 * have been invoked on it
1170 GSC_SESSIONS_queue_request (struct GSC_ClientActiveRequest *car)
1172 struct Neighbour *n; // FIXME: session...
1174 n = find_neighbour (&car->peer);
1175 if ((n == NULL) || (GNUNET_YES != n->is_connected) ||
1176 (n->status != PEER_STATE_KEY_CONFIRMED))
1178 /* neighbour must have disconnected since request was issued,
1179 * ignore (client will realize it once it processes the
1180 * disconnect notification) */
1181 #if DEBUG_CORE_CLIENT
1182 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1183 "Dropped client request for transmission (am disconnected)\n");
1185 GNUNET_STATISTICS_update (stats,
1187 ("# send requests dropped (disconnected)"), 1,
1189 GSC_CLIENTS_reject_requests (car);
1192 #if DEBUG_CORE_CLIENT
1193 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1194 "Received client transmission request. queueing\n");
1196 GNUNET_CONTAINER_DLL_insert (n->active_client_request_head,
1197 n->active_client_request_tail, car);
1199 // schedule_peer_messages (n);
1204 * Dequeue a request from a client from transmission to a particular peer.
1206 * @param car request to dequeue; this handle will then be 'owned' by
1207 * the caller (CLIENTS sysbsystem)
1210 GSC_SESSIONS_dequeue_request (struct GSC_ClientActiveRequest *car)
1214 s = find_session (&car->peer);
1215 GNUNET_CONTAINER_DLL_remove (s->active_client_request_head,
1216 s->active_client_request_tail, car);
1222 * Transmit a message to a particular peer.
1224 * @param car original request that was queued and then solicited;
1225 * this handle will now be 'owned' by the SESSIONS subsystem
1226 * @param msg message to transmit
1229 GSC_SESSIONS_transmit (struct GSC_ClientActiveRequest *car,
1230 const struct GNUNET_MessageHeader *msg)
1232 struct MessageEntry *prev;
1233 struct MessageEntry *pos;
1234 struct MessageEntry *e;
1235 struct MessageEntry *min_prio_entry;
1236 struct MessageEntry *min_prio_prev;
1237 unsigned int min_prio;
1238 unsigned int queue_size;
1240 n = find_neighbour (&sm->peer);
1241 if ((n == NULL) || (GNUNET_YES != n->is_connected) ||
1242 (n->status != PEER_STATE_KEY_CONFIRMED))
1244 /* attempt to send message to peer that is not connected anymore
1245 * (can happen due to asynchrony) */
1246 GNUNET_STATISTICS_update (stats,
1248 ("# messages discarded (disconnected)"), 1,
1251 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1255 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1256 "Core received `%s' request, queueing %u bytes of plaintext data for transmission to `%4s'.\n",
1257 "SEND", (unsigned int) msize, GNUNET_i2s (&sm->peer));
1259 discard_expired_messages (n);
1260 /* bound queue size */
1261 /* NOTE: this entire block to bound the queue size should be
1262 * obsolete with the new client-request code and the
1263 * 'schedule_peer_messages' mechanism; we still have this code in
1264 * here for now as a sanity check for the new mechanmism;
1265 * ultimately, we should probably simply reject SEND messages that
1266 * are not 'approved' (or provide a new core API for very unreliable
1267 * delivery that always sends with priority 0). Food for thought. */
1268 min_prio = UINT32_MAX;
1269 min_prio_entry = NULL;
1270 min_prio_prev = NULL;
1276 if (pos->priority <= min_prio)
1278 min_prio_entry = pos;
1279 min_prio_prev = prev;
1280 min_prio = pos->priority;
1286 if (queue_size >= MAX_PEER_QUEUE_SIZE)
1289 if (ntohl (sm->priority) <= min_prio)
1291 /* discard new entry; this should no longer happen! */
1294 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1295 "Queue full (%u/%u), discarding new request (%u bytes of type %u)\n",
1296 queue_size, (unsigned int) MAX_PEER_QUEUE_SIZE,
1297 (unsigned int) msize, (unsigned int) ntohs (message->type));
1299 GNUNET_STATISTICS_update (stats,
1300 gettext_noop ("# discarded CORE_SEND requests"),
1304 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1307 GNUNET_assert (min_prio_entry != NULL);
1308 /* discard "min_prio_entry" */
1310 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1311 "Queue full, discarding existing older request\n");
1313 GNUNET_STATISTICS_update (stats,
1315 ("# discarded lower priority CORE_SEND requests"),
1317 if (min_prio_prev == NULL)
1318 n->messages = min_prio_entry->next;
1320 min_prio_prev->next = min_prio_entry->next;
1321 GNUNET_free (min_prio_entry);
1325 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1326 "Adding transmission request for `%4s' of size %u to queue\n",
1327 GNUNET_i2s (&sm->peer), (unsigned int) msize);
1329 e = GNUNET_malloc (sizeof (struct MessageEntry) + msize);
1330 e->deadline = GNUNET_TIME_absolute_ntoh (sm->deadline);
1331 e->priority = ntohl (sm->priority);
1333 if (GNUNET_YES != (int) ntohl (sm->cork))
1334 e->got_slack = GNUNET_YES;
1335 memcpy (&e[1], &sm[1], msize);
1337 /* insert, keep list sorted by deadline */
1340 while ((pos != NULL) && (pos->deadline.abs_value < e->deadline.abs_value))
1351 /* consider scheduling now */
1352 process_plaintext_neighbour_queue (n);
1359 * Send a message to the neighbour.
1361 * @param cls the message
1362 * @param key neighbour's identity
1363 * @param value 'struct Neighbour' of the target
1364 * @return always GNUNET_OK
1367 do_send_message (void *cls, const GNUNET_HashCode * key, void *value)
1369 struct GNUNET_MessageHeader *hdr = cls;
1370 struct Neighbour *n = value;
1371 struct MessageEntry *m;
1374 size = ntohs (hdr->size);
1375 m = GNUNET_malloc (sizeof (struct MessageEntry) + size);
1376 memcpy (&m[1], hdr, size);
1377 m->deadline = GNUNET_TIME_UNIT_FOREVER_ABS;
1378 m->slack_deadline = GNUNET_TIME_UNIT_FOREVER_ABS;
1379 m->priority = UINT_MAX;
1380 m->sender_status = n->status;
1382 GNUNET_CONTAINER_DLL_insert (n->message_head,
1390 * Broadcast a message to all neighbours.
1392 * @param msg message to transmit
1395 GSC_SESSIONS_broadcast (const struct GNUNET_MessageHeader *msg)
1397 if (NULL == sessions)
1399 GNUNET_CONTAINER_multihashmap_iterate (sessions,
1400 &do_send_message, msg);
1405 * Helper function for GSC_SESSIONS_handle_client_iterate_peers.
1407 * @param cls the 'struct GNUNET_SERVER_TransmitContext' to queue replies
1408 * @param key identity of the connected peer
1409 * @param value the 'struct Neighbour' for the peer
1410 * @return GNUNET_OK (continue to iterate)
1413 queue_connect_message (void *cls, const GNUNET_HashCode * key, void *value)
1415 struct GNUNET_SERVER_TransmitContext *tc = cls;
1416 struct Neighbour *n = value;
1417 char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1];
1418 struct GNUNET_TRANSPORT_ATS_Information *ats;
1420 struct ConnectNotifyMessage *cnm;
1422 cnm = (struct ConnectNotifyMessage *) buf;
1423 if (n->status != PEER_STATE_KEY_CONFIRMED)
1426 sizeof (struct ConnectNotifyMessage) +
1427 (n->ats_count) * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
1428 if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1431 /* recovery strategy: throw away performance data */
1432 GNUNET_array_grow (n->ats, n->ats_count, 0);
1434 sizeof (struct PeerStatusNotifyMessage) +
1435 n->ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
1437 cnm = (struct ConnectNotifyMessage *) buf;
1438 cnm->header.size = htons (size);
1439 cnm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT);
1440 cnm->ats_count = htonl (n->ats_count);
1442 memcpy (ats, n->ats,
1443 n->ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information));
1444 ats[n->ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
1445 ats[n->ats_count].value = htonl (0);
1446 #if DEBUG_CORE_CLIENT
1447 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message to client.\n",
1450 cnm->peer = n->peer;
1451 GNUNET_SERVER_transmit_context_append_message (tc, &cnm->header);
1457 * End the session with the given peer (we are no longer
1460 * @param pid identity of peer to kill session with
1463 GSC_SESSIONS_end (const struct GNUNET_PeerIdentity *pid)
1469 * Traffic is being solicited for the given peer. This means that the
1470 * message queue on the transport-level (NEIGHBOURS subsystem) is now
1471 * empty and it is now OK to transmit another (non-control) message.
1473 * @param pid identity of peer ready to receive data
1476 GSC_SESSIONS_solicit (const struct GNUNET_PeerIdentity *pid)
1482 * Transmit a message to a particular peer.
1484 * @param car original request that was queued and then solicited,
1485 * ownership does not change (dequeue will be called soon).
1486 * @param msg message to transmit
1489 GSC_SESSIONS_transmit (struct GSC_ClientActiveRequest *car,
1490 const struct GNUNET_MessageHeader *msg)
1496 * We have a new client, notify it about all current sessions.
1498 * @param client the new client
1501 GSC_SESSIONS_notify_client_about_sessions (struct GSC_Client *client)
1507 * Handle CORE_ITERATE_PEERS request. For this request type, the client
1508 * does not have to have transmitted an INIT request. All current peers
1509 * are returned, regardless of which message types they accept.
1512 * @param client client sending the iteration request
1513 * @param message iteration request message
1516 GSC_SESSIONS_handle_client_iterate_peers (void *cls, struct GNUNET_SERVER_Client *client,
1517 const struct GNUNET_MessageHeader *message)
1519 struct GNUNET_MessageHeader done_msg;
1520 struct GNUNET_SERVER_TransmitContext *tc;
1522 tc = GNUNET_SERVER_transmit_context_create (client);
1523 GNUNET_CONTAINER_multihashmap_iterate (neighbours, &queue_connect_message,
1525 done_msg.size = htons (sizeof (struct GNUNET_MessageHeader));
1526 done_msg.type = htons (GNUNET_MESSAGE_TYPE_CORE_ITERATE_PEERS_END);
1527 GNUNET_SERVER_transmit_context_append_message (tc, &done_msg);
1528 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
1533 * Handle CORE_PEER_CONNECTED request. Notify client about connection
1534 * to the given neighbour. For this request type, the client does not
1535 * have to have transmitted an INIT request. All current peers are
1536 * returned, regardless of which message types they accept.
1539 * @param client client sending the iteration request
1540 * @param message iteration request message
1543 GSC_SESSIONS_handle_client_have_peer (void *cls, struct GNUNET_SERVER_Client *client,
1544 const struct GNUNET_MessageHeader *message)
1546 struct GNUNET_MessageHeader done_msg;
1547 struct GNUNET_SERVER_TransmitContext *tc;
1548 const struct GNUNET_PeerIdentity *peer;
1550 peer = (const struct GNUNET_PeerIdentity *) &message[1]; // YUCK!
1551 tc = GNUNET_SERVER_transmit_context_create (client);
1552 GNUNET_CONTAINER_multihashmap_get_multiple (neighbours, &peer->hashPubKey,
1553 &queue_connect_message, tc);
1554 done_msg.size = htons (sizeof (struct GNUNET_MessageHeader));
1555 done_msg.type = htons (GNUNET_MESSAGE_TYPE_CORE_ITERATE_PEERS_END);
1556 GNUNET_SERVER_transmit_context_append_message (tc, &done_msg);
1557 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
1563 * Handle REQUEST_INFO request. For this request type, the client must
1564 * have transmitted an INIT first.
1567 * @param client client sending the request
1568 * @param message iteration request message
1571 GSC_SESSIONS_handle_client_request_info (void *cls, struct GNUNET_SERVER_Client *client,
1572 const struct GNUNET_MessageHeader *message)
1574 const struct RequestInfoMessage *rcm;
1575 struct GSC_Client *pos;
1576 struct Neighbour *n;
1577 struct ConfigurationInfoMessage cim;
1578 int32_t want_reserv;
1580 unsigned long long old_preference;
1581 struct GNUNET_TIME_Relative rdelay;
1583 rdelay = GNUNET_TIME_relative_get_zero ();
1584 #if DEBUG_CORE_CLIENT
1585 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Core service receives `%s' request.\n",
1588 rcm = (const struct RequestInfoMessage *) message;
1589 n = find_neighbour (&rcm->peer);
1590 memset (&cim, 0, sizeof (cim));
1591 if ((n != NULL) && (GNUNET_YES == n->is_connected))
1593 want_reserv = ntohl (rcm->reserve_inbound);
1594 if (n->bw_out_internal_limit.value__ != rcm->limit_outbound.value__)
1596 n->bw_out_internal_limit = rcm->limit_outbound;
1597 if (n->bw_out.value__ !=
1598 GNUNET_BANDWIDTH_value_min (n->bw_out_internal_limit,
1599 n->bw_out_external_limit).value__)
1602 GNUNET_BANDWIDTH_value_min (n->bw_out_internal_limit,
1603 n->bw_out_external_limit);
1604 GNUNET_BANDWIDTH_tracker_update_quota (&n->available_recv_window,
1606 GNUNET_TRANSPORT_set_quota (transport, &n->peer, n->bw_in, n->bw_out);
1607 handle_peer_status_change (n);
1610 if (want_reserv < 0)
1612 got_reserv = want_reserv;
1614 else if (want_reserv > 0)
1617 GNUNET_BANDWIDTH_tracker_get_delay (&n->available_recv_window,
1619 if (rdelay.rel_value == 0)
1620 got_reserv = want_reserv;
1622 got_reserv = 0; /* all or nothing */
1626 GNUNET_BANDWIDTH_tracker_consume (&n->available_recv_window, got_reserv);
1627 old_preference = n->current_preference;
1628 n->current_preference += GNUNET_ntohll (rcm->preference_change);
1629 if (old_preference > n->current_preference)
1631 /* overflow; cap at maximum value */
1632 n->current_preference = ULLONG_MAX;
1634 update_preference_sum (n->current_preference - old_preference);
1635 #if DEBUG_CORE_QUOTA
1636 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1637 "Received reservation request for %d bytes for peer `%4s', reserved %d bytes, suggesting delay of %llu ms\n",
1638 (int) want_reserv, GNUNET_i2s (&rcm->peer), (int) got_reserv,
1639 (unsigned long long) rdelay.rel_value);
1641 cim.reserved_amount = htonl (got_reserv);
1642 cim.reserve_delay = GNUNET_TIME_relative_hton (rdelay);
1643 cim.bw_out = n->bw_out;
1644 cim.preference = n->current_preference;
1648 /* Technically, this COULD happen (due to asynchronous behavior),
1649 * but it should be rare, so we should generate an info event
1650 * to help diagnosis of serious errors that might be masked by this */
1651 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1653 ("Client asked for preference change with peer `%s', which is not connected!\n"),
1654 GNUNET_i2s (&rcm->peer));
1655 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1658 cim.header.size = htons (sizeof (struct ConfigurationInfoMessage));
1659 cim.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_CONFIGURATION_INFO);
1660 cim.peer = rcm->peer;
1661 cim.rim_id = rcm->rim_id;
1662 #if DEBUG_CORE_CLIENT
1663 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message to client.\n",
1664 "CONFIGURATION_INFO");
1666 GSC_CLIENTS_send_to_client (client, &cim.header, GNUNET_NO);
1667 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1672 * Create a session, a key exchange was just completed.
1674 * @param peer peer that is now connected
1675 * @param kx key exchange that completed
1678 GSC_SESSIONS_create (const struct GNUNET_PeerIdentity *peer,
1679 struct GSC_KeyExchangeInfo *kx)
1682 struct GNUNET_MessageHeader *hdr;
1684 hdr = compute_type_map_message ();
1685 send_type_map_to_neighbour (hdr, &n->peer.hashPubKey, n);
1688 if (n->bw_out_external_limit.value__ != t.inbound_bw_limit.value__)
1690 n->bw_out_external_limit = t.inbound_bw_limit;
1692 GNUNET_BANDWIDTH_value_min (n->bw_out_external_limit,
1693 n->bw_out_internal_limit);
1694 GNUNET_BANDWIDTH_tracker_update_quota (&n->available_send_window,
1696 GNUNET_TRANSPORT_set_quota (transport, &n->peer, n->bw_in, n->bw_out);
1699 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1700 "Confirmed key via `%s' message for peer `%4s'\n", "PONG",
1701 GNUNET_i2s (&n->peer));
1706 sizeof (struct ConnectNotifyMessage) +
1707 (n->ats_count) * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
1708 if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1711 /* recovery strategy: throw away performance data */
1712 GNUNET_array_grow (n->ats, n->ats_count, 0);
1714 sizeof (struct PeerStatusNotifyMessage) +
1715 n->ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
1717 cnm = (struct ConnectNotifyMessage *) buf;
1718 cnm->header.size = htons (size);
1719 cnm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT);
1720 cnm->ats_count = htonl (n->ats_count);
1721 cnm->peer = n->peer;
1723 memcpy (mats, n->ats,
1724 n->ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information));
1725 mats[n->ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
1726 mats[n->ats_count].value = htonl (0);
1727 send_to_all_clients (&cnm->header, GNUNET_NO,
1728 GNUNET_CORE_OPTION_SEND_CONNECT);
1729 process_encrypted_neighbour_queue (n);
1730 n->last_activity = GNUNET_TIME_absolute_get ();
1732 if (n->status == PEER_STATE_KEY_CONFIRMED)
1734 now = GNUNET_TIME_absolute_get ();
1735 n->last_activity = now;
1736 changed = GNUNET_YES;
1739 GNUNET_STATISTICS_update (stats, gettext_noop ("# established sessions"),
1741 n->time_established = now;
1743 if (n->keep_alive_task != GNUNET_SCHEDULER_NO_TASK)
1744 GNUNET_SCHEDULER_cancel (n->keep_alive_task);
1745 n->keep_alive_task =
1746 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide
1747 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1748 2), &send_keep_alive, n);
1756 * Update information about a session.
1758 * @param peer peer who's session should be updated
1759 * @param bw_out new outbound bandwidth limit for the peer
1760 * @param atsi performance information
1761 * @param atsi_count number of performance records supplied
1764 GSC_SESSIONS_update (const struct GNUNET_PeerIdentity *peer,
1765 struct GNUNET_BANDWIDTH_Value32NBO bw_out,
1766 const struct GNUNET_TRANSPORT_ATS_Information *atsi,
1767 uint32_t atsi_count)
1769 if (bw_out_external_limit.value__ != pt->inbound_bw_limit.value__)
1771 #if DEBUG_CORE_SET_QUOTA
1772 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1773 "Received %u b/s as new inbound limit for peer `%4s'\n",
1774 (unsigned int) ntohl (pt->inbound_bw_limit.value__),
1775 GNUNET_i2s (&n->peer));
1777 n->bw_out_external_limit = pt->inbound_bw_limit;
1779 GNUNET_BANDWIDTH_value_min (n->bw_out_external_limit,
1780 n->bw_out_internal_limit);
1781 GNUNET_BANDWIDTH_tracker_update_quota (&n->available_send_window,
1783 GNUNET_TRANSPORT_set_quota (transport, &n->peer, n->bw_in, n->bw_out);
1790 * Initialize sessions subsystem.
1793 GSC_SESSIONS_init ()
1795 neighbours = GNUNET_CONTAINER_multihashmap_create (128);
1796 self.public_key = &my_public_key;
1797 self.peer = my_identity;
1798 self.last_activity = GNUNET_TIME_UNIT_FOREVER_ABS;
1799 self.status = PEER_STATE_KEY_CONFIRMED;
1800 self.is_connected = GNUNET_YES;
1806 * Shutdown sessions subsystem.
1809 GSC_SESSIONS_done ()
1811 GNUNET_CONTAINER_multihashmap_iterate (neighbours, &free_neighbour_helper,
1813 GNUNET_CONTAINER_multihashmap_destroy (neighbours);
1815 GNUNET_STATISTICS_set (stats, gettext_noop ("# neighbour entries allocated"),