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 * Available bandwidth in for this peer (current target).
105 struct GNUNET_BANDWIDTH_Value32NBO bw_in;
108 * Available bandwidth out for this peer (current target).
110 struct GNUNET_BANDWIDTH_Value32NBO bw_out;
113 * Internal bandwidth limit set for this peer (initially typically
114 * set to "-1"). Actual "bw_out" is MIN of
115 * "bpm_out_internal_limit" and "bw_out_external_limit".
117 struct GNUNET_BANDWIDTH_Value32NBO bw_out_internal_limit;
120 * External bandwidth limit set for this peer by the
121 * peer that we are communicating with. "bw_out" is MIN of
122 * "bw_out_internal_limit" and "bw_out_external_limit".
124 struct GNUNET_BANDWIDTH_Value32NBO bw_out_external_limit;
130 * Map of peer identities to 'struct Session'.
132 static struct GNUNET_CONTAINER_MultiHashMap *sessions;
136 * Session entry for "this" peer.
138 static struct Session self;
141 * Sum of all preferences among all neighbours.
143 static unsigned long long preference_sum;
149 * At what time should the connection to the given neighbour
150 * time out (given no further activity?)
152 * @param n neighbour in question
153 * @return absolute timeout
155 static struct GNUNET_TIME_Absolute
156 get_neighbour_timeout (struct Neighbour *n)
158 return GNUNET_TIME_absolute_add (n->last_activity,
159 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
164 * Helper function for update_preference_sum.
167 update_preference (void *cls, const GNUNET_HashCode * key, void *value)
169 unsigned long long *ps = cls;
170 struct Neighbour *n = value;
172 n->current_preference /= 2;
173 *ps += n->current_preference;
179 * A preference value for a neighbour was update. Update
180 * the preference sum accordingly.
182 * @param inc how much was a preference value increased?
185 update_preference_sum (unsigned long long inc)
187 unsigned long long os;
190 preference_sum += inc;
191 if (preference_sum >= os)
193 /* overflow! compensate by cutting all values in half! */
195 GNUNET_CONTAINER_multihashmap_iterate (neighbours, &update_preference,
197 GNUNET_STATISTICS_set (stats, gettext_noop ("# total peer preference"),
198 preference_sum, GNUNET_NO);
203 * Find the entry for the given neighbour.
205 * @param peer identity of the neighbour
206 * @return NULL if we are not connected, otherwise the
209 static struct Neighbour *
210 find_neighbour (const struct GNUNET_PeerIdentity *peer)
212 return GNUNET_CONTAINER_multihashmap_get (neighbours, &peer->hashPubKey);
217 * Function called by transport telling us that a peer
220 * @param n the peer that changed status
223 handle_peer_status_change (struct Neighbour *n)
225 struct PeerStatusNotifyMessage *psnm;
226 char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1];
227 struct GNUNET_TRANSPORT_ATS_Information *ats;
230 if ((!n->is_connected) || (n->status != PEER_STATE_KEY_CONFIRMED))
233 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%4s' changed status\n",
234 GNUNET_i2s (&n->peer));
237 sizeof (struct PeerStatusNotifyMessage) +
238 n->ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
239 if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
242 /* recovery strategy: throw away performance data */
243 GNUNET_array_grow (n->ats, n->ats_count, 0);
245 sizeof (struct PeerStatusNotifyMessage) +
246 n->ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
248 psnm = (struct PeerStatusNotifyMessage *) buf;
249 psnm->header.size = htons (size);
250 psnm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_STATUS_CHANGE);
251 psnm->timeout = GNUNET_TIME_absolute_hton (get_neighbour_timeout (n));
252 psnm->bandwidth_in = n->bw_in;
253 psnm->bandwidth_out = n->bw_out;
254 psnm->peer = n->peer;
255 psnm->ats_count = htonl (n->ats_count);
258 n->ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information));
259 ats[n->ats_count].type = htonl (0);
260 ats[n->ats_count].value = htonl (0);
261 send_to_all_clients (&psnm->header, GNUNET_YES,
262 GNUNET_CORE_OPTION_SEND_STATUS_CHANGE);
263 GNUNET_STATISTICS_update (stats, gettext_noop ("# peer status changes"), 1,
270 * Go over our message queue and if it is not too long, go
271 * over the pending requests from clients for this
272 * neighbour and send some clients a 'READY' notification.
274 * @param n which peer to process
277 schedule_peer_messages (struct Neighbour *n)
279 struct GSC_ClientActiveRequest *car;
280 struct GSC_ClientActiveRequest *pos;
282 struct MessageEntry *mqe;
283 unsigned int queue_size;
285 /* check if neighbour queue is empty enough! */
295 if (queue_size >= MAX_PEER_QUEUE_SIZE)
297 #if DEBUG_CORE_CLIENT
298 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
299 "Not considering client transmission requests: queue full\n");
301 return; /* queue still full */
303 /* find highest priority request */
304 pos = n->active_client_request_head;
308 if ((car == NULL) || (pos->priority > car->priority))
315 car = n->active_client_request_head;
318 return; /* no pending requests */
319 #if DEBUG_CORE_CLIENT
320 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
321 "Permitting client transmission request to `%s'\n",
322 GNUNET_i2s (&n->peer));
324 GSC_CLIENTS_solicite_request (car);
330 * Free the given entry for the neighbour (it has
331 * already been removed from the list at this point).
333 * @param n neighbour to free
336 free_neighbour (struct Neighbour *n)
338 struct MessageEntry *m;
339 struct GSC_ClientActiveRequest *car;
342 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
343 "Destroying neighbour entry for peer `%4s'\n",
344 GNUNET_i2s (&n->peer));
348 GNUNET_free (n->skm);
351 while (NULL != (m = n->messages))
353 n->messages = m->next;
356 while (NULL != (m = n->encrypted_head))
358 GNUNET_CONTAINER_DLL_remove (n->encrypted_head, n->encrypted_tail, m);
361 while (NULL != (car = n->active_client_request_head))
363 GNUNET_CONTAINER_DLL_remove (n->active_client_request_head,
364 n->active_client_request_tail, car);
365 GNUNET_assert (GNUNET_YES ==
366 GNUNET_CONTAINER_multihashmap_remove (car->client->requests,
373 GNUNET_TRANSPORT_notify_transmit_ready_cancel (n->th);
376 if (n->retry_plaintext_task != GNUNET_SCHEDULER_NO_TASK)
377 GNUNET_SCHEDULER_cancel (n->retry_plaintext_task);
378 if (n->quota_update_task != GNUNET_SCHEDULER_NO_TASK)
379 GNUNET_SCHEDULER_cancel (n->quota_update_task);
380 if (n->dead_clean_task != GNUNET_SCHEDULER_NO_TASK)
381 GNUNET_SCHEDULER_cancel (n->keep_alive_task);
382 if (n->status == PEER_STATE_KEY_CONFIRMED)
383 GNUNET_STATISTICS_update (stats, gettext_noop ("# established sessions"),
385 GNUNET_array_grow (n->ats, n->ats_count, 0);
386 GNUNET_free_non_null (n->pending_ping);
387 GNUNET_free_non_null (n->pending_pong);
394 * Consider freeing the given neighbour since we may not need
395 * to keep it around anymore.
397 * @param n neighbour to consider discarding
400 consider_free_neighbour (struct Neighbour *n);
404 * Task triggered when a neighbour entry might have gotten stale.
406 * @param cls the 'struct Neighbour'
407 * @param tc scheduler context (not used)
410 consider_free_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
412 struct Neighbour *n = cls;
414 n->dead_clean_task = GNUNET_SCHEDULER_NO_TASK;
415 consider_free_neighbour (n);
420 * Consider freeing the given neighbour since we may not need
421 * to keep it around anymore.
423 * @param n neighbour to consider discarding
426 consider_free_neighbour (struct Neighbour *n)
428 struct GNUNET_TIME_Relative left;
430 if ((n->th != NULL) || (n->pitr != NULL) || (GNUNET_YES == n->is_connected))
431 return; /* no chance */
433 left = GNUNET_TIME_absolute_get_remaining (get_neighbour_timeout (n));
434 if (left.rel_value > 0)
436 if (n->dead_clean_task != GNUNET_SCHEDULER_NO_TASK)
437 GNUNET_SCHEDULER_cancel (n->dead_clean_task);
439 GNUNET_SCHEDULER_add_delayed (left, &consider_free_task, n);
442 /* actually free the neighbour... */
443 GNUNET_assert (GNUNET_YES ==
444 GNUNET_CONTAINER_multihashmap_remove (neighbours,
445 &n->peer.hashPubKey, n));
446 GNUNET_STATISTICS_set (stats, gettext_noop ("# neighbour entries allocated"),
447 GNUNET_CONTAINER_multihashmap_size (neighbours),
454 * Function called when the transport service is ready to
455 * receive an encrypted message for the respective peer
457 * @param cls neighbour to use message from
458 * @param size number of bytes we can transmit
459 * @param buf where to copy the message
460 * @return number of bytes transmitted
463 notify_encrypted_transmit_ready (void *cls, size_t size, void *buf)
465 struct Neighbour *n = cls;
466 struct MessageEntry *m;
471 m = n->encrypted_head;
475 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
476 "Encrypted message queue empty, no messages added to buffer for `%4s'\n",
477 GNUNET_i2s (&n->peer));
481 GNUNET_CONTAINER_DLL_remove (n->encrypted_head, n->encrypted_tail, m);
486 GNUNET_assert (size >= m->size);
487 memcpy (cbuf, &m[1], m->size);
489 GNUNET_BANDWIDTH_tracker_consume (&n->available_send_window, m->size);
491 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
492 "Copied message of type %u and size %u into transport buffer for `%4s'\n",
494 ntohs (((struct GNUNET_MessageHeader *) &m[1])->type),
495 (unsigned int) ret, GNUNET_i2s (&n->peer));
497 process_encrypted_neighbour_queue (n);
502 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
503 "Transmission of message of type %u and size %u failed\n",
505 ntohs (((struct GNUNET_MessageHeader *) &m[1])->type),
506 (unsigned int) m->size);
510 consider_free_neighbour (n);
511 GNUNET_STATISTICS_update (stats,
513 ("# encrypted bytes given to transport"), ret,
523 * Select messages for transmission. This heuristic uses a combination
524 * of earliest deadline first (EDF) scheduling (with bounded horizon)
525 * and priority-based discard (in case no feasible schedule exist) and
526 * speculative optimization (defer any kind of transmission until
527 * we either create a batch of significant size, 25% of max, or until
528 * we are close to a deadline). Furthermore, when scheduling the
529 * heuristic also packs as many messages into the batch as possible,
530 * starting with those with the earliest deadline. Yes, this is fun.
532 * @param n neighbour to select messages from
533 * @param size number of bytes to select for transmission
534 * @param retry_time set to the time when we should try again
535 * (only valid if this function returns zero)
536 * @return number of bytes selected, or 0 if we decided to
537 * defer scheduling overall; in that case, retry_time is set.
540 select_messages (struct Neighbour *n, size_t size,
541 struct GNUNET_TIME_Relative *retry_time)
543 struct MessageEntry *pos;
544 struct MessageEntry *min;
545 struct MessageEntry *last;
546 unsigned int min_prio;
547 struct GNUNET_TIME_Absolute t;
548 struct GNUNET_TIME_Absolute now;
549 struct GNUNET_TIME_Relative delta;
551 struct GNUNET_TIME_Relative slack; /* how long could we wait before missing deadlines? */
554 unsigned int queue_size;
555 int discard_low_prio;
557 GNUNET_assert (NULL != n->messages);
558 now = GNUNET_TIME_absolute_get ();
559 /* last entry in linked list of messages processed */
561 /* should we remove the entry with the lowest
562 * priority from consideration for scheduling at the
563 * end of the loop? */
573 discard_low_prio = GNUNET_YES;
574 while (GNUNET_YES == discard_low_prio)
578 discard_low_prio = GNUNET_NO;
579 /* calculate number of bytes available for transmission at time "t" */
580 avail = GNUNET_BANDWIDTH_tracker_get_available (&n->available_send_window);
582 /* how many bytes have we (hypothetically) scheduled so far */
584 /* maximum time we can wait before transmitting anything
585 * and still make all of our deadlines */
586 slack = GNUNET_TIME_UNIT_FOREVER_REL;
588 /* note that we use "*2" here because we want to look
589 * a bit further into the future; much more makes no
590 * sense since new message might be scheduled in the
592 while ((pos != NULL) && (off < size * 2))
594 if (pos->do_transmit == GNUNET_YES)
596 /* already removed from consideration */
600 if (discard_low_prio == GNUNET_NO)
602 delta = GNUNET_TIME_absolute_get_difference (t, pos->deadline);
603 if (delta.rel_value > 0)
605 // FIXME: HUH? Check!
608 GNUNET_BANDWIDTH_value_get_available_until (n->bw_out, delta);
610 if (avail < pos->size)
612 // FIXME: HUH? Check!
613 discard_low_prio = GNUNET_YES; /* we could not schedule this one! */
618 /* update slack, considering both its absolute deadline
619 * and relative deadlines caused by other messages
620 * with their respective load */
622 GNUNET_TIME_relative_min (slack,
623 GNUNET_BANDWIDTH_value_get_delay_for
625 if (pos->deadline.abs_value <= now.abs_value)
628 slack = GNUNET_TIME_UNIT_ZERO;
630 else if (GNUNET_YES == pos->got_slack)
632 /* should be soon now! */
634 GNUNET_TIME_relative_min (slack,
635 GNUNET_TIME_absolute_get_remaining
636 (pos->slack_deadline));
641 GNUNET_TIME_relative_min (slack,
642 GNUNET_TIME_absolute_get_difference
643 (now, pos->deadline));
644 pos->got_slack = GNUNET_YES;
645 pos->slack_deadline =
646 GNUNET_TIME_absolute_min (pos->deadline,
647 GNUNET_TIME_relative_to_absolute
648 (GNUNET_CONSTANTS_MAX_CORK_DELAY));
653 t = GNUNET_TIME_absolute_max (pos->deadline, t); // HUH? Check!
654 if (pos->priority <= min_prio)
656 /* update min for discard */
657 min_prio = pos->priority;
662 if (discard_low_prio)
664 GNUNET_assert (min != NULL);
665 /* remove lowest-priority entry from consideration */
666 min->do_transmit = GNUNET_YES; /* means: discard (for now) */
670 /* guard against sending "tiny" messages with large headers without
671 * urgent deadlines */
672 if ((slack.rel_value > GNUNET_CONSTANTS_MAX_CORK_DELAY.rel_value) &&
673 (size > 4 * off) && (queue_size <= MAX_PEER_QUEUE_SIZE - 2))
675 /* less than 25% of message would be filled with deadlines still
676 * being met if we delay by one second or more; so just wait for
677 * more data; but do not wait longer than 1s (since we don't want
678 * to delay messages for a really long time either). */
679 *retry_time = GNUNET_CONSTANTS_MAX_CORK_DELAY;
680 /* reset do_transmit values for next time */
683 pos->do_transmit = GNUNET_NO;
686 GNUNET_STATISTICS_update (stats,
688 ("# transmissions delayed due to corking"), 1,
691 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
692 "Deferring transmission for %llums due to underfull message buffer size (%u/%u)\n",
693 (unsigned long long) retry_time->rel_value, (unsigned int) off,
694 (unsigned int) size);
698 /* select marked messages (up to size) for transmission */
703 if ((pos->size <= size) && (pos->do_transmit == GNUNET_NO))
705 pos->do_transmit = GNUNET_YES; /* mark for transmission */
709 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
710 "Selecting message of size %u for transmission\n",
711 (unsigned int) pos->size);
717 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
718 "Not selecting message of size %u for transmission at this time (maximum is %u)\n",
719 (unsigned int) pos->size, size);
721 pos->do_transmit = GNUNET_NO; /* mark for not transmitting! */
726 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
727 "Selected %llu/%llu bytes of %u/%u plaintext messages for transmission to `%4s'.\n",
728 (unsigned long long) off, (unsigned long long) tsize, queue_size,
729 (unsigned int) MAX_PEER_QUEUE_SIZE, GNUNET_i2s (&n->peer));
736 * Batch multiple messages into a larger buffer.
738 * @param n neighbour to take messages from
739 * @param buf target buffer
740 * @param size size of buf
741 * @param deadline set to transmission deadline for the result
742 * @param retry_time set to the time when we should try again
743 * (only valid if this function returns zero)
744 * @param priority set to the priority of the batch
745 * @return number of bytes written to buf (can be zero)
748 batch_message (struct Neighbour *n, char *buf, size_t size,
749 struct GNUNET_TIME_Absolute *deadline,
750 struct GNUNET_TIME_Relative *retry_time, unsigned int *priority)
752 char ntmb[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1];
753 struct NotifyTrafficMessage *ntm = (struct NotifyTrafficMessage *) ntmb;
754 struct MessageEntry *pos;
755 struct MessageEntry *prev;
756 struct MessageEntry *next;
761 *deadline = GNUNET_TIME_UNIT_FOREVER_ABS;
762 *retry_time = GNUNET_TIME_UNIT_FOREVER_REL;
763 if (0 == select_messages (n, size, retry_time))
766 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
767 "No messages selected, will try again in %llu ms\n",
768 retry_time->rel_value);
772 ntm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_OUTBOUND);
773 ntm->ats_count = htonl (0);
774 ntm->ats.type = htonl (0);
775 ntm->ats.value = htonl (0);
779 while ((pos != NULL) && (size >= sizeof (struct GNUNET_MessageHeader)))
782 if (GNUNET_YES == pos->do_transmit)
784 GNUNET_assert (pos->size <= size);
785 /* do notifications */
786 /* FIXME: track if we have *any* client that wants
787 * full notifications and only do this if that is
790 GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct NotifyTrafficMessage))
792 memcpy (&ntm[1], &pos[1], pos->size);
794 htons (sizeof (struct NotifyTrafficMessage) +
795 sizeof (struct GNUNET_MessageHeader));
796 send_to_all_clients (&ntm->header, GNUNET_YES,
797 GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND);
801 /* message too large for 'full' notifications, we do at
802 * least the 'hdr' type */
803 memcpy (&ntm[1], &pos[1], sizeof (struct GNUNET_MessageHeader));
806 htons (sizeof (struct NotifyTrafficMessage) + pos->size);
807 send_to_all_clients (&ntm->header, GNUNET_YES,
808 GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND);
810 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
811 "Encrypting %u bytes with message of type %u and size %u\n",
814 ntohs (((const struct GNUNET_MessageHeader *) &pos[1])->type),
816 ntohs (((const struct GNUNET_MessageHeader *)
819 /* copy for encrypted transmission */
820 memcpy (&buf[ret], &pos[1], pos->size);
823 *priority += pos->priority;
825 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
826 "Adding plaintext message of size %u with deadline %llu ms to batch\n",
827 (unsigned int) pos->size,
829 GNUNET_TIME_absolute_get_remaining (pos->deadline).rel_value);
831 deadline->abs_value =
832 GNUNET_MIN (deadline->abs_value, pos->deadline.abs_value);
846 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
847 "Deadline for message batch is %llu ms\n",
848 GNUNET_TIME_absolute_get_remaining (*deadline).rel_value);
855 * Remove messages with deadlines that have long expired from
858 * @param n neighbour to inspect
861 discard_expired_messages (struct Neighbour *n)
863 struct MessageEntry *prev;
864 struct MessageEntry *next;
865 struct MessageEntry *pos;
866 struct GNUNET_TIME_Absolute now;
867 struct GNUNET_TIME_Relative delta;
869 unsigned int queue_length;
872 now = GNUNET_TIME_absolute_get ();
880 delta = GNUNET_TIME_absolute_get_difference (pos->deadline, now);
881 if (delta.rel_value > PAST_EXPIRATION_DISCARD_TIME.rel_value)
884 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
885 "Message is %llu ms past due, discarding.\n",
892 GNUNET_STATISTICS_update (stats,
894 ("# messages discarded (expired prior to transmission)"),
903 if ( (GNUNET_YES == disc) &&
904 (queue_length == MAX_PEER_QUEUE_SIZE) )
905 schedule_peer_messages (n);
910 * Signature of the main function of a task.
913 * @param tc context information (why was this task triggered now)
916 retry_plaintext_processing (void *cls,
917 const struct GNUNET_SCHEDULER_TaskContext *tc)
919 struct Neighbour *n = cls;
921 n->retry_plaintext_task = GNUNET_SCHEDULER_NO_TASK;
922 process_plaintext_neighbour_queue (n);
927 * Check if we have plaintext messages for the specified neighbour
928 * pending, and if so, consider batching and encrypting them (and
929 * then trigger processing of the encrypted queue if needed).
931 * @param n neighbour to check.
934 process_plaintext_neighbour_queue (struct Neighbour *n)
936 char pbuf[GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE + sizeof (struct EncryptedMessage)]; /* plaintext */
938 struct EncryptedMessage *em; /* encrypted message */
939 struct EncryptedMessage *ph; /* plaintext header */
940 struct MessageEntry *me;
941 unsigned int priority;
942 struct GNUNET_TIME_Absolute deadline;
943 struct GNUNET_TIME_Relative retry_time;
944 struct GNUNET_CRYPTO_AesInitializationVector iv;
945 struct GNUNET_CRYPTO_AuthKey auth_key;
947 if (n->retry_plaintext_task != GNUNET_SCHEDULER_NO_TASK)
949 GNUNET_SCHEDULER_cancel (n->retry_plaintext_task);
950 n->retry_plaintext_task = GNUNET_SCHEDULER_NO_TASK;
954 case PEER_STATE_DOWN:
957 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
958 "Not yet connected to `%4s', deferring processing of plaintext messages.\n",
959 GNUNET_i2s (&n->peer));
962 case PEER_STATE_KEY_SENT:
963 if (n->retry_set_key_task == GNUNET_SCHEDULER_NO_TASK)
964 n->retry_set_key_task =
965 GNUNET_SCHEDULER_add_delayed (n->set_key_retry_frequency,
966 &set_key_retry_task, n);
968 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
969 "Not yet connected to `%4s', deferring processing of plaintext messages.\n",
970 GNUNET_i2s (&n->peer));
973 case PEER_STATE_KEY_RECEIVED:
974 if (n->retry_set_key_task == GNUNET_SCHEDULER_NO_TASK)
975 n->retry_set_key_task =
976 GNUNET_SCHEDULER_add_delayed (n->set_key_retry_frequency,
977 &set_key_retry_task, n);
979 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
980 "Not yet connected to `%4s', deferring processing of plaintext messages.\n",
981 GNUNET_i2s (&n->peer));
984 case PEER_STATE_KEY_CONFIRMED:
985 /* ready to continue */
988 discard_expired_messages (n);
989 if (n->messages == NULL)
992 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
993 "Plaintext message queue for `%4s' is empty.\n",
994 GNUNET_i2s (&n->peer));
996 return; /* no pending messages */
998 if (n->encrypted_head != NULL)
1001 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1002 "Encrypted message queue for `%4s' is still full, delaying plaintext processing.\n",
1003 GNUNET_i2s (&n->peer));
1005 return; /* wait for messages already encrypted to be
1006 * processed first! */
1008 ph = (struct EncryptedMessage *) pbuf;
1009 deadline = GNUNET_TIME_UNIT_FOREVER_ABS;
1011 used = sizeof (struct EncryptedMessage);
1013 batch_message (n, &pbuf[used],
1014 GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE, &deadline,
1015 &retry_time, &priority);
1016 if (used == sizeof (struct EncryptedMessage))
1019 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1020 "No messages selected for transmission to `%4s' at this time, will try again later.\n",
1021 GNUNET_i2s (&n->peer));
1023 /* no messages selected for sending, try again later... */
1024 n->retry_plaintext_task =
1025 GNUNET_SCHEDULER_add_delayed (retry_time, &retry_plaintext_processing,
1029 GSC_KX_encrypt_and_transmit (n->kx,
1030 &pbuf[struct EncryptedMessage],
1031 used - sizeof (struct EncryptedMessage));
1032 schedule_peer_messages (n);
1039 * Check if we have encrypted messages for the specified neighbour
1040 * pending, and if so, check with the transport about sending them
1043 * @param n neighbour to check.
1046 process_encrypted_neighbour_queue (struct Neighbour *n)
1048 struct MessageEntry *m;
1051 return; /* request already pending */
1052 if (GNUNET_YES != n->is_connected)
1057 m = n->encrypted_head;
1060 /* encrypted queue empty, try plaintext instead */
1061 process_plaintext_neighbour_queue (n);
1065 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1066 "Asking transport for transmission of %u bytes to `%4s' in next %llu ms\n",
1067 (unsigned int) m->size, GNUNET_i2s (&n->peer),
1068 (unsigned long long)
1069 GNUNET_TIME_absolute_get_remaining (m->deadline).rel_value);
1072 GNUNET_TRANSPORT_notify_transmit_ready (transport, &n->peer, m->size,
1074 GNUNET_TIME_absolute_get_remaining
1076 ¬ify_encrypted_transmit_ready,
1080 /* message request too large or duplicate request */
1082 /* discard encrypted message */
1083 GNUNET_CONTAINER_DLL_remove (n->encrypted_head, n->encrypted_tail, m);
1085 process_encrypted_neighbour_queue (n);
1091 * Initialize a new 'struct Neighbour'.
1093 * @param pid ID of the new neighbour
1094 * @return handle for the new neighbour
1096 static struct Neighbour *
1097 create_neighbour (const struct GNUNET_PeerIdentity *pid)
1099 struct Neighbour *n;
1100 struct GNUNET_TIME_Absolute now;
1103 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1104 "Creating neighbour entry for peer `%4s'\n", GNUNET_i2s (pid));
1106 n = GNUNET_malloc (sizeof (struct Neighbour));
1108 n->last_activity = GNUNET_TIME_absolute_get ();
1109 n->bw_in = GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT;
1110 n->bw_out = GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT;
1111 n->bw_out_internal_limit = GNUNET_BANDWIDTH_value_init (UINT32_MAX);
1112 n->bw_out_external_limit = GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT;
1114 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX);
1115 GNUNET_assert (GNUNET_OK ==
1116 GNUNET_CONTAINER_multihashmap_put (neighbours,
1117 &n->peer.hashPubKey, n,
1118 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1119 GNUNET_STATISTICS_set (stats, gettext_noop ("# neighbour entries allocated"),
1120 GNUNET_CONTAINER_multihashmap_size (neighbours),
1122 neighbour_quota_update (n, NULL);
1123 consider_free_neighbour (n);
1130 * We have a new client, notify it about all current sessions.
1132 * @param client the new client
1135 GSC_SESSIONS_notify_client_about_sessions (struct GSC_Client *client)
1137 /* notify new client about existing neighbours */
1138 GNUNET_CONTAINER_multihashmap_iterate (neighbours,
1139 ¬ify_client_about_neighbour, client);
1144 * Queue a request from a client for transmission to a particular peer.
1146 * @param car request to queue; this handle is then shared between
1147 * the caller (CLIENTS subsystem) and SESSIONS and must not
1148 * be released by either until either 'GNUNET_SESSIONS_dequeue',
1149 * 'GNUNET_SESSIONS_transmit' or 'GNUNET_CLIENTS_failed'
1150 * have been invoked on it
1153 GSC_SESSIONS_queue_request (struct GSC_ClientActiveRequest *car)
1155 struct Neighbour *n; // FIXME: session...
1157 n = find_neighbour (&car->peer);
1158 if ((n == NULL) || (GNUNET_YES != n->is_connected) ||
1159 (n->status != PEER_STATE_KEY_CONFIRMED))
1161 /* neighbour must have disconnected since request was issued,
1162 * ignore (client will realize it once it processes the
1163 * disconnect notification) */
1164 #if DEBUG_CORE_CLIENT
1165 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1166 "Dropped client request for transmission (am disconnected)\n");
1168 GNUNET_STATISTICS_update (stats,
1170 ("# send requests dropped (disconnected)"), 1,
1172 GSC_CLIENTS_reject_requests (car);
1175 #if DEBUG_CORE_CLIENT
1176 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1177 "Received client transmission request. queueing\n");
1179 GNUNET_CONTAINER_DLL_insert (n->active_client_request_head,
1180 n->active_client_request_tail, car);
1182 // schedule_peer_messages (n);
1187 * Dequeue a request from a client from transmission to a particular peer.
1189 * @param car request to dequeue; this handle will then be 'owned' by
1190 * the caller (CLIENTS sysbsystem)
1193 GSC_SESSIONS_dequeue_request (struct GSC_ClientActiveRequest *car)
1197 s = find_session (&car->peer);
1198 GNUNET_CONTAINER_DLL_remove (s->active_client_request_head,
1199 s->active_client_request_tail, car);
1205 * Transmit a message to a particular peer.
1207 * @param car original request that was queued and then solicited;
1208 * this handle will now be 'owned' by the SESSIONS subsystem
1209 * @param msg message to transmit
1212 GSC_SESSIONS_transmit (struct GSC_ClientActiveRequest *car,
1213 const struct GNUNET_MessageHeader *msg)
1215 struct MessageEntry *prev;
1216 struct MessageEntry *pos;
1217 struct MessageEntry *e;
1218 struct MessageEntry *min_prio_entry;
1219 struct MessageEntry *min_prio_prev;
1220 unsigned int min_prio;
1221 unsigned int queue_size;
1223 n = find_neighbour (&sm->peer);
1224 if ((n == NULL) || (GNUNET_YES != n->is_connected) ||
1225 (n->status != PEER_STATE_KEY_CONFIRMED))
1227 /* attempt to send message to peer that is not connected anymore
1228 * (can happen due to asynchrony) */
1229 GNUNET_STATISTICS_update (stats,
1231 ("# messages discarded (disconnected)"), 1,
1234 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1238 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1239 "Core received `%s' request, queueing %u bytes of plaintext data for transmission to `%4s'.\n",
1240 "SEND", (unsigned int) msize, GNUNET_i2s (&sm->peer));
1242 discard_expired_messages (n);
1243 /* bound queue size */
1244 /* NOTE: this entire block to bound the queue size should be
1245 * obsolete with the new client-request code and the
1246 * 'schedule_peer_messages' mechanism; we still have this code in
1247 * here for now as a sanity check for the new mechanmism;
1248 * ultimately, we should probably simply reject SEND messages that
1249 * are not 'approved' (or provide a new core API for very unreliable
1250 * delivery that always sends with priority 0). Food for thought. */
1251 min_prio = UINT32_MAX;
1252 min_prio_entry = NULL;
1253 min_prio_prev = NULL;
1259 if (pos->priority <= min_prio)
1261 min_prio_entry = pos;
1262 min_prio_prev = prev;
1263 min_prio = pos->priority;
1269 if (queue_size >= MAX_PEER_QUEUE_SIZE)
1272 if (ntohl (sm->priority) <= min_prio)
1274 /* discard new entry; this should no longer happen! */
1277 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1278 "Queue full (%u/%u), discarding new request (%u bytes of type %u)\n",
1279 queue_size, (unsigned int) MAX_PEER_QUEUE_SIZE,
1280 (unsigned int) msize, (unsigned int) ntohs (message->type));
1282 GNUNET_STATISTICS_update (stats,
1283 gettext_noop ("# discarded CORE_SEND requests"),
1287 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1290 GNUNET_assert (min_prio_entry != NULL);
1291 /* discard "min_prio_entry" */
1293 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1294 "Queue full, discarding existing older request\n");
1296 GNUNET_STATISTICS_update (stats,
1298 ("# discarded lower priority CORE_SEND requests"),
1300 if (min_prio_prev == NULL)
1301 n->messages = min_prio_entry->next;
1303 min_prio_prev->next = min_prio_entry->next;
1304 GNUNET_free (min_prio_entry);
1308 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1309 "Adding transmission request for `%4s' of size %u to queue\n",
1310 GNUNET_i2s (&sm->peer), (unsigned int) msize);
1312 e = GNUNET_malloc (sizeof (struct MessageEntry) + msize);
1313 e->deadline = GNUNET_TIME_absolute_ntoh (sm->deadline);
1314 e->priority = ntohl (sm->priority);
1316 if (GNUNET_YES != (int) ntohl (sm->cork))
1317 e->got_slack = GNUNET_YES;
1318 memcpy (&e[1], &sm[1], msize);
1320 /* insert, keep list sorted by deadline */
1323 while ((pos != NULL) && (pos->deadline.abs_value < e->deadline.abs_value))
1334 /* consider scheduling now */
1335 process_plaintext_neighbour_queue (n);
1342 * Send a message to the neighbour.
1344 * @param cls the message
1345 * @param key neighbour's identity
1346 * @param value 'struct Neighbour' of the target
1347 * @return always GNUNET_OK
1350 do_send_message (void *cls, const GNUNET_HashCode * key, void *value)
1352 struct GNUNET_MessageHeader *hdr = cls;
1353 struct Neighbour *n = value;
1354 struct MessageEntry *m;
1357 size = ntohs (hdr->size);
1358 m = GNUNET_malloc (sizeof (struct MessageEntry) + size);
1359 memcpy (&m[1], hdr, size);
1360 m->deadline = GNUNET_TIME_UNIT_FOREVER_ABS;
1361 m->slack_deadline = GNUNET_TIME_UNIT_FOREVER_ABS;
1362 m->priority = UINT_MAX;
1363 m->sender_status = n->status;
1365 GNUNET_CONTAINER_DLL_insert (n->message_head,
1373 * Broadcast a message to all neighbours.
1375 * @param msg message to transmit
1378 GSC_SESSIONS_broadcast (const struct GNUNET_MessageHeader *msg)
1380 if (NULL == sessions)
1382 GNUNET_CONTAINER_multihashmap_iterate (sessions,
1383 &do_send_message, msg);
1388 * Helper function for GSC_SESSIONS_handle_client_iterate_peers.
1390 * @param cls the 'struct GNUNET_SERVER_TransmitContext' to queue replies
1391 * @param key identity of the connected peer
1392 * @param value the 'struct Neighbour' for the peer
1393 * @return GNUNET_OK (continue to iterate)
1396 queue_connect_message (void *cls, const GNUNET_HashCode * key, void *value)
1398 struct GNUNET_SERVER_TransmitContext *tc = cls;
1399 struct Neighbour *n = value;
1400 char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1];
1401 struct GNUNET_TRANSPORT_ATS_Information *ats;
1403 struct ConnectNotifyMessage *cnm;
1405 cnm = (struct ConnectNotifyMessage *) buf;
1406 if (n->status != PEER_STATE_KEY_CONFIRMED)
1409 sizeof (struct ConnectNotifyMessage) +
1410 (n->ats_count) * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
1411 if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1414 /* recovery strategy: throw away performance data */
1415 GNUNET_array_grow (n->ats, n->ats_count, 0);
1417 sizeof (struct PeerStatusNotifyMessage) +
1418 n->ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
1420 cnm = (struct ConnectNotifyMessage *) buf;
1421 cnm->header.size = htons (size);
1422 cnm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT);
1423 cnm->ats_count = htonl (n->ats_count);
1425 memcpy (ats, n->ats,
1426 n->ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information));
1427 ats[n->ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
1428 ats[n->ats_count].value = htonl (0);
1429 #if DEBUG_CORE_CLIENT
1430 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message to client.\n",
1433 cnm->peer = n->peer;
1434 GNUNET_SERVER_transmit_context_append_message (tc, &cnm->header);
1440 * End the session with the given peer (we are no longer
1443 * @param pid identity of peer to kill session with
1446 GSC_SESSIONS_end (const struct GNUNET_PeerIdentity *pid)
1452 * Traffic is being solicited for the given peer. This means that the
1453 * message queue on the transport-level (NEIGHBOURS subsystem) is now
1454 * empty and it is now OK to transmit another (non-control) message.
1456 * @param pid identity of peer ready to receive data
1459 GSC_SESSIONS_solicit (const struct GNUNET_PeerIdentity *pid)
1465 * Transmit a message to a particular peer.
1467 * @param car original request that was queued and then solicited,
1468 * ownership does not change (dequeue will be called soon).
1469 * @param msg message to transmit
1472 GSC_SESSIONS_transmit (struct GSC_ClientActiveRequest *car,
1473 const struct GNUNET_MessageHeader *msg)
1479 * We have a new client, notify it about all current sessions.
1481 * @param client the new client
1484 GSC_SESSIONS_notify_client_about_sessions (struct GSC_Client *client)
1490 * Handle CORE_ITERATE_PEERS request. For this request type, the client
1491 * does not have to have transmitted an INIT request. All current peers
1492 * are returned, regardless of which message types they accept.
1495 * @param client client sending the iteration request
1496 * @param message iteration request message
1499 GSC_SESSIONS_handle_client_iterate_peers (void *cls, struct GNUNET_SERVER_Client *client,
1500 const struct GNUNET_MessageHeader *message)
1502 struct GNUNET_MessageHeader done_msg;
1503 struct GNUNET_SERVER_TransmitContext *tc;
1505 tc = GNUNET_SERVER_transmit_context_create (client);
1506 GNUNET_CONTAINER_multihashmap_iterate (neighbours, &queue_connect_message,
1508 done_msg.size = htons (sizeof (struct GNUNET_MessageHeader));
1509 done_msg.type = htons (GNUNET_MESSAGE_TYPE_CORE_ITERATE_PEERS_END);
1510 GNUNET_SERVER_transmit_context_append_message (tc, &done_msg);
1511 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
1516 * Handle CORE_PEER_CONNECTED request. Notify client about connection
1517 * to the given neighbour. For this request type, the client does not
1518 * have to have transmitted an INIT request. All current peers are
1519 * returned, regardless of which message types they accept.
1522 * @param client client sending the iteration request
1523 * @param message iteration request message
1526 GSC_SESSIONS_handle_client_have_peer (void *cls, struct GNUNET_SERVER_Client *client,
1527 const struct GNUNET_MessageHeader *message)
1529 struct GNUNET_MessageHeader done_msg;
1530 struct GNUNET_SERVER_TransmitContext *tc;
1531 const struct GNUNET_PeerIdentity *peer;
1533 peer = (const struct GNUNET_PeerIdentity *) &message[1]; // YUCK!
1534 tc = GNUNET_SERVER_transmit_context_create (client);
1535 GNUNET_CONTAINER_multihashmap_get_multiple (neighbours, &peer->hashPubKey,
1536 &queue_connect_message, tc);
1537 done_msg.size = htons (sizeof (struct GNUNET_MessageHeader));
1538 done_msg.type = htons (GNUNET_MESSAGE_TYPE_CORE_ITERATE_PEERS_END);
1539 GNUNET_SERVER_transmit_context_append_message (tc, &done_msg);
1540 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
1546 * Handle REQUEST_INFO request. For this request type, the client must
1547 * have transmitted an INIT first.
1550 * @param client client sending the request
1551 * @param message iteration request message
1554 GSC_SESSIONS_handle_client_request_info (void *cls, struct GNUNET_SERVER_Client *client,
1555 const struct GNUNET_MessageHeader *message)
1557 const struct RequestInfoMessage *rcm;
1558 struct GSC_Client *pos;
1559 struct Neighbour *n;
1560 struct ConfigurationInfoMessage cim;
1561 int32_t want_reserv;
1563 unsigned long long old_preference;
1564 struct GNUNET_TIME_Relative rdelay;
1566 rdelay = GNUNET_TIME_relative_get_zero ();
1567 #if DEBUG_CORE_CLIENT
1568 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Core service receives `%s' request.\n",
1571 rcm = (const struct RequestInfoMessage *) message;
1572 n = find_neighbour (&rcm->peer);
1573 memset (&cim, 0, sizeof (cim));
1574 if ((n != NULL) && (GNUNET_YES == n->is_connected))
1576 want_reserv = ntohl (rcm->reserve_inbound);
1577 if (n->bw_out_internal_limit.value__ != rcm->limit_outbound.value__)
1579 n->bw_out_internal_limit = rcm->limit_outbound;
1580 if (n->bw_out.value__ !=
1581 GNUNET_BANDWIDTH_value_min (n->bw_out_internal_limit,
1582 n->bw_out_external_limit).value__)
1585 GNUNET_BANDWIDTH_value_min (n->bw_out_internal_limit,
1586 n->bw_out_external_limit);
1587 GNUNET_BANDWIDTH_tracker_update_quota (&n->available_recv_window,
1589 GNUNET_TRANSPORT_set_quota (transport, &n->peer, n->bw_in, n->bw_out);
1590 handle_peer_status_change (n);
1593 if (want_reserv < 0)
1595 got_reserv = want_reserv;
1597 else if (want_reserv > 0)
1600 GNUNET_BANDWIDTH_tracker_get_delay (&n->available_recv_window,
1602 if (rdelay.rel_value == 0)
1603 got_reserv = want_reserv;
1605 got_reserv = 0; /* all or nothing */
1609 GNUNET_BANDWIDTH_tracker_consume (&n->available_recv_window, got_reserv);
1610 old_preference = n->current_preference;
1611 n->current_preference += GNUNET_ntohll (rcm->preference_change);
1612 if (old_preference > n->current_preference)
1614 /* overflow; cap at maximum value */
1615 n->current_preference = ULLONG_MAX;
1617 update_preference_sum (n->current_preference - old_preference);
1618 #if DEBUG_CORE_QUOTA
1619 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1620 "Received reservation request for %d bytes for peer `%4s', reserved %d bytes, suggesting delay of %llu ms\n",
1621 (int) want_reserv, GNUNET_i2s (&rcm->peer), (int) got_reserv,
1622 (unsigned long long) rdelay.rel_value);
1624 cim.reserved_amount = htonl (got_reserv);
1625 cim.reserve_delay = GNUNET_TIME_relative_hton (rdelay);
1626 cim.bw_out = n->bw_out;
1627 cim.preference = n->current_preference;
1631 /* Technically, this COULD happen (due to asynchronous behavior),
1632 * but it should be rare, so we should generate an info event
1633 * to help diagnosis of serious errors that might be masked by this */
1634 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1636 ("Client asked for preference change with peer `%s', which is not connected!\n"),
1637 GNUNET_i2s (&rcm->peer));
1638 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1641 cim.header.size = htons (sizeof (struct ConfigurationInfoMessage));
1642 cim.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_CONFIGURATION_INFO);
1643 cim.peer = rcm->peer;
1644 cim.rim_id = rcm->rim_id;
1645 #if DEBUG_CORE_CLIENT
1646 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message to client.\n",
1647 "CONFIGURATION_INFO");
1649 GSC_CLIENTS_send_to_client (client, &cim.header, GNUNET_NO);
1650 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1655 * Create a session, a key exchange was just completed.
1657 * @param peer peer that is now connected
1658 * @param kx key exchange that completed
1661 GSC_SESSIONS_create (const struct GNUNET_PeerIdentity *peer,
1662 struct GSC_KeyExchangeInfo *kx)
1665 struct GNUNET_MessageHeader *hdr;
1667 hdr = compute_type_map_message ();
1668 send_type_map_to_neighbour (hdr, &n->peer.hashPubKey, n);
1671 if (n->bw_out_external_limit.value__ != t.inbound_bw_limit.value__)
1673 n->bw_out_external_limit = t.inbound_bw_limit;
1675 GNUNET_BANDWIDTH_value_min (n->bw_out_external_limit,
1676 n->bw_out_internal_limit);
1677 GNUNET_BANDWIDTH_tracker_update_quota (&n->available_send_window,
1679 GNUNET_TRANSPORT_set_quota (transport, &n->peer, n->bw_in, n->bw_out);
1682 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1683 "Confirmed key via `%s' message for peer `%4s'\n", "PONG",
1684 GNUNET_i2s (&n->peer));
1689 sizeof (struct ConnectNotifyMessage) +
1690 (n->ats_count) * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
1691 if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1694 /* recovery strategy: throw away performance data */
1695 GNUNET_array_grow (n->ats, n->ats_count, 0);
1697 sizeof (struct PeerStatusNotifyMessage) +
1698 n->ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
1700 cnm = (struct ConnectNotifyMessage *) buf;
1701 cnm->header.size = htons (size);
1702 cnm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT);
1703 cnm->ats_count = htonl (n->ats_count);
1704 cnm->peer = n->peer;
1706 memcpy (mats, n->ats,
1707 n->ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information));
1708 mats[n->ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
1709 mats[n->ats_count].value = htonl (0);
1710 send_to_all_clients (&cnm->header, GNUNET_NO,
1711 GNUNET_CORE_OPTION_SEND_CONNECT);
1712 process_encrypted_neighbour_queue (n);
1713 n->last_activity = GNUNET_TIME_absolute_get ();
1715 if (n->status == PEER_STATE_KEY_CONFIRMED)
1717 now = GNUNET_TIME_absolute_get ();
1718 n->last_activity = now;
1719 changed = GNUNET_YES;
1722 GNUNET_STATISTICS_update (stats, gettext_noop ("# established sessions"),
1724 n->time_established = now;
1726 if (n->keep_alive_task != GNUNET_SCHEDULER_NO_TASK)
1727 GNUNET_SCHEDULER_cancel (n->keep_alive_task);
1728 n->keep_alive_task =
1729 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide
1730 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1731 2), &send_keep_alive, n);
1739 * Update information about a session.
1741 * @param peer peer who's session should be updated
1742 * @param bw_out new outbound bandwidth limit for the peer
1743 * @param atsi performance information
1744 * @param atsi_count number of performance records supplied
1747 GSC_SESSIONS_update (const struct GNUNET_PeerIdentity *peer,
1748 struct GNUNET_BANDWIDTH_Value32NBO bw_out,
1749 const struct GNUNET_TRANSPORT_ATS_Information *atsi,
1750 uint32_t atsi_count)
1752 if (bw_out_external_limit.value__ != pt->inbound_bw_limit.value__)
1754 #if DEBUG_CORE_SET_QUOTA
1755 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1756 "Received %u b/s as new inbound limit for peer `%4s'\n",
1757 (unsigned int) ntohl (pt->inbound_bw_limit.value__),
1758 GNUNET_i2s (&n->peer));
1760 n->bw_out_external_limit = pt->inbound_bw_limit;
1762 GNUNET_BANDWIDTH_value_min (n->bw_out_external_limit,
1763 n->bw_out_internal_limit);
1764 GNUNET_BANDWIDTH_tracker_update_quota (&n->available_send_window,
1766 GNUNET_TRANSPORT_set_quota (transport, &n->peer, n->bw_in, n->bw_out);
1773 * Initialize sessions subsystem.
1776 GSC_SESSIONS_init ()
1778 neighbours = GNUNET_CONTAINER_multihashmap_create (128);
1779 self.public_key = &my_public_key;
1780 self.peer = my_identity;
1781 self.last_activity = GNUNET_TIME_UNIT_FOREVER_ABS;
1782 self.status = PEER_STATE_KEY_CONFIRMED;
1783 self.is_connected = GNUNET_YES;
1789 * Shutdown sessions subsystem.
1792 GSC_SESSIONS_done ()
1794 GNUNET_CONTAINER_multihashmap_iterate (neighbours, &free_neighbour_helper,
1796 GNUNET_CONTAINER_multihashmap_destroy (neighbours);
1798 GNUNET_STATISTICS_set (stats, gettext_noop ("# neighbour entries allocated"),