#define DEBUG_HANDSHAKE GNUNET_NO
-#define DEBUG_CORE_QUOTA GNUNET_YES
+#define DEBUG_CORE_QUOTA GNUNET_NO
/**
* Receive and send buffer windows grow over time. For
*/
enum PeerStateMachine
{
+ /**
+ * No handshake yet.
+ */
PEER_STATE_DOWN,
+
+ /**
+ * We've sent our session key.
+ */
PEER_STATE_KEY_SENT,
+
+ /**
+ * We've received the other peers session key.
+ */
PEER_STATE_KEY_RECEIVED,
+
+ /**
+ * The other peer has confirmed our session key with a message
+ * encrypted with his session key (which we got). Session is now fully up.
+ */
PEER_STATE_KEY_CONFIRMED
};
*/
struct Neighbour
{
- /**
- * We keep neighbours in a linked list (for now).
- */
- struct Neighbour *next;
/**
* Unencrypted messages destined for this peer.
*/
struct SetKeyMessage *skm;
+ /**
+ * Performance data for the peer.
+ */
+ struct GNUNET_TRANSPORT_ATS_Information *ats;
+
/**
* Identity of the neighbour.
*/
*/
unsigned long long current_preference;
+ /**
+ * Number of entries in 'ats'.
+ */
+ unsigned int ats_count;
+
/**
* Bit map indicating which of the 32 sequence numbers before the last
* were received (good for accepting out-of-order packets and
static struct GNUNET_SERVER_NotificationContext *notifier;
/**
- * We keep neighbours in a linked list (for now).
+ * Map of peer identities to 'struct Neighbour'.
+ */
+static struct GNUNET_CONTAINER_MultiHashMap *neighbours;
+
+/**
+ * Neighbour entry for "this" peer.
*/
-static struct Neighbour *neighbours;
+static struct Neighbour self;
/**
* For creating statistics.
*/
static unsigned long long preference_sum;
-/**
- * Total number of neighbours we have.
- */
-static unsigned int neighbour_count;
-
/**
* How much inbound bandwidth are we supposed to be using per second?
- * FIXME: this value is not used!
*/
static unsigned long long bandwidth_target_in_bps;
}
+/**
+ * At what time should the connection to the given neighbour
+ * time out (given no further activity?)
+ *
+ * @param n neighbour in question
+ * @return absolute timeout
+ */
+static struct GNUNET_TIME_Absolute
+get_neighbour_timeout (struct Neighbour *n)
+{
+ return GNUNET_TIME_absolute_add (n->last_activity,
+ GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
+}
+
+
+/**
+ * Helper function for update_preference_sum.
+ */
+static int
+update_preference (void *cls,
+ const GNUNET_HashCode *key,
+ void *value)
+{
+ unsigned long long *ps = cls;
+ struct Neighbour *n = value;
+
+ n->current_preference /= 2;
+ *ps += n->current_preference;
+ return GNUNET_OK;
+}
+
+
/**
* A preference value for a neighbour was update. Update
* the preference sum accordingly.
static void
update_preference_sum (unsigned long long inc)
{
- struct Neighbour *n;
unsigned long long os;
os = preference_sum;
return; /* done! */
/* overflow! compensate by cutting all values in half! */
preference_sum = 0;
- n = neighbours;
- while (n != NULL)
- {
- n->current_preference /= 2;
- preference_sum += n->current_preference;
- n = n->next;
- }
+ GNUNET_CONTAINER_multihashmap_iterate (neighbours,
+ &update_preference,
+ &preference_sum);
GNUNET_STATISTICS_set (stats, gettext_noop ("# total peer preference"), preference_sum, GNUNET_NO);
}
static struct Neighbour *
find_neighbour (const struct GNUNET_PeerIdentity *peer)
{
- struct Neighbour *ret;
-
- ret = neighbours;
- while ((ret != NULL) &&
- (0 != memcmp (&ret->peer,
- peer, sizeof (struct GNUNET_PeerIdentity))))
- ret = ret->next;
- return ret;
+ return GNUNET_CONTAINER_multihashmap_get (neighbours, &peer->hashPubKey);
}
static void
handle_peer_status_change (struct Neighbour *n)
{
- struct PeerStatusNotifyMessage psnm;
+ struct PeerStatusNotifyMessage *psnm;
+ char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1];
+ struct GNUNET_TRANSPORT_ATS_Information *ats;
+ size_t size;
if ( (! n->is_connected) ||
(n->status != PEER_STATE_KEY_CONFIRMED) )
"Peer `%4s' changed status\n",
GNUNET_i2s (&n->peer));
#endif
- psnm.header.size = htons (sizeof (struct PeerStatusNotifyMessage));
- psnm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_STATUS_CHANGE);
- psnm.ats_count = htonl (0);
- psnm.ats.type = htonl (0);
- psnm.ats.value = htonl (0);
- psnm.timeout = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_add (n->last_activity,
- GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT));
- psnm.bandwidth_in = n->bw_in;
- psnm.bandwidth_out = n->bw_out;
- psnm.peer = n->peer;
- send_to_all_clients (&psnm.header,
+ size = sizeof (struct PeerStatusNotifyMessage) +
+ n->ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
+ if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+ {
+ GNUNET_break (0);
+ /* recovery strategy: throw away performance data */
+ GNUNET_array_grow (n->ats,
+ n->ats_count,
+ 0);
+ size = sizeof (struct PeerStatusNotifyMessage) +
+ n->ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
+ }
+ psnm = (struct PeerStatusNotifyMessage*) buf;
+ psnm->header.size = htons (size);
+ psnm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_STATUS_CHANGE);
+ psnm->timeout = GNUNET_TIME_absolute_hton (get_neighbour_timeout (n));
+ psnm->bandwidth_in = n->bw_in;
+ psnm->bandwidth_out = n->bw_out;
+ psnm->peer = n->peer;
+ psnm->ats_count = htonl (n->ats_count);
+ ats = &psnm->ats;
+ memcpy (ats,
+ n->ats,
+ n->ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information));
+ ats[n->ats_count].type = htonl (0);
+ ats[n->ats_count].value = htonl (0);
+ send_to_all_clients (&psnm->header,
GNUNET_YES,
GNUNET_CORE_OPTION_SEND_STATUS_CHANGE);
GNUNET_STATISTICS_update (stats,
unsigned int queue_size;
/* check if neighbour queue is empty enough! */
- queue_size = 0;
- mqe = n->messages;
- while (mqe != NULL)
- {
- queue_size++;
- mqe = mqe->next;
- }
- if (queue_size >= MAX_PEER_QUEUE_SIZE)
+ if (n != &self)
{
+ queue_size = 0;
+ mqe = n->messages;
+ while (mqe != NULL)
+ {
+ queue_size++;
+ mqe = mqe->next;
+ }
+ if (queue_size >= MAX_PEER_QUEUE_SIZE)
+ {
#if DEBUG_CORE_CLIENT
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Not considering client transmission requests: queue full\n");
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Not considering client transmission requests: queue full\n");
#endif
- return; /* queue still full */
+ return; /* queue still full */
+ }
+ /* find highest priority request */
+ pos = n->active_client_request_head;
+ car = NULL;
+ while (pos != NULL)
+ {
+ if ( (car == NULL) ||
+ (pos->priority > car->priority) )
+ car = pos;
+ pos = pos->next;
+ }
}
- /* find highest priority request */
- pos = n->active_client_request_head;
- car = NULL;
- while (pos != NULL)
+ else
{
- if ( (car == NULL) ||
- (pos->priority > car->priority) )
- car = pos;
- pos = pos->next;
+ car = n->active_client_request_head;
}
if (car == NULL)
return; /* no pending requests */
GNUNET_CONTAINER_DLL_remove (n->active_client_request_head,
n->active_client_request_tail,
car);
- GNUNET_CONTAINER_multihashmap_remove (c->requests,
- &n->peer.hashPubKey,
- car);
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap_remove (c->requests,
+ &n->peer.hashPubKey,
+ car));
smr.header.size = htons (sizeof (struct SendMessageReady));
smr.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_SEND_READY);
smr.size = htons (car->msize);
struct ClientActiveRequest *car;
req = (const struct SendMessageRequest*) message;
- n = find_neighbour (&req->peer);
+ if (0 == memcmp (&req->peer,
+ &my_identity,
+ sizeof (struct GNUNET_PeerIdentity)))
+ n = &self;
+ else
+ n = find_neighbour (&req->peer);
if ( (n == NULL) ||
(GNUNET_YES != n->is_connected) ||
(n->status != PEER_STATE_KEY_CONFIRMED) )
}
+/**
+ * Notify client about an existing connection to one of our neighbours.
+ */
+static int
+notify_client_about_neighbour (void *cls,
+ const GNUNET_HashCode *key,
+ void *value)
+{
+ struct Client *c = cls;
+ struct Neighbour *n = value;
+ size_t size;
+ char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1];
+ struct GNUNET_TRANSPORT_ATS_Information *ats;
+ struct ConnectNotifyMessage *cnm;
+
+ size = sizeof (struct ConnectNotifyMessage) +
+ (n->ats_count) * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
+ if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+ {
+ GNUNET_break (0);
+ /* recovery strategy: throw away performance data */
+ GNUNET_array_grow (n->ats,
+ n->ats_count,
+ 0);
+ size = sizeof (struct ConnectNotifyMessage) +
+ (n->ats_count) * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
+ }
+ cnm = (struct ConnectNotifyMessage*) buf;
+ cnm->header.size = htons (size);
+ cnm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT);
+ cnm->ats_count = htonl (n->ats_count);
+ ats = &cnm->ats;
+ memcpy (ats,
+ n->ats,
+ sizeof (struct GNUNET_TRANSPORT_ATS_Information) * n->ats_count);
+ ats[n->ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
+ ats[n->ats_count].value = htonl (0);
+ if (n->status == PEER_STATE_KEY_CONFIRMED)
+ {
+#if DEBUG_CORE_CLIENT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Sending `%s' message to client.\n", "NOTIFY_CONNECT");
+#endif
+ cnm->peer = n->peer;
+ send_to_client (c, &cnm->header, GNUNET_NO);
+ }
+ return GNUNET_OK;
+}
+
+
+
/**
* Handle CORE_INIT request.
*/
uint16_t msize;
const uint16_t *types;
uint16_t *wtypes;
- struct Neighbour *n;
- struct ConnectNotifyMessage cnm;
unsigned int i;
#if DEBUG_CORE_CLIENT
if (0 != (c->options & GNUNET_CORE_OPTION_SEND_CONNECT))
{
/* notify new client about existing neighbours */
- cnm.header.size = htons (sizeof (struct ConnectNotifyMessage));
- cnm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT);
- cnm.ats_count = htonl (0);
- cnm.ats.type = htonl (0);
- cnm.ats.value = htonl (0);
- n = neighbours;
- while (n != NULL)
- {
- if (n->status == PEER_STATE_KEY_CONFIRMED)
- {
-#if DEBUG_CORE_CLIENT
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Sending `%s' message to client.\n", "NOTIFY_CONNECT");
-#endif
- cnm.peer = n->peer;
- send_to_client (c, &cnm.header, GNUNET_NO);
- }
- n = n->next;
- }
+ GNUNET_CONTAINER_multihashmap_iterate (neighbours,
+ ¬ify_client_about_neighbour,
+ c);
}
GNUNET_SERVER_receive_done (client, GNUNET_OK);
}
peer.hashPubKey = *key;
n = find_neighbour (&peer);
+ GNUNET_assert (NULL != n);
GNUNET_CONTAINER_DLL_remove (n->active_client_request_head,
n->active_client_request_tail,
car);
}
+/**
+ * Helper function for handle_client_iterate_peers.
+ *
+ * @param cls the 'struct GNUNET_SERVER_TransmitContext' to queue replies
+ * @param key identity of the connected peer
+ * @param value the 'struct Neighbour' for the peer
+ * @return GNUNET_OK (continue to iterate)
+ */
+static int
+queue_connect_message (void *cls,
+ const GNUNET_HashCode *key,
+ void *value)
+{
+ struct GNUNET_SERVER_TransmitContext *tc = cls;
+ struct Neighbour *n = value;
+ char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1];
+ struct GNUNET_TRANSPORT_ATS_Information *ats;
+ size_t size;
+ struct ConnectNotifyMessage *cnm;
+
+ cnm = (struct ConnectNotifyMessage*) buf;
+ if (n->status != PEER_STATE_KEY_CONFIRMED)
+ return GNUNET_OK;
+ size = sizeof (struct ConnectNotifyMessage) +
+ (n->ats_count) * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
+ if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+ {
+ GNUNET_break (0);
+ /* recovery strategy: throw away performance data */
+ GNUNET_array_grow (n->ats,
+ n->ats_count,
+ 0);
+ size = sizeof (struct PeerStatusNotifyMessage) +
+ n->ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
+ }
+ cnm = (struct ConnectNotifyMessage*) buf;
+ cnm->header.size = htons (size);
+ cnm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT);
+ cnm->ats_count = htonl (n->ats_count);
+ ats = &cnm->ats;
+ memcpy (ats,
+ n->ats,
+ n->ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information));
+ ats[n->ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
+ ats[n->ats_count].value = htonl (0);
+#if DEBUG_CORE_CLIENT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Sending `%s' message to client.\n",
+ "NOTIFY_CONNECT");
+#endif
+ cnm->peer = n->peer;
+ GNUNET_SERVER_transmit_context_append_message (tc,
+ &cnm->header);
+ return GNUNET_OK;
+}
+
+
/**
* Handle CORE_ITERATE_PEERS request.
+ *
+ * @param cls unused
+ * @param client client sending the iteration request
+ * @param message iteration request message
*/
static void
handle_client_iterate_peers (void *cls,
- struct GNUNET_SERVER_Client *client,
- const struct GNUNET_MessageHeader *message)
+ struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
{
- struct Neighbour *n;
- struct ConnectNotifyMessage cnm;
struct GNUNET_MessageHeader done_msg;
struct GNUNET_SERVER_TransmitContext *tc;
-
+ int msize;
/* notify new client about existing neighbours */
- cnm.header.size = htons (sizeof (struct ConnectNotifyMessage));
- cnm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT);
+
+ msize = ntohs(message->size);
+ tc = GNUNET_SERVER_transmit_context_create (client);
+ if (msize == sizeof(struct GNUNET_MessageHeader))
+ GNUNET_CONTAINER_multihashmap_iterate (neighbours, &queue_connect_message, tc);
+ else
+ GNUNET_break(0);
+
done_msg.size = htons (sizeof (struct GNUNET_MessageHeader));
- done_msg.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT);
+ done_msg.type = htons (GNUNET_MESSAGE_TYPE_CORE_ITERATE_PEERS_END);
+ GNUNET_SERVER_transmit_context_append_message (tc, &done_msg);
+ GNUNET_SERVER_transmit_context_run (tc,
+ GNUNET_TIME_UNIT_FOREVER_REL);
+}
+
+/**
+ * Handle CORE_ITERATE_PEERS request. Notify client about existing neighbours.
+ *
+ * @param cls unused
+ * @param client client sending the iteration request
+ * @param message iteration request message
+ */
+static void
+handle_client_have_peer (void *cls,
+ struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+
+{
+ struct GNUNET_MessageHeader done_msg;
+ struct GNUNET_SERVER_TransmitContext *tc;
+ struct GNUNET_PeerIdentity *peer;
+
tc = GNUNET_SERVER_transmit_context_create (client);
- n = neighbours;
- cnm.ats_count = htonl (0);
- cnm.ats.type = htonl (0);
- cnm.ats.value = htonl (0);
- while (n != NULL)
- {
- if (n->status == PEER_STATE_KEY_CONFIRMED)
- {
-#if DEBUG_CORE_CLIENT
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Sending `%s' message to client.\n", "NOTIFY_CONNECT");
-#endif
- cnm.peer = n->peer;
- GNUNET_SERVER_transmit_context_append_message (tc, &cnm.header);
- }
- n = n->next;
- }
+ peer = (struct GNUNET_PeerIdentity *) &message[1];
+ GNUNET_CONTAINER_multihashmap_get_multiple(neighbours,
+ &peer->hashPubKey,
+ &queue_connect_message,
+ tc);
+ done_msg.size = htons (sizeof (struct GNUNET_MessageHeader));
+ done_msg.type = htons (GNUNET_MESSAGE_TYPE_CORE_ITERATE_PEERS_END);
GNUNET_SERVER_transmit_context_append_message (tc, &done_msg);
GNUNET_SERVER_transmit_context_run (tc,
GNUNET_TIME_UNIT_FOREVER_REL);
/**
* Handle REQUEST_INFO request.
+ *
+ * @param cls unused
+ * @param client client sending the request
+ * @param message iteration request message
*/
static void
handle_client_request_info (void *cls,
int32_t want_reserv;
int32_t got_reserv;
unsigned long long old_preference;
+ struct GNUNET_TIME_Relative rdelay;
+ rdelay = GNUNET_TIME_relative_get_zero();
#if DEBUG_CORE_CLIENT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Core service receives `%s' request.\n", "REQUEST_INFO");
}
else if (want_reserv > 0)
{
- if (GNUNET_BANDWIDTH_tracker_get_delay (&n->available_recv_window,
- want_reserv).rel_value == 0)
+ rdelay = GNUNET_BANDWIDTH_tracker_get_delay (&n->available_recv_window,
+ want_reserv);
+ if (rdelay.rel_value == 0)
got_reserv = want_reserv;
else
got_reserv = 0; /* all or nothing */
(int) got_reserv);
#endif
cim.reserved_amount = htonl (got_reserv);
+ cim.reserve_delay = GNUNET_TIME_relative_hton (rdelay);
cim.rim_id = rcm->rim_id;
cim.bw_out = n->bw_out;
cim.preference = n->current_preference;
if (n->keep_alive_task != GNUNET_SCHEDULER_NO_TASK)
GNUNET_SCHEDULER_cancel (n->keep_alive_task);
if (n->status == PEER_STATE_KEY_CONFIRMED)
- GNUNET_STATISTICS_update (stats, gettext_noop ("# established sessions"), -1, GNUNET_NO);
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# established sessions"),
+ -1,
+ GNUNET_NO);
+ GNUNET_array_grow (n->ats, n->ats_count, 0);
GNUNET_free_non_null (n->public_key);
GNUNET_free_non_null (n->pending_ping);
GNUNET_free_non_null (n->pending_pong);
((void *) &pm->target - (void *) pm));
process_encrypted_neighbour_queue (n);
/* reschedule PING job */
- left = GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_add (n->last_activity,
- GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT));
+ left = GNUNET_TIME_absolute_get_remaining (get_neighbour_timeout (n));
retry = GNUNET_TIME_relative_max (GNUNET_TIME_relative_divide (left, 2),
MIN_PING_FREQUENCY);
n->keep_alive_task
static void
consider_free_neighbour (struct Neighbour *n)
{
- struct Neighbour *pos;
- struct Neighbour *prev;
struct GNUNET_TIME_Relative left;
if ( (n->th != NULL) ||
(GNUNET_YES == n->is_connected) )
return; /* no chance */
- left = GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_add (n->last_activity,
- GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT));
+ left = GNUNET_TIME_absolute_get_remaining (get_neighbour_timeout (n));
if (left.rel_value > 0)
{
if (n->dead_clean_task != GNUNET_SCHEDULER_NO_TASK)
return;
}
/* actually free the neighbour... */
- prev = NULL;
- pos = neighbours;
- while (pos != n)
- {
- prev = pos;
- pos = pos->next;
- }
- if (prev == NULL)
- neighbours = n->next;
- else
- prev->next = n->next;
- GNUNET_assert (neighbour_count > 0);
- neighbour_count--;
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CONTAINER_multihashmap_remove (neighbours,
+ &n->peer.hashPubKey,
+ n));
GNUNET_STATISTICS_set (stats,
gettext_noop ("# neighbour entries allocated"),
- neighbour_count,
+ GNUNET_CONTAINER_multihashmap_size (neighbours),
GNUNET_NO);
free_neighbour (n);
}
* @return number of bytes transmitted
*/
static size_t
-notify_encrypted_transmit_ready (void *cls, size_t size, void *buf)
+notify_encrypted_transmit_ready (void *cls,
+ size_t size,
+ void *buf)
{
struct Neighbour *n = cls;
struct MessageEntry *m;
}
GNUNET_free (m);
consider_free_neighbour (n);
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# encrypted bytes given to transport"),
+ ret,
+ GNUNET_NO);
return ret;
}
GNUNET_break (0);
return GNUNET_SYSERR;
}
- GNUNET_STATISTICS_update (stats, gettext_noop ("# bytes decrypted"), size, GNUNET_NO);
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# bytes decrypted"),
+ size,
+ GNUNET_NO);
#if DEBUG_CORE
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Decrypted %u bytes from `%4s' using key %u, IV %u\n",
GNUNET_i2s (pid));
#endif
n = GNUNET_malloc (sizeof (struct Neighbour));
- n->next = neighbours;
- neighbours = n;
- neighbour_count++;
- GNUNET_STATISTICS_set (stats, gettext_noop ("# neighbour entries allocated"), neighbour_count, GNUNET_NO);
n->peer = *pid;
GNUNET_CRYPTO_aes_create_session_key (&n->encrypt_key);
now = GNUNET_TIME_absolute_get ();
n->bw_out_external_limit = GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT;
n->ping_challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
UINT32_MAX);
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CONTAINER_multihashmap_put (neighbours,
+ &n->peer.hashPubKey,
+ n,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+ GNUNET_STATISTICS_set (stats, gettext_noop ("# neighbour entries allocated"),
+ GNUNET_CONTAINER_multihashmap_size (neighbours), GNUNET_NO);
neighbour_quota_update (n, NULL);
consider_free_neighbour (n);
return n;
msize -= sizeof (struct SendMessage);
if (0 == memcmp (&sm->peer, &my_identity, sizeof (struct GNUNET_PeerIdentity)))
{
- /* FIXME: should we not allow loopback-injection here? */
- GNUNET_break (0);
+ /* loopback */
+ GNUNET_SERVER_mst_receive (mst,
+ &self,
+ (const char*) &sm[1],
+ msize,
+ GNUNET_YES,
+ GNUNET_NO);
if (client != NULL)
- GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
return;
}
n = find_neighbour (&sm->peer);
GNUNET_i2s (&sm->peer),
(unsigned int) msize);
#endif
+ GNUNET_break (0 == ntohl (sm->reserved));
e = GNUNET_malloc (sizeof (struct MessageEntry) + msize);
e->deadline = GNUNET_TIME_absolute_ntoh (sm->deadline);
e->priority = ntohl (sm->priority);
e->size = msize;
+ if (GNUNET_YES != (int) ntohl (sm->cork))
+ e->got_slack = GNUNET_YES;
memcpy (&e[1], &sm[1], msize);
/* insert, keep list sorted by deadline */
* @return number of bytes transmitted
*/
static size_t
-notify_transport_connect_done (void *cls, size_t size, void *buf)
+notify_transport_connect_done (void *cls,
+ size_t size,
+ void *buf)
{
struct Neighbour *n = cls;
+ n->th = NULL;
if (GNUNET_YES != n->is_connected)
{
/* transport should only call us to transmit a message after
* telling us about a successful connection to the respective peer */
- n->th = NULL; /* If this happens because of a timeout, reset n-th so another message may be sent for this peer! */
#if DEBUG_CORE
- GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Timeout on notify connect!\n");
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Timeout on notify connect!\n");
#endif
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# connection requests timed out in transport"),
+ 1,
+ GNUNET_NO);
return 0;
}
- n->th = NULL;
if (buf == NULL)
{
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# connection requests timed out in transport"),
+ 1,
+ GNUNET_NO);
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
_("Failed to connect to `%4s': transport failed to connect\n"),
GNUNET_i2s (&n->peer));
struct Neighbour *n;
struct GNUNET_TIME_Relative timeout;
- if (0 == memcmp (&cm->peer, &my_identity, sizeof (struct GNUNET_PeerIdentity)))
+ if (0 == memcmp (&cm->peer,
+ &my_identity,
+ sizeof (struct GNUNET_PeerIdentity)))
{
- GNUNET_break (0);
- GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ /* In this case a client has asked us to connect to ourselves, not really an error! */
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
return;
}
+ timeout = GNUNET_TIME_relative_ntoh (cm->timeout);
+ GNUNET_break (ntohl (cm->reserved) == 0);
GNUNET_SERVER_receive_done (client, GNUNET_OK);
n = find_neighbour (&cm->peer);
if (n == NULL)
if ( (GNUNET_YES == n->is_connected) ||
(n->th != NULL) )
{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Core received `%s' request for `%4s', already connected!\n",
- "REQUEST_CONNECT",
- GNUNET_i2s (&cm->peer));
+ if (GNUNET_YES == n->is_connected)
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# connection requests ignored (already connected)"),
+ 1,
+ GNUNET_NO);
+ else
+ {
+ GNUNET_TRANSPORT_notify_transmit_ready_cancel(n->th);
+ n->th = GNUNET_TRANSPORT_notify_transmit_ready (transport,
+ &cm->peer,
+ sizeof (struct GNUNET_MessageHeader), 0,
+ timeout,
+ ¬ify_transport_connect_done,
+ n);
+ GNUNET_break (NULL != n->th);
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# connection requests retried (due to repeat request connect)"),
+ 1,
+ GNUNET_NO);
+ }
return; /* already connected, or at least trying */
}
- GNUNET_STATISTICS_update (stats, gettext_noop ("# connection requests received"), 1, GNUNET_NO);
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# connection requests received"),
+ 1,
+ GNUNET_NO);
+#if DEBUG_CORE
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Core received `%s' request for `%4s', will try to establish connection\n",
"REQUEST_CONNECT",
GNUNET_i2s (&cm->peer));
+#endif
- timeout = GNUNET_TIME_relative_ntoh (cm->timeout);
/* ask transport to connect to the peer */
n->th = GNUNET_TRANSPORT_notify_transmit_ready (transport,
&cm->peer,
* @param cls the 'struct Neighbour' to retry sending the key for
* @param peer the peer for which this is the HELLO
* @param hello HELLO message of that peer
+ * @param err_msg NULL if successful, otherwise contains error message
*/
static void
process_hello_retry_send_key (void *cls,
const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_HELLO_Message *hello)
+ const struct GNUNET_HELLO_Message *hello,
+ const char *err_msg)
{
struct Neighbour *n = cls;
+ if (err_msg != NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ _("Error in communication with PEERINFO service\n"));
+ /* return; */
+ }
+
if (peer == NULL)
{
#if DEBUG_CORE
*
* @param n the neighbour from which we received message m
* @param m the set key message we received
+ * @param ats performance data
+ * @param ats_count number of entries in ats (excluding 0-termination)
*/
static void
handle_set_key (struct Neighbour *n,
- const struct SetKeyMessage *m);
+ const struct SetKeyMessage *m,
+ const struct GNUNET_TRANSPORT_ATS_Information *ats,
+ uint32_t ats_count);
+
/**
* @param cls pointer to the set key message
* @param peer the peer for which this is the HELLO
* @param hello HELLO message of that peer
+ * @param err_msg NULL if successful, otherwise contains error message
*/
static void
process_hello_retry_handle_set_key (void *cls,
const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_HELLO_Message *hello)
+ const struct GNUNET_HELLO_Message *hello,
+ const char *err_msg)
{
struct Neighbour *n = cls;
struct SetKeyMessage *sm = n->skm;
+ if (err_msg != NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ _("Error in communication with PEERINFO service\n"));
+ /* return; */
+ }
+
if (peer == NULL)
{
n->skm = NULL;
GNUNET_i2s (&n->peer),
"SET_KEY");
#endif
- handle_set_key (n, sm);
+ handle_set_key (n, sm, NULL, 0);
}
else
{
}
+/**
+ * Merge the given performance data with the data we currently
+ * track for the given neighbour.
+ *
+ * @param n neighbour
+ * @param ats new performance data
+ * @param ats_count number of records in ats
+ */
+static void
+update_neighbour_performance (struct Neighbour *n,
+ const struct GNUNET_TRANSPORT_ATS_Information *ats,
+ uint32_t ats_count)
+{
+ uint32_t i;
+ unsigned int j;
+
+ if (ats_count == 0)
+ return;
+ for (i = 0; i < ats_count; i++)
+ {
+ for (j=0;j < n->ats_count; j++)
+ {
+ if (n->ats[j].type == ats[i].type)
+ {
+ n->ats[j].value = ats[i].value;
+ break;
+ }
+ }
+ if (j == n->ats_count)
+ {
+ GNUNET_array_append (n->ats,
+ n->ats_count,
+ ats[i]);
+ }
+ }
+}
+
+
/**
* We received a PING message. Validate and transmit
* PONG.
*
* @param n sender of the PING
* @param m the encrypted PING message itself
+ * @param ats performance data
+ * @param ats_count number of entries in ats (excluding 0-termination)
*/
static void
-handle_ping (struct Neighbour *n, const struct PingMessage *m)
+handle_ping (struct Neighbour *n,
+ const struct PingMessage *m,
+ const struct GNUNET_TRANSPORT_ATS_Information *ats,
+ uint32_t ats_count)
{
struct PingMessage t;
struct PongMessage tx;
GNUNET_break_op (0);
return;
}
+ update_neighbour_performance (n, ats, ats_count);
me = GNUNET_malloc (sizeof (struct MessageEntry) +
sizeof (struct PongMessage));
GNUNET_CONTAINER_DLL_insert_after (n->encrypted_head,
*
* @param n sender of the PONG
* @param m the encrypted PONG message itself
+ * @param ats performance data
+ * @param ats_count number of entries in ats (excluding 0-termination)
*/
static void
handle_pong (struct Neighbour *n,
- const struct PongMessage *m)
+ const struct PongMessage *m,
+ const struct GNUNET_TRANSPORT_ATS_Information *ats,
+ uint32_t ats_count)
{
struct PongMessage t;
- struct ConnectNotifyMessage cnm;
+ struct ConnectNotifyMessage *cnm;
struct GNUNET_CRYPTO_AesInitializationVector iv;
+ char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1];
+ struct GNUNET_TRANSPORT_ATS_Information *mats;
+ size_t size;
#if DEBUG_CORE
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
GNUNET_SCHEDULER_cancel (n->retry_set_key_task);
n->retry_set_key_task = GNUNET_SCHEDULER_NO_TASK;
}
- cnm.header.size = htons (sizeof (struct ConnectNotifyMessage));
- cnm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT);
- cnm.peer = n->peer;
- send_to_all_clients (&cnm.header, GNUNET_NO, GNUNET_CORE_OPTION_SEND_CONNECT);
+ update_neighbour_performance (n, ats, ats_count);
+ size = sizeof (struct ConnectNotifyMessage) +
+ (n->ats_count) * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
+ if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+ {
+ GNUNET_break (0);
+ /* recovery strategy: throw away performance data */
+ GNUNET_array_grow (n->ats,
+ n->ats_count,
+ 0);
+ size = sizeof (struct PeerStatusNotifyMessage) +
+ n->ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
+ }
+ cnm = (struct ConnectNotifyMessage*) buf;
+ cnm->header.size = htons (size);
+ cnm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT);
+ cnm->ats_count = htonl (n->ats_count);
+ cnm->peer = n->peer;
+ mats = &cnm->ats;
+ memcpy (mats,
+ n->ats,
+ n->ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information));
+ mats[n->ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
+ mats[n->ats_count].value = htonl (0);
+ send_to_all_clients (&cnm->header,
+ GNUNET_NO,
+ GNUNET_CORE_OPTION_SEND_CONNECT);
process_encrypted_neighbour_queue (n);
/* fall-through! */
case PEER_STATE_KEY_CONFIRMED:
*
* @param n the neighbour from which we received message m
* @param m the set key message we received
+ * @param ats performance data
+ * @param ats_count number of entries in ats (excluding 0-termination)
*/
static void
-handle_set_key (struct Neighbour *n, const struct SetKeyMessage *m)
+handle_set_key (struct Neighbour *n,
+ const struct SetKeyMessage *m,
+ const struct GNUNET_TRANSPORT_ATS_Information *ats,
+ uint32_t ats_count)
{
struct SetKeyMessage *m_cpy;
struct GNUNET_TIME_Absolute t;
n->last_packets_bitmap = 0;
n->decrypt_key_created = t;
}
+ update_neighbour_performance (n, ats, ats_count);
sender_status = (enum PeerStateMachine) ntohl (m->sender_status);
switch (n->status)
{
{
ping = n->pending_ping;
n->pending_ping = NULL;
- handle_ping (n, ping);
+ handle_ping (n, ping, NULL, 0);
GNUNET_free (ping);
}
if (n->pending_pong != NULL)
{
pong = n->pending_pong;
n->pending_pong = NULL;
- handle_pong (n, pong);
+ handle_pong (n, pong, NULL, 0);
GNUNET_free (pong);
}
}
struct Client *client,
const void *m, size_t msize)
{
- char buf[msize + sizeof (struct NotifyTrafficMessage)];
+ size_t size = msize + sizeof (struct NotifyTrafficMessage) +
+ (sender->ats_count) * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
+ char buf[size];
struct NotifyTrafficMessage *ntm;
+ struct GNUNET_TRANSPORT_ATS_Information *ats;
+ if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+ {
+ GNUNET_break (0);
+ /* recovery strategy: throw performance data away... */
+ GNUNET_array_grow (sender->ats,
+ sender->ats_count,
+ 0);
+ size = msize + sizeof (struct NotifyTrafficMessage) +
+ (sender->ats_count) * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
+ }
#if DEBUG_CORE
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Core service passes message from `%4s' of type %u to client.\n",
(unsigned int) ntohs (((const struct GNUNET_MessageHeader *) m)->type));
#endif
ntm = (struct NotifyTrafficMessage *) buf;
- ntm->header.size = htons (msize + sizeof (struct NotifyTrafficMessage));
+ ntm->header.size = htons (size);
ntm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND);
- ntm->ats_count = htonl (0);
- ntm->ats.type = htonl (0);
- ntm->ats.value = htonl (0);
+ ntm->ats_count = htonl (sender->ats_count);
ntm->peer = sender->peer;
- memcpy (&ntm[1], m, msize);
+ ats = &ntm->ats;
+ memcpy (ats,
+ sender->ats,
+ sizeof (struct GNUNET_TRANSPORT_ATS_Information) * sender->ats_count);
+ ats[sender->ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
+ ats[sender->ats_count].value = htonl (0);
+ memcpy (&ats[sender->ats_count+1],
+ m,
+ msize);
send_to_client (client, &ntm->header, GNUNET_YES);
}
/**
* We received an encrypted message. Decrypt, validate and
* pass on to the appropriate clients.
+ *
+ * @param n target of the message
+ * @param m encrypted message
+ * @param ats performance data
+ * @param ats_count number of entries in ats (excluding 0-termination)
*/
static void
handle_encrypted_message (struct Neighbour *n,
- const struct EncryptedMessage *m)
+ const struct EncryptedMessage *m,
+ const struct GNUNET_TRANSPORT_ATS_Information *ats,
+ uint32_t ats_count)
{
size_t size = ntohs (m->header.size);
char buf[size];
size - sizeof (struct EncryptedMessage),
GNUNET_NO);
handle_peer_status_change (n);
+ update_neighbour_performance (n, ats, ats_count);
if (GNUNET_OK != GNUNET_SERVER_mst_receive (mst,
n,
&buf[sizeof (struct EncryptedMessage)],
* @param cls closure
* @param peer (claimed) identity of the other peer
* @param message the message
- * @param latency estimated latency for communicating with the
- * given peer (round-trip)
- * @param distance in overlay hops, as given by transport plugin
+ * @param ats performance data
+ * @param ats_count number of entries in ats (excluding 0-termination)
*/
static void
handle_transport_receive (void *cls,
const struct GNUNET_PeerIdentity *peer,
const struct GNUNET_MessageHeader *message,
- struct GNUNET_TIME_Relative latency,
- unsigned int distance)
+ const struct GNUNET_TRANSPORT_ATS_Information *ats,
+ uint32_t ats_count)
{
struct Neighbour *n;
struct GNUNET_TIME_Absolute now;
n = find_neighbour (peer);
if (n == NULL)
n = create_neighbour (peer);
- changed = GNUNET_YES; /* FIXME... */
+ changed = GNUNET_NO;
up = (n->status == PEER_STATE_KEY_CONFIRMED);
type = ntohs (message->type);
size = ntohs (message->size);
GNUNET_break_op (0);
return;
}
- GNUNET_STATISTICS_update (stats, gettext_noop ("# session keys received"), 1, GNUNET_NO);
- handle_set_key (n, (const struct SetKeyMessage *) message);
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# session keys received"),
+ 1,
+ GNUNET_NO);
+ handle_set_key (n,
+ (const struct SetKeyMessage *) message,
+ ats, ats_count);
break;
case GNUNET_MESSAGE_TYPE_CORE_ENCRYPTED_MESSAGE:
if (size < sizeof (struct EncryptedMessage) +
if ((n->status != PEER_STATE_KEY_RECEIVED) &&
(n->status != PEER_STATE_KEY_CONFIRMED))
{
- GNUNET_break_op (0);
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# failed to decrypt message (no session key)"),
+ 1,
+ GNUNET_NO);
+ send_key (n);
return;
}
- handle_encrypted_message (n, (const struct EncryptedMessage *) message);
+ handle_encrypted_message (n,
+ (const struct EncryptedMessage *) message,
+ ats, ats_count);
break;
case GNUNET_MESSAGE_TYPE_CORE_PING:
if (size != sizeof (struct PingMessage))
memcpy (n->pending_ping, message, sizeof (struct PingMessage));
return;
}
- handle_ping (n, (const struct PingMessage *) message);
+ handle_ping (n, (const struct PingMessage *) message,
+ ats, ats_count);
break;
case GNUNET_MESSAGE_TYPE_CORE_PONG:
if (size != sizeof (struct PongMessage))
memcpy (n->pending_pong, message, sizeof (struct PongMessage));
return;
}
- handle_pong (n, (const struct PongMessage *) message);
+ handle_pong (n, (const struct PongMessage *) message,
+ ats, ats_count);
break;
default:
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
changed = GNUNET_YES;
if (!up)
{
- GNUNET_STATISTICS_update (stats, gettext_noop ("# established sessions"), 1, GNUNET_NO);
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# established sessions"),
+ 1,
+ GNUNET_NO);
n->time_established = now;
}
if (n->keep_alive_task != GNUNET_SCHEDULER_NO_TASK)
{
struct Neighbour *n = cls;
struct GNUNET_BANDWIDTH_Value32NBO q_in;
+ struct GNUNET_BANDWIDTH_Value32NBO q_out;
+ struct GNUNET_BANDWIDTH_Value32NBO q_out_min;
double pref_rel;
double share;
unsigned long long distributable;
uint64_t need_per_peer;
uint64_t need_per_second;
+ unsigned int neighbour_count;
#if DEBUG_CORE
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
divides by a bit more to avoid division by zero AND to
account for possibility of new neighbours joining any time
AND to convert to double... */
+ neighbour_count = GNUNET_CONTAINER_multihashmap_size (neighbours);
+ if (neighbour_count == 0)
+ return;
if (preference_sum == 0)
{
pref_rel = 1.0 / (double) neighbour_count;
need_per_peer = GNUNET_BANDWIDTH_value_get_available_until (MIN_BANDWIDTH_PER_PEER,
GNUNET_TIME_UNIT_SECONDS);
need_per_second = need_per_peer * neighbour_count;
+
+ /* calculate inbound bandwidth per peer */
distributable = 0;
- if (bandwidth_target_out_bps > need_per_second)
- distributable = bandwidth_target_out_bps - need_per_second;
+ if (bandwidth_target_in_bps > need_per_second)
+ distributable = bandwidth_target_in_bps - need_per_second;
share = distributable * pref_rel;
if (share + need_per_peer > UINT32_MAX)
q_in = GNUNET_BANDWIDTH_value_init (UINT32_MAX);
else
q_in = GNUNET_BANDWIDTH_value_init (need_per_peer + (uint32_t) share);
+
+ /* calculate outbound bandwidth per peer */
+ distributable = 0;
+ if (bandwidth_target_out_bps > need_per_second)
+ distributable = bandwidth_target_out_bps - need_per_second;
+ share = distributable * pref_rel;
+ if (share + need_per_peer > UINT32_MAX)
+ q_out = GNUNET_BANDWIDTH_value_init (UINT32_MAX);
+ else
+ q_out = GNUNET_BANDWIDTH_value_init (need_per_peer + (uint32_t) share);
+ n->bw_out_internal_limit = q_out;
+
+ q_out_min = GNUNET_BANDWIDTH_value_min (n->bw_out_external_limit, n->bw_out_internal_limit);
+ GNUNET_BANDWIDTH_tracker_update_quota (&n->available_send_window, n->bw_out);
+
/* check if we want to disconnect for good due to inactivity */
- if ( (GNUNET_TIME_absolute_get_duration (n->last_activity).rel_value > GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value) &&
+ if ( (GNUNET_TIME_absolute_get_duration (get_neighbour_timeout (n)).rel_value > 0) &&
(GNUNET_TIME_absolute_get_duration (n->time_established).rel_value > GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value) )
{
#if DEBUG_CORE
(unsigned int) ntohl (n->bw_in.value__),
(unsigned int) ntohl (n->bw_out.value__),
(unsigned int) ntohl (n->bw_out_internal_limit.value__));
-#endif
- if (n->bw_in.value__ != q_in.value__)
+ #endif
+ if ((n->bw_in.value__ != q_in.value__) || (n->bw_out.value__ != q_out_min.value__))
{
- n->bw_in = q_in;
+ if (n->bw_in.value__ != q_in.value__)
+ n->bw_in = q_in;
+ if (n->bw_out.value__ != q_out_min.value__)
+ n->bw_out = q_out_min;
if (GNUNET_YES == n->is_connected)
GNUNET_TRANSPORT_set_quota (transport,
&n->peer,
*
* @param cls closure
* @param peer the peer that connected
- * @param latency current latency of the connection
- * @param distance in overlay hops, as given by transport plugin
+ * @param ats performance data
+ * @param ats_count number of entries in ats (excluding 0-termination)
*/
static void
handle_transport_notify_connect (void *cls,
const struct GNUNET_PeerIdentity *peer,
- struct GNUNET_TIME_Relative latency,
- unsigned int distance)
+ const struct GNUNET_TRANSPORT_ATS_Information *ats,
+ uint32_t ats_count)
{
struct Neighbour *n;
1,
GNUNET_NO);
n->is_connected = GNUNET_YES;
+ update_neighbour_performance (n, ats, ats_count);
GNUNET_BANDWIDTH_tracker_init (&n->available_send_window,
n->bw_out,
MAX_WINDOW_TIME_S);
#if DEBUG_CORE
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Peer `%4s' disconnected from us; received notification from transport.\n", GNUNET_i2s (peer));
+ "Peer `%4s' disconnected from us; received notification from transport.\n",
+ GNUNET_i2s (peer));
#endif
-
n = find_neighbour (peer);
if (n == NULL)
{
GNUNET_break (0);
return;
}
- GNUNET_break (n->is_connected);
+ GNUNET_break (n->is_connected == GNUNET_YES);
if (n->status == PEER_STATE_KEY_CONFIRMED)
{
cnm.header.size = htons (sizeof (struct DisconnectNotifyMessage));
cnm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_DISCONNECT);
+ cnm.reserved = htonl (0);
cnm.peer = *peer;
send_to_all_clients (&cnm.header, GNUNET_NO, GNUNET_CORE_OPTION_SEND_DISCONNECT);
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# established sessions"),
+ -1,
+ GNUNET_NO);
+ }
+
+ /* On transport disconnect transport doesn't cancel requests, so must do so here. */
+ if (n->th != NULL)
+ {
+ GNUNET_TRANSPORT_notify_transmit_ready_cancel (n->th);
+ n->th = NULL;
}
n->is_connected = GNUNET_NO;
+ n->status = PEER_STATE_DOWN;
while (NULL != (car = n->active_client_request_head))
{
GNUNET_CONTAINER_DLL_remove (n->active_client_request_head,
}
+/**
+ * Wrapper around 'free_neighbour'; helper for 'cleaning_task'.
+ */
+static int
+free_neighbour_helper (void *cls,
+ const GNUNET_HashCode *key,
+ void *value)
+{
+ struct Neighbour *n = value;
+
+ free_neighbour (n);
+ return GNUNET_OK;
+}
+
+
/**
* Last task run during shutdown. Disconnects us from
* the transport.
static void
cleaning_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
{
- struct Neighbour *n;
struct Client *c;
#if DEBUG_CORE
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Core service shutting down.\n");
#endif
+ GNUNET_CONTAINER_multihashmap_iterate (neighbours,
+ &free_neighbour_helper,
+ NULL);
+ GNUNET_CONTAINER_multihashmap_destroy (neighbours);
+ neighbours = NULL;
+ GNUNET_STATISTICS_set (stats, gettext_noop ("# neighbour entries allocated"), 0, GNUNET_NO);
GNUNET_assert (transport != NULL);
GNUNET_TRANSPORT_disconnect (transport);
transport = NULL;
- while (NULL != (n = neighbours))
- {
- neighbours = n->next;
- GNUNET_assert (neighbour_count > 0);
- neighbour_count--;
- free_neighbour (n);
- }
- GNUNET_STATISTICS_set (stats, gettext_noop ("# neighbour entries allocated"), neighbour_count, GNUNET_NO);
GNUNET_SERVER_notification_context_destroy (notifier);
notifier = NULL;
while (NULL != (c = clients))
{&handle_client_iterate_peers, NULL,
GNUNET_MESSAGE_TYPE_CORE_ITERATE_PEERS,
sizeof (struct GNUNET_MessageHeader)},
+ {&handle_client_have_peer, NULL,
+ GNUNET_MESSAGE_TYPE_CORE_PEER_CONNECTED,
+ sizeof (struct GNUNET_MessageHeader) + sizeof(struct GNUNET_PeerIdentity)},
{&handle_client_request_info, NULL,
GNUNET_MESSAGE_TYPE_CORE_REQUEST_INFO,
sizeof (struct RequestInfoMessage)},
};
char *keyfile;
- cfg = c;
+ cfg = c;
/* parse configuration */
if (
(GNUNET_OK !=
GNUNET_SCHEDULER_shutdown ();
return;
}
+ neighbours = GNUNET_CONTAINER_multihashmap_create (128);
GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
GNUNET_CRYPTO_hash (&my_public_key,
sizeof (my_public_key), &my_identity.hashPubKey);
+ self.public_key = &my_public_key;
+ self.peer = my_identity;
+ self.last_activity = GNUNET_TIME_UNIT_FOREVER_ABS;
+ self.status = PEER_STATE_KEY_CONFIRMED;
+ self.is_connected = GNUNET_YES;
/* setup notification */
notifier = GNUNET_SERVER_notification_context_create (server,
MAX_NOTIFY_QUEUE);