};
-/**
- * Number of bytes (at the beginning) of "struct EncryptedMessage"
- * that are NOT encrypted.
- */
-#define ENCRYPTED_HEADER_SIZE (sizeof(struct GNUNET_MessageHeader) + sizeof(uint32_t))
-
-
/**
* Encapsulation for encrypted messages exchanged between
* peers. Followed by the actual encrypted data.
struct GNUNET_MessageHeader header;
/**
- * Random value used for IV generation. ENCRYPTED_HEADER_SIZE must
- * be set to the offset of the *next* field.
+ * Random value used for IV generation.
*/
uint32_t iv_seed GNUNET_PACKED;
/**
- * Hash of the plaintext (starting at 'sequence_number'), used to
- * verify message integrity. Everything after this hash (including
- * this hash itself) will be encrypted.
+ * MAC of the encrypted message (starting at 'sequence_number'),
+ * used to verify message integrity. Everything after this value
+ * (excluding this value itself) will be encrypted and authenticated.
+ * ENCRYPTED_HEADER_SIZE must be set to the offset of the *next* field.
*/
GNUNET_HashCode hmac;
/**
* Sequence number, in network byte order. This field
- * must be the first encrypted/decrypted field and the
- * first byte that is hashed for the plaintext hash.
+ * must be the first encrypted/decrypted field
*/
uint32_t sequence_number GNUNET_PACKED;
};
+/**
+ * Number of bytes (at the beginning) of "struct EncryptedMessage"
+ * that are NOT encrypted.
+ */
+#define ENCRYPTED_HEADER_SIZE (offsetof(struct EncryptedMessage, sequence_number))
+
+
/**
* We're sending an (encrypted) PING to the other peer to check if he
* can decrypt. The other peer should respond with a PONG with the
* Message type is CORE_PING.
*/
struct GNUNET_MessageHeader header;
-
+
/**
- * Random number chosen to make reply harder.
+ * Seed for the IV
*/
- uint32_t challenge GNUNET_PACKED;
+ uint32_t iv_seed GNUNET_PACKED;
/**
* Intended target of the PING, used primarily to check
* that decryption actually worked.
*/
struct GNUNET_PeerIdentity target;
+
+ /**
+ * Random number chosen to make reply harder.
+ */
+ uint32_t challenge GNUNET_PACKED;
};
* Message type is CORE_PONG.
*/
struct GNUNET_MessageHeader header;
-
+
/**
- * Random number proochosen to make reply harder. Must be
- * first field after header (this is where we start to encrypt!).
+ * Seed for the IV
*/
- uint32_t challenge GNUNET_PACKED;
+ uint32_t iv_seed GNUNET_PACKED;
/**
- * Must be zero.
+ * Random number to make faking the reply harder. Must be
+ * first field after header (this is where we start to encrypt!).
*/
- uint32_t reserved GNUNET_PACKED;
+ uint32_t challenge GNUNET_PACKED;
/**
* Desired bandwidth (how much we should send to this
};
+/**
+ * Record kept for each request for transmission issued by a
+ * client that is still pending.
+ */
+struct ClientActiveRequest;
+
+/**
+ * Data kept per neighbouring peer.
+ */
struct Neighbour
{
/**
*/
struct MessageEntry *encrypted_tail;
+ /**
+ * Head of list of requests from clients for transmission to
+ * this peer.
+ */
+ struct ClientActiveRequest *active_client_request_head;
+
+ /**
+ * Tail of list of requests from clients for transmission to
+ * this peer.
+ */
+ struct ClientActiveRequest *active_client_request_tail;
+
/**
* Handle for pending requests for transmission to this peer
* with the transport service. NULL if no request is pending.
*/
struct SetKeyMessage *skm;
+ /**
+ * Performance data for the peer.
+ */
+ struct GNUNET_TRANSPORT_ATS_Information *ats;
+
/**
* Identity of the neighbour.
*/
*/
struct GNUNET_TIME_Absolute last_activity;
- /**
- * Last latency observed from this peer.
- */
- struct GNUNET_TIME_Relative last_latency;
-
/**
* At what frequency are we currently re-trying SET_KEY messages?
*/
*/
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
*/
uint32_t ping_challenge;
- /**
- * What was the last distance to this peer as reported by the transports?
- */
- uint32_t last_distance;
-
/**
* What is our connection status?
*/
*/
const uint16_t *types;
+ /**
+ * Map of peer identities to active transmission requests of this
+ * client to the peer (of type 'struct ClientActiveRequest').
+ */
+ struct GNUNET_CONTAINER_MultiHashMap *requests;
+
/**
* Options for messages this client cares about,
* see GNUNET_CORE_OPTION_ values.
};
+/**
+ * Record kept for each request for transmission issued by a
+ * client that is still pending.
+ */
+struct ClientActiveRequest
+{
+
+ /**
+ * Active requests are kept in a doubly-linked list of
+ * the respective target peer.
+ */
+ struct ClientActiveRequest *next;
+
+ /**
+ * Active requests are kept in a doubly-linked list of
+ * the respective target peer.
+ */
+ struct ClientActiveRequest *prev;
+
+ /**
+ * Handle to the client.
+ */
+ struct Client *client;
+
+ /**
+ * By what time would the client want to see this message out?
+ */
+ struct GNUNET_TIME_Absolute deadline;
+
+ /**
+ * How important is this request.
+ */
+ uint32_t priority;
+
+ /**
+ * How many more requests does this client have?
+ */
+ uint32_t queue_size;
+
+ /**
+ * How many bytes does the client intend to send?
+ */
+ uint16_t msize;
+
+ /**
+ * Unique request ID (in big endian).
+ */
+ uint16_t smr_id;
+
+};
+
+
+
/**
* Our public key.
*/
*/
static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
-/**
- * Our scheduler.
- */
-struct GNUNET_SCHEDULER_Handle *sched;
/**
* Handle to peerinfo service.
*/
static unsigned long long bandwidth_target_out_bps;
+/**
+ * Derive an authentication key from "set key" information
+ */
+static void
+derive_auth_key (struct GNUNET_CRYPTO_AuthKey *akey,
+ const struct GNUNET_CRYPTO_AesSessionKey *skey,
+ uint32_t seed,
+ struct GNUNET_TIME_Absolute creation_time)
+{
+ static const char ctx[] = "authentication key";
+ struct GNUNET_TIME_AbsoluteNBO ctbe;
+
+
+ ctbe = GNUNET_TIME_absolute_hton (creation_time);
+ GNUNET_CRYPTO_hmac_derive_key (akey,
+ skey,
+ &seed,
+ sizeof(seed),
+ &skey->key,
+ sizeof(skey->key),
+ &ctbe,
+ sizeof(ctbe),
+ ctx,
+ sizeof(ctx), NULL);
+}
+
+
+/**
+ * Derive an IV from packet information
+ */
+static void
+derive_iv (struct GNUNET_CRYPTO_AesInitializationVector *iv,
+ const struct GNUNET_CRYPTO_AesSessionKey *skey, uint32_t seed,
+ const struct GNUNET_PeerIdentity *identity)
+{
+ static const char ctx[] = "initialization vector";
+
+ GNUNET_CRYPTO_aes_derive_iv (iv,
+ skey,
+ &seed,
+ sizeof(seed),
+ &identity->hashPubKey.bits,
+ sizeof(identity->hashPubKey.bits),
+ ctx,
+ sizeof(ctx), NULL);
+}
+
+/**
+ * Derive an IV from pong packet information
+ */
+static void
+derive_pong_iv (struct GNUNET_CRYPTO_AesInitializationVector *iv,
+ const struct GNUNET_CRYPTO_AesSessionKey *skey, uint32_t seed,
+ uint32_t challenge, const struct GNUNET_PeerIdentity *identity)
+{
+ static const char ctx[] = "pong initialization vector";
+
+ GNUNET_CRYPTO_aes_derive_iv (iv,
+ skey,
+ &seed,
+ sizeof(seed),
+ &identity->hashPubKey.bits,
+ sizeof(identity->hashPubKey.bits),
+ &challenge,
+ sizeof(challenge),
+ ctx,
+ sizeof(ctx), NULL);
+}
+
+
+/**
+ * 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);
+}
/**
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)
+ if ( (! n->is_connected) ||
+ (n->status != PEER_STATE_KEY_CONFIRMED) )
return;
#if DEBUG_CORE
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"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.distance = htonl (n->last_distance);
- psnm.latency = GNUNET_TIME_relative_hton (n->last_latency);
- 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,
GNUNET_NO);
}
+
/**
- * Handle CORE_ITERATE_PEERS request.
+ * Go over our message queue and if it is not too long, go
+ * over the pending requests from clients for this
+ * neighbour and send some clients a 'READY' notification.
+ *
+ * @param n which peer to process
*/
static void
-handle_client_iterate_peers (void *cls,
- struct GNUNET_SERVER_Client *client,
- const struct GNUNET_MessageHeader *message)
+schedule_peer_messages (struct Neighbour *n)
{
- struct Neighbour *n;
- struct ConnectNotifyMessage cnm;
- struct GNUNET_MessageHeader done_msg;
- struct GNUNET_SERVER_TransmitContext *tc;
-
- /* notify new client about existing neighbours */
- cnm.header.size = htons (sizeof (struct ConnectNotifyMessage));
- cnm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT);
- done_msg.size = htons (sizeof (struct GNUNET_MessageHeader));
- done_msg.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT);
- tc = GNUNET_SERVER_transmit_context_create (client);
- n = neighbours;
- while (n != NULL)
+ struct SendMessageReady smr;
+ struct ClientActiveRequest *car;
+ struct ClientActiveRequest *pos;
+ struct Client *c;
+ struct MessageEntry *mqe;
+ 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->status == PEER_STATE_KEY_CONFIRMED)
- {
#if DEBUG_CORE_CLIENT
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Sending `%s' message to client.\n", "NOTIFY_CONNECT");
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Not considering client transmission requests: queue full\n");
#endif
- cnm.distance = htonl (n->last_distance);
- cnm.latency = GNUNET_TIME_relative_hton (n->last_latency);
- cnm.peer = n->peer;
- GNUNET_SERVER_transmit_context_append_message (tc, &cnm.header);
- /*send_to_client (c, &cnm.header, GNUNET_NO);*/
- }
- n = n->next;
+ 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;
+ }
+ if (car == NULL)
+ return; /* no pending requests */
+#if DEBUG_CORE_CLIENT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Permitting client transmission request to `%s'\n",
+ GNUNET_i2s (&n->peer));
+#endif
+ c = car->client;
+ 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);
+ smr.header.size = htons (sizeof (struct SendMessageReady));
+ smr.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_SEND_READY);
+ smr.size = htons (car->msize);
+ smr.smr_id = car->smr_id;
+ smr.peer = n->peer;
+ send_to_client (c, &smr.header, GNUNET_NO);
+ GNUNET_free (car);
+}
- GNUNET_SERVER_transmit_context_append_message (tc, &done_msg);
- GNUNET_SERVER_transmit_context_run (tc,
- GNUNET_TIME_UNIT_FOREVER_REL);
+
+/**
+ * Handle CORE_SEND_REQUEST message.
+ */
+static void
+handle_client_send_request (void *cls,
+ struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ const struct SendMessageRequest *req;
+ struct Neighbour *n;
+ struct Client *c;
+ struct ClientActiveRequest *car;
+
+ req = (const struct SendMessageRequest*) message;
+ n = find_neighbour (&req->peer);
+ if ( (n == NULL) ||
+ (GNUNET_YES != n->is_connected) ||
+ (n->status != PEER_STATE_KEY_CONFIRMED) )
+ {
+ /* neighbour must have disconnected since request was issued,
+ ignore (client will realize it once it processes the
+ disconnect notification) */
+#if DEBUG_CORE_CLIENT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Dropped client request for transmission (am disconnected)\n");
+#endif
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# send requests dropped (disconnected)"),
+ 1,
+ GNUNET_NO);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ return;
+ }
+ c = clients;
+ while ( (c != NULL) &&
+ (c->client_handle != client) )
+ c = c->next;
+ if (c == NULL)
+ {
+ /* client did not send INIT first! */
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ if (c->requests == NULL)
+ c->requests = GNUNET_CONTAINER_multihashmap_create (16);
+#if DEBUG_CORE_CLIENT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Received client transmission request. queueing\n");
+#endif
+ car = GNUNET_CONTAINER_multihashmap_get (c->requests,
+ &req->peer.hashPubKey);
+ if (car == NULL)
+ {
+ /* create new entry */
+ car = GNUNET_malloc (sizeof (struct ClientActiveRequest));
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CONTAINER_multihashmap_put (c->requests,
+ &req->peer.hashPubKey,
+ car,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
+ GNUNET_CONTAINER_DLL_insert (n->active_client_request_head,
+ n->active_client_request_tail,
+ car);
+ car->client = c;
+ }
+ car->deadline = GNUNET_TIME_absolute_ntoh (req->deadline);
+ car->priority = ntohl (req->priority);
+ car->queue_size = ntohl (req->queue_size);
+ car->msize = ntohs (req->size);
+ car->smr_id = req->smr_id;
+ schedule_peer_messages (n);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
}
const uint16_t *types;
uint16_t *wtypes;
struct Neighbour *n;
- struct ConnectNotifyMessage cnm;
+ struct ConnectNotifyMessage *cnm;
+ char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1];
+ struct GNUNET_TRANSPORT_ATS_Information *ats;
+ size_t size;
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);
n = neighbours;
while (n != NULL)
{
+ 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.distance = htonl (n->last_distance);
- cnm.latency = GNUNET_TIME_relative_hton (n->last_latency);
- cnm.peer = n->peer;
- send_to_client (c, &cnm.header, GNUNET_NO);
+ cnm->peer = n->peer;
+ send_to_client (c, &cnm->header, GNUNET_NO);
}
n = n->next;
}
}
+/**
+ * Free client request records.
+ *
+ * @param cls NULL
+ * @param key identity of peer for which this is an active request
+ * @param value the 'struct ClientActiveRequest' to free
+ * @return GNUNET_YES (continue iteration)
+ */
+static int
+destroy_active_client_request (void *cls,
+ const GNUNET_HashCode *key,
+ void *value)
+{
+ struct ClientActiveRequest *car = value;
+ struct Neighbour *n;
+ struct GNUNET_PeerIdentity peer;
+
+ peer.hashPubKey = *key;
+ n = find_neighbour (&peer);
+ GNUNET_CONTAINER_DLL_remove (n->active_client_request_head,
+ n->active_client_request_tail,
+ car);
+ GNUNET_free (car);
+ return GNUNET_YES;
+}
+
+
/**
* A client disconnected, clean up.
*
while (pos != NULL)
{
if (client == pos->client_handle)
- {
- if (prev == NULL)
- clients = pos->next;
- else
- prev->next = pos->next;
- GNUNET_free (pos);
- return;
- }
+ break;
prev = pos;
pos = pos->next;
}
- /* client never sent INIT */
+ if (pos == NULL)
+ {
+ /* client never sent INIT */
+ return;
+ }
+ if (prev == NULL)
+ clients = pos->next;
+ else
+ prev->next = pos->next;
+ if (pos->requests != NULL)
+ {
+ GNUNET_CONTAINER_multihashmap_iterate (pos->requests,
+ &destroy_active_client_request,
+ NULL);
+ GNUNET_CONTAINER_multihashmap_destroy (pos->requests);
+ }
+ GNUNET_free (pos);
+}
+
+
+/**
+ * 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 Neighbour *n;
+ struct ConnectNotifyMessage *cnm;
+ struct GNUNET_MessageHeader done_msg;
+ struct GNUNET_SERVER_TransmitContext *tc;
+ char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1];
+ struct GNUNET_TRANSPORT_ATS_Information *ats;
+ size_t size;
+
+ /* notify new client about existing neighbours */
+ tc = GNUNET_SERVER_transmit_context_create (client);
+ cnm = (struct ConnectNotifyMessage*) buf;
+ n = neighbours;
+ while (n != NULL)
+ {
+ if (n->status == PEER_STATE_KEY_CONFIRMED)
+ {
+ 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);
+ }
+ n = n->next;
+ }
+ 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);
}
const struct GNUNET_MessageHeader *message)
{
const struct RequestInfoMessage *rcm;
+ struct Client *pos;
struct Neighbour *n;
struct ConfigurationInfoMessage cim;
int32_t want_reserv;
int32_t got_reserv;
unsigned long long old_preference;
- struct GNUNET_SERVER_TransmitContext *tc;
#if DEBUG_CORE_CLIENT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Core service receives `%s' request.\n", "REQUEST_INFO");
#endif
+ pos = clients;
+ while (pos != NULL)
+ {
+ if (client == pos->client_handle)
+ break;
+ pos = pos->next;
+ }
+ if (pos == NULL)
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+
rcm = (const struct RequestInfoMessage *) message;
n = find_neighbour (&rcm->peer);
memset (&cim, 0, sizeof (cim));
else if (want_reserv > 0)
{
if (GNUNET_BANDWIDTH_tracker_get_delay (&n->available_recv_window,
- want_reserv).value == 0)
+ want_reserv).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.bw_in = n->bw_in;
+ cim.rim_id = rcm->rim_id;
cim.bw_out = n->bw_out;
cim.preference = n->current_preference;
}
cim.header.size = htons (sizeof (struct ConfigurationInfoMessage));
cim.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_CONFIGURATION_INFO);
cim.peer = rcm->peer;
-
#if DEBUG_CORE_CLIENT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Sending `%s' message to client.\n", "CONFIGURATION_INFO");
#endif
- tc = GNUNET_SERVER_transmit_context_create (client);
- GNUNET_SERVER_transmit_context_append_message (tc, &cim.header);
- GNUNET_SERVER_transmit_context_run (tc,
- GNUNET_TIME_UNIT_FOREVER_REL);
+ send_to_client (pos, &cim.header, GNUNET_NO);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
}
free_neighbour (struct Neighbour *n)
{
struct MessageEntry *m;
+ struct ClientActiveRequest *car;
#if DEBUG_CORE
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
m);
GNUNET_free (m);
}
+ while (NULL != (car = n->active_client_request_head))
+ {
+ GNUNET_CONTAINER_DLL_remove (n->active_client_request_head,
+ n->active_client_request_tail,
+ car);
+ GNUNET_CONTAINER_multihashmap_remove (car->client->requests,
+ &n->peer.hashPubKey,
+ car);
+ GNUNET_free (car);
+ }
if (NULL != n->th)
{
GNUNET_TRANSPORT_notify_transmit_ready_cancel (n->th);
n->th = NULL;
}
if (n->retry_plaintext_task != GNUNET_SCHEDULER_NO_TASK)
- GNUNET_SCHEDULER_cancel (sched, n->retry_plaintext_task);
+ GNUNET_SCHEDULER_cancel (n->retry_plaintext_task);
if (n->retry_set_key_task != GNUNET_SCHEDULER_NO_TASK)
- GNUNET_SCHEDULER_cancel (sched, n->retry_set_key_task);
+ GNUNET_SCHEDULER_cancel (n->retry_set_key_task);
if (n->quota_update_task != GNUNET_SCHEDULER_NO_TASK)
- GNUNET_SCHEDULER_cancel (sched, n->quota_update_task);
+ GNUNET_SCHEDULER_cancel (n->quota_update_task);
if (n->dead_clean_task != GNUNET_SCHEDULER_NO_TASK)
- GNUNET_SCHEDULER_cancel (sched, n->dead_clean_task);
+ GNUNET_SCHEDULER_cancel (n->dead_clean_task);
if (n->keep_alive_task != GNUNET_SCHEDULER_NO_TASK)
- GNUNET_SCHEDULER_cancel (sched, n->keep_alive_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_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);
*/
static int
do_encrypt (struct Neighbour *n,
- const GNUNET_HashCode * iv,
+ const struct GNUNET_CRYPTO_AesInitializationVector * iv,
const void *in, void *out, size_t size)
{
if (size != (uint16_t) size)
GNUNET_CRYPTO_aes_encrypt (in,
(uint16_t) size,
&n->encrypt_key,
- (const struct
- GNUNET_CRYPTO_AesInitializationVector
- *) iv, out));
+ iv, out));
GNUNET_STATISTICS_update (stats, gettext_noop ("# bytes encrypted"), size, GNUNET_NO);
#if DEBUG_CORE
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Encrypted %u bytes for `%4s' using key %u\n",
+ "Encrypted %u bytes for `%4s' using key %u, IV %u\n",
(unsigned int) size,
GNUNET_i2s (&n->peer),
- (unsigned int) n->encrypt_key.crc32);
+ (unsigned int) n->encrypt_key.crc32,
+ GNUNET_CRYPTO_crc32_n (iv, sizeof(iv)));
#endif
return GNUNET_OK;
}
struct MessageEntry *me;
struct PingMessage pp;
struct PingMessage *pm;
+ struct GNUNET_CRYPTO_AesInitializationVector iv;
n->keep_alive_task = GNUNET_SCHEDULER_NO_TASK;
/* send PING */
pm = (struct PingMessage *) &me[1];
pm->header.size = htons (sizeof (struct PingMessage));
pm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_PING);
- pp.challenge = htonl (n->ping_challenge);
+ pm->iv_seed = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
+ UINT32_MAX);
+ derive_iv (&iv, &n->encrypt_key, pm->iv_seed, &n->peer);
+ pp.challenge = n->ping_challenge;
pp.target = n->peer;
#if DEBUG_HANDSHAKE
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Encrypting `%s' message with challenge %u for `%4s' using key %u.\n",
+ "Encrypting `%s' message with challenge %u for `%4s' using key %u, IV %u (salt %u).\n",
"PING",
(unsigned int) n->ping_challenge,
GNUNET_i2s (&n->peer),
- (unsigned int) n->encrypt_key.crc32);
+ (unsigned int) n->encrypt_key.crc32,
+ GNUNET_CRYPTO_crc32_n (&iv, sizeof(iv)),
+ pm->iv_seed);
#endif
do_encrypt (n,
- &n->peer.hashPubKey,
- &pp.challenge,
- &pm->challenge,
+ &iv,
+ &pp.target,
+ &pm->target,
sizeof (struct PingMessage) -
- sizeof (struct GNUNET_MessageHeader));
+ ((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
- = GNUNET_SCHEDULER_add_delayed (sched,
- retry,
+ = GNUNET_SCHEDULER_add_delayed (retry,
&send_keep_alive,
n);
(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));
- if (left.value > 0)
+ left = GNUNET_TIME_absolute_get_remaining (get_neighbour_timeout (n));
+ if (left.rel_value > 0)
{
if (n->dead_clean_task != GNUNET_SCHEDULER_NO_TASK)
- GNUNET_SCHEDULER_cancel (sched, n->dead_clean_task);
- n->dead_clean_task = GNUNET_SCHEDULER_add_delayed (sched,
- left,
+ GNUNET_SCHEDULER_cancel (n->dead_clean_task);
+ n->dead_clean_task = GNUNET_SCHEDULER_add_delayed (left,
&consider_free_task,
n);
return;
"Asking transport for transmission of %u bytes to `%4s' in next %llu ms\n",
(unsigned int) m->size,
GNUNET_i2s (&n->peer),
- (unsigned long long) GNUNET_TIME_absolute_get_remaining (m->deadline).
- value);
+ (unsigned long long) GNUNET_TIME_absolute_get_remaining (m->deadline).rel_value);
#endif
n->th =
GNUNET_TRANSPORT_notify_transmit_ready (transport, &n->peer,
*/
static int
do_decrypt (struct Neighbour *n,
- const GNUNET_HashCode * iv,
+ const struct GNUNET_CRYPTO_AesInitializationVector * iv,
const void *in, void *out, size_t size)
{
if (size != (uint16_t) size)
GNUNET_CRYPTO_aes_decrypt (in,
(uint16_t) size,
&n->decrypt_key,
- (const struct
- GNUNET_CRYPTO_AesInitializationVector *) iv,
+ iv,
out))
{
GNUNET_break (0);
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\n",
+ "Decrypted %u bytes from `%4s' using key %u, IV %u\n",
(unsigned int) size,
GNUNET_i2s (&n->peer),
- (unsigned int) n->decrypt_key.crc32);
+ (unsigned int) n->decrypt_key.crc32,
+ GNUNET_CRYPTO_crc32_n (iv, sizeof(*iv)));
#endif
return GNUNET_OK;
}
if (discard_low_prio == GNUNET_NO)
{
delta = GNUNET_TIME_absolute_get_difference (t, pos->deadline);
- if (delta.value > 0)
+ if (delta.rel_value > 0)
{
// FIXME: HUH? Check!
t = pos->deadline;
slack = GNUNET_TIME_relative_min (slack,
GNUNET_BANDWIDTH_value_get_delay_for (n->bw_out,
avail));
- if (pos->deadline.value <= now.value)
+ if (pos->deadline.abs_value <= now.abs_value)
{
/* now or never */
slack = GNUNET_TIME_UNIT_ZERO;
}
/* guard against sending "tiny" messages with large headers without
urgent deadlines */
- if ( (slack.value > GNUNET_CONSTANTS_MAX_CORK_DELAY.value) &&
+ if ( (slack.rel_value > GNUNET_CONSTANTS_MAX_CORK_DELAY.rel_value) &&
(size > 4 * off) &&
(queue_size <= MAX_PEER_QUEUE_SIZE - 2) )
{
pos->do_transmit = GNUNET_NO;
pos = pos->next;
}
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# transmissions delayed due to corking"),
+ 1, GNUNET_NO);
#if DEBUG_CORE
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Deferring transmission for %llums due to underfull message buffer size (%u/%u)\n",
- (unsigned long long) retry_time->value,
+ (unsigned long long) retry_time->rel_value,
(unsigned int) off,
(unsigned int) size);
#endif
#if DEBUG_CORE
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"No messages selected, will try again in %llu ms\n",
- retry_time->value);
+ retry_time->rel_value);
#endif
return 0;
}
ntm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_OUTBOUND);
- ntm->distance = htonl (n->last_distance);
- ntm->latency = GNUNET_TIME_relative_hton (n->last_latency);
+ ntm->ats_count = htonl (0);
+ ntm->ats.type = htonl (0);
+ ntm->ats.value = htonl (0);
ntm->peer = n->peer;
pos = n->messages;
prev = NULL;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Adding plaintext message of size %u with deadline %llu ms to batch\n",
(unsigned int) pos->size,
- (unsigned long long) GNUNET_TIME_absolute_get_remaining (pos->deadline).value);
+ (unsigned long long) GNUNET_TIME_absolute_get_remaining (pos->deadline).rel_value);
#endif
- deadline->value = GNUNET_MIN (deadline->value, pos->deadline.value);
+ deadline->abs_value = GNUNET_MIN (deadline->abs_value, pos->deadline.abs_value);
GNUNET_free (pos);
if (prev == NULL)
n->messages = next;
#if DEBUG_CORE
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Deadline for message batch is %llu ms\n",
- GNUNET_TIME_absolute_get_remaining (*deadline).value);
+ GNUNET_TIME_absolute_get_remaining (*deadline).rel_value);
#endif
return ret;
}
struct MessageEntry *pos;
struct GNUNET_TIME_Absolute now;
struct GNUNET_TIME_Relative delta;
+ int disc;
+ disc = GNUNET_NO;
now = GNUNET_TIME_absolute_get ();
prev = NULL;
pos = n->messages;
{
next = pos->next;
delta = GNUNET_TIME_absolute_get_difference (pos->deadline, now);
- if (delta.value > PAST_EXPIRATION_DISCARD_TIME.value)
+ if (delta.rel_value > PAST_EXPIRATION_DISCARD_TIME.rel_value)
{
#if DEBUG_CORE
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Message is %llu ms past due, discarding.\n",
- delta.value);
+ delta.rel_value);
#endif
if (prev == NULL)
n->messages = next;
else
prev->next = next;
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# messages discarded (expired prior to transmission)"),
+ 1,
+ GNUNET_NO);
+ disc = GNUNET_YES;
GNUNET_free (pos);
}
else
prev = pos;
pos = next;
}
+ if (GNUNET_YES == disc)
+ schedule_peer_messages (n);
}
{
char pbuf[GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE + sizeof (struct EncryptedMessage)]; /* plaintext */
size_t used;
- size_t esize;
struct EncryptedMessage *em; /* encrypted message */
struct EncryptedMessage *ph; /* plaintext header */
struct MessageEntry *me;
unsigned int priority;
struct GNUNET_TIME_Absolute deadline;
struct GNUNET_TIME_Relative retry_time;
- GNUNET_HashCode iv;
+ struct GNUNET_CRYPTO_AesInitializationVector iv;
+ struct GNUNET_CRYPTO_AuthKey auth_key;
if (n->retry_plaintext_task != GNUNET_SCHEDULER_NO_TASK)
{
- GNUNET_SCHEDULER_cancel (sched, n->retry_plaintext_task);
+ GNUNET_SCHEDULER_cancel (n->retry_plaintext_task);
n->retry_plaintext_task = GNUNET_SCHEDULER_NO_TASK;
}
switch (n->status)
case PEER_STATE_KEY_SENT:
if (n->retry_set_key_task == GNUNET_SCHEDULER_NO_TASK)
n->retry_set_key_task
- = GNUNET_SCHEDULER_add_delayed (sched,
- n->set_key_retry_frequency,
+ = GNUNET_SCHEDULER_add_delayed (n->set_key_retry_frequency,
&set_key_retry_task, n);
#if DEBUG_CORE
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
case PEER_STATE_KEY_RECEIVED:
if (n->retry_set_key_task == GNUNET_SCHEDULER_NO_TASK)
n->retry_set_key_task
- = GNUNET_SCHEDULER_add_delayed (sched,
- n->set_key_retry_frequency,
+ = GNUNET_SCHEDULER_add_delayed (n->set_key_retry_frequency,
&set_key_retry_task, n);
#if DEBUG_CORE
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
#endif
/* no messages selected for sending, try again later... */
n->retry_plaintext_task =
- GNUNET_SCHEDULER_add_delayed (sched,
- retry_time,
+ GNUNET_SCHEDULER_add_delayed (retry_time,
&retry_plaintext_processing, n);
return;
}
(unsigned int) ntohl (n->bw_in.value__),
GNUNET_i2s (&n->peer));
#endif
- ph->iv_seed = htonl (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX));
+ ph->iv_seed = htonl (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX));
ph->sequence_number = htonl (++n->last_sequence_number_sent);
ph->inbound_bw_limit = n->bw_in;
ph->timestamp = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
em->header.size = htons (used);
em->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_ENCRYPTED_MESSAGE);
em->iv_seed = ph->iv_seed;
- esize = used - ENCRYPTED_HEADER_SIZE;
- GNUNET_CRYPTO_hmac (&n->encrypt_key,
- &ph->sequence_number,
- esize - sizeof (GNUNET_HashCode),
- &ph->hmac);
- GNUNET_CRYPTO_hash (&ph->iv_seed, sizeof (uint32_t), &iv);
-#if DEBUG_HANDSHAKE
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Hashed %u bytes of plaintext (`%s') using IV `%d'\n",
- (unsigned int) (esize - sizeof (GNUNET_HashCode)),
- GNUNET_h2s (&ph->hmac),
- (int) ph->iv_seed);
-#endif
+ derive_iv (&iv, &n->encrypt_key, ph->iv_seed, &n->peer);
/* encrypt */
#if DEBUG_HANDSHAKE
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Encrypting %u bytes of plaintext messages for `%4s' for transmission in %llums.\n",
- (unsigned int) esize,
+ (unsigned int) used - ENCRYPTED_HEADER_SIZE,
GNUNET_i2s(&n->peer),
- (unsigned long long) GNUNET_TIME_absolute_get_remaining (deadline).value);
+ (unsigned long long) GNUNET_TIME_absolute_get_remaining (deadline).rel_value);
#endif
GNUNET_assert (GNUNET_OK ==
do_encrypt (n,
&iv,
- &ph->hmac,
- &em->hmac, esize));
+ &ph->sequence_number,
+ &em->sequence_number, used - ENCRYPTED_HEADER_SIZE));
+ derive_auth_key (&auth_key,
+ &n->encrypt_key,
+ ph->iv_seed,
+ n->encrypt_key_created);
+ GNUNET_CRYPTO_hmac (&auth_key,
+ &em->sequence_number,
+ used - ENCRYPTED_HEADER_SIZE,
+ &em->hmac);
+#if DEBUG_HANDSHAKE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Authenticated %u bytes of ciphertext %u: `%s'\n",
+ used - ENCRYPTED_HEADER_SIZE,
+ GNUNET_CRYPTO_crc32_n (&em->sequence_number,
+ used - ENCRYPTED_HEADER_SIZE),
+ GNUNET_h2s (&em->hmac));
+#endif
/* append to transmission list */
GNUNET_CONTAINER_DLL_insert_after (n->encrypted_head,
n->encrypted_tail,
n->encrypted_tail,
me);
process_encrypted_neighbour_queue (n);
+ schedule_peer_messages (n);
}
GNUNET_assert (n->quota_update_task ==
GNUNET_SCHEDULER_NO_TASK);
n->quota_update_task
- = GNUNET_SCHEDULER_add_delayed (sched,
- QUOTA_UPDATE_FREQUENCY,
+ = GNUNET_SCHEDULER_add_delayed (QUOTA_UPDATE_FREQUENCY,
&neighbour_quota_update,
n);
}
n->bw_out = GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT;
n->bw_out_internal_limit = GNUNET_BANDWIDTH_value_init (UINT32_MAX);
n->bw_out_external_limit = GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT;
- n->ping_challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
+ n->ping_challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
UINT32_MAX);
neighbour_quota_update (n, NULL);
consider_free_neighbour (n);
(unsigned int) msize,
GNUNET_i2s (&sm->peer));
#endif
- /* bound queue size */
discard_expired_messages (n);
+ /* bound queue size */
+ /* NOTE: this entire block to bound the queue size should be
+ obsolete with the new client-request code and the
+ 'schedule_peer_messages' mechanism; we still have this code in
+ here for now as a sanity check for the new mechanmism;
+ ultimately, we should probably simply reject SEND messages that
+ are not 'approved' (or provide a new core API for very unreliable
+ delivery that always sends with priority 0). Food for thought. */
min_prio = UINT32_MAX;
min_prio_entry = NULL;
min_prio_prev = NULL;
/* queue full */
if (ntohl(sm->priority) <= min_prio)
{
- /* discard new entry */
+ /* discard new entry; this should no longer happen! */
+ GNUNET_break (0);
#if DEBUG_CORE
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Queue full (%u/%u), discarding new request (%u bytes of type %u)\n",
(unsigned int) msize,
(unsigned int) ntohs (message->type));
#endif
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# discarded CORE_SEND requests"),
+ 1, GNUNET_NO);
+
if (client != NULL)
GNUNET_SERVER_receive_done (client, GNUNET_OK);
return;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Queue full, discarding existing older request\n");
#endif
+ GNUNET_STATISTICS_update (stats, gettext_noop ("# discarded lower priority CORE_SEND requests"), 1, GNUNET_NO);
if (min_prio_prev == NULL)
n->messages = min_prio_entry->next;
else
/* insert, keep list sorted by deadline */
prev = NULL;
pos = n->messages;
- while ((pos != NULL) && (pos->deadline.value < e->deadline.value))
+ while ((pos != NULL) && (pos->deadline.abs_value < e->deadline.abs_value))
{
prev = pos;
pos = pos->next;
{
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! */
- GNUNET_break (0);
+#if DEBUG_CORE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Timeout on notify connect!\n");
+#endif
return 0;
}
- n->th = NULL;
if (buf == NULL)
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
_("TRANSPORT connection to peer `%4s' is up, trying to establish CORE connection\n"),
GNUNET_i2s (&n->peer));
if (n->retry_set_key_task != GNUNET_SCHEDULER_NO_TASK)
- GNUNET_SCHEDULER_cancel (sched,
- n->retry_set_key_task);
- n->retry_set_key_task = GNUNET_SCHEDULER_add_now (sched,
- &set_key_retry_task,
+ GNUNET_SCHEDULER_cancel (n->retry_set_key_task);
+ n->retry_set_key_task = GNUNET_SCHEDULER_add_now (&set_key_retry_task,
n);
return 0;
}
{
if (n->retry_set_key_task != GNUNET_SCHEDULER_NO_TASK)
{
- GNUNET_SCHEDULER_cancel (sched, n->retry_set_key_task);
+ GNUNET_SCHEDULER_cancel (n->retry_set_key_task);
n->retry_set_key_task = GNUNET_SCHEDULER_NO_TASK;
}
GNUNET_STATISTICS_update (stats,
GNUNET_NO);
if (GNUNET_SCHEDULER_NO_TASK == n->retry_set_key_task)
n->retry_set_key_task
- = GNUNET_SCHEDULER_add_delayed (sched,
- n->set_key_retry_frequency,
+ = GNUNET_SCHEDULER_add_delayed (n->set_key_retry_frequency,
&set_key_retry_task, n);
}
return;
struct MessageEntry *me;
struct PingMessage pp;
struct PingMessage *pm;
+ struct GNUNET_CRYPTO_AesInitializationVector iv;
if (n->retry_set_key_task != GNUNET_SCHEDULER_NO_TASK)
{
- GNUNET_SCHEDULER_cancel (sched, n->retry_set_key_task);
+ GNUNET_SCHEDULER_cancel (n->retry_set_key_task);
n->retry_set_key_task = GNUNET_SCHEDULER_NO_TASK;
}
if (n->pitr != NULL)
pm = (struct PingMessage *) &sm[1];
pm->header.size = htons (sizeof (struct PingMessage));
pm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_PING);
- pp.challenge = htonl (n->ping_challenge);
+ pm->iv_seed = GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX);
+ derive_iv (&iv, &n->encrypt_key, pm->iv_seed, &n->peer);
+ pp.challenge = n->ping_challenge;
pp.target = n->peer;
#if DEBUG_HANDSHAKE
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Encrypting `%s' and `%s' messages with challenge %u for `%4s' using key %u.\n",
+ "Encrypting `%s' and `%s' messages with challenge %u for `%4s' using key %u, IV %u (salt %u).\n",
"SET_KEY", "PING",
(unsigned int) n->ping_challenge,
GNUNET_i2s (&n->peer),
- (unsigned int) n->encrypt_key.crc32);
+ (unsigned int) n->encrypt_key.crc32,
+ GNUNET_CRYPTO_crc32_n (&iv, sizeof(iv)),
+ pm->iv_seed);
#endif
do_encrypt (n,
- &n->peer.hashPubKey,
- &pp.challenge,
- &pm->challenge,
+ &iv,
+ &pp.target,
+ &pm->target,
sizeof (struct PingMessage) -
- sizeof (struct GNUNET_MessageHeader));
+ ((void *) &pm->target - (void *) pm));
GNUNET_STATISTICS_update (stats,
gettext_noop ("# SET_KEY and PING messages created"),
1,
#if DEBUG_CORE
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Have %llu ms left for `%s' transmission.\n",
- (unsigned long long) GNUNET_TIME_absolute_get_remaining (me->deadline).value,
+ (unsigned long long) GNUNET_TIME_absolute_get_remaining (me->deadline).rel_value,
"SET_KEY");
#endif
trigger_processing:
if ( (n->status != PEER_STATE_KEY_CONFIRMED) &&
(GNUNET_SCHEDULER_NO_TASK == n->retry_set_key_task) )
n->retry_set_key_task
- = GNUNET_SCHEDULER_add_delayed (sched,
- n->set_key_retry_frequency,
+ = GNUNET_SCHEDULER_add_delayed (n->set_key_retry_frequency,
&set_key_retry_task, n);
}
*
* @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);
+
/**
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;
struct PongMessage *tp;
struct MessageEntry *me;
+ struct GNUNET_CRYPTO_AesInitializationVector iv;
#if DEBUG_CORE
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Core service receives `%s' request from `%4s'.\n",
"PING", GNUNET_i2s (&n->peer));
#endif
+ derive_iv (&iv, &n->decrypt_key, m->iv_seed, &my_identity);
if (GNUNET_OK !=
do_decrypt (n,
- &my_identity.hashPubKey,
- &m->challenge,
- &t.challenge,
+ &iv,
+ &m->target,
+ &t.target,
sizeof (struct PingMessage) -
- sizeof (struct GNUNET_MessageHeader)))
+ ((void *) &m->target - (void *) m)))
return;
#if DEBUG_HANDSHAKE
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Decrypted `%s' to `%4s' with challenge %u decrypted using key %u\n",
+ "Decrypted `%s' to `%4s' with challenge %u decrypted using key %u, IV %u (salt %u)\n",
"PING",
GNUNET_i2s (&t.target),
- (unsigned int) ntohl (t.challenge),
- (unsigned int) n->decrypt_key.crc32);
+ (unsigned int) t.challenge,
+ (unsigned int) n->decrypt_key.crc32,
+ GNUNET_CRYPTO_crc32_n (&iv, sizeof(iv)),
+ m->iv_seed);
#endif
GNUNET_STATISTICS_update (stats,
gettext_noop ("# PING messages decrypted"),
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,
me->deadline = GNUNET_TIME_relative_to_absolute (MAX_PONG_DELAY);
me->priority = PONG_PRIORITY;
me->size = sizeof (struct PongMessage);
- tx.reserved = htonl (0);
tx.inbound_bw_limit = n->bw_in;
tx.challenge = t.challenge;
tx.target = t.target;
tp = (struct PongMessage *) &me[1];
tp->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_PONG);
tp->header.size = htons (sizeof (struct PongMessage));
+ tp->iv_seed = GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX);
+ derive_pong_iv (&iv, &n->encrypt_key, tp->iv_seed, t.challenge, &n->peer);
do_encrypt (n,
- &my_identity.hashPubKey,
+ &iv,
&tx.challenge,
&tp->challenge,
sizeof (struct PongMessage) -
- sizeof (struct GNUNET_MessageHeader));
+ ((void *) &tp->challenge - (void *) tp));
GNUNET_STATISTICS_update (stats,
gettext_noop ("# PONG messages created"),
1,
GNUNET_NO);
#if DEBUG_HANDSHAKE
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Encrypting `%s' with challenge %u using key %u\n",
+ "Encrypting `%s' with challenge %u using key %u, IV %u (salt %u)\n",
"PONG",
- (unsigned int) ntohl (t.challenge),
- (unsigned int) n->encrypt_key.crc32);
+ (unsigned int) t.challenge,
+ (unsigned int) n->encrypt_key.crc32,
+ GNUNET_CRYPTO_crc32_n (&iv, sizeof(iv)),
+ tp->iv_seed);
#endif
/* trigger queue processing */
process_encrypted_neighbour_queue (n);
*
* @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,
#endif
/* mark as garbage, just to be sure */
memset (&t, 255, sizeof (t));
+ derive_pong_iv (&iv, &n->decrypt_key, m->iv_seed, n->ping_challenge,
+ &my_identity);
if (GNUNET_OK !=
do_decrypt (n,
- &n->peer.hashPubKey,
+ &iv,
&m->challenge,
&t.challenge,
sizeof (struct PongMessage) -
- sizeof (struct GNUNET_MessageHeader)))
+ ((void *) &m->challenge - (void *) m)))
{
GNUNET_break_op (0);
return;
gettext_noop ("# PONG messages decrypted"),
1,
GNUNET_NO);
- if (0 != ntohl (t.reserved))
- {
- GNUNET_break_op (0);
- return;
- }
#if DEBUG_HANDSHAKE
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Decrypted `%s' from `%4s' with challenge %u using key %u\n",
+ "Decrypted `%s' from `%4s' with challenge %u using key %u, IV %u (salt %u)\n",
"PONG",
GNUNET_i2s (&t.target),
- (unsigned int) ntohl (t.challenge),
- (unsigned int) n->decrypt_key.crc32);
+ (unsigned int) t.challenge,
+ (unsigned int) n->decrypt_key.crc32,
+ GNUNET_CRYPTO_crc32_n (&iv, sizeof(iv)),
+ m->iv_seed);
#endif
if ((0 != memcmp (&t.target,
&n->peer,
sizeof (struct GNUNET_PeerIdentity))) ||
- (n->ping_challenge != ntohl (t.challenge)))
+ (n->ping_challenge != t.challenge))
{
/* PONG malformed */
#if DEBUG_CORE
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Received malformed `%s' received from `%4s' with challenge %u\n",
"PONG", GNUNET_i2s (&t.target),
- (unsigned int) ntohl (t.challenge));
+ (unsigned int) t.challenge);
#endif
- GNUNET_break_op (0);
+ GNUNET_break_op (n->ping_challenge != t.challenge);
return;
}
switch (n->status)
#endif
if (n->retry_set_key_task != GNUNET_SCHEDULER_NO_TASK)
{
- GNUNET_SCHEDULER_cancel (sched, n->retry_set_key_task);
+ 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.distance = htonl (n->last_distance);
- cnm.latency = GNUNET_TIME_relative_hton (n->last_latency);
- cnm.peer = n->peer;
- send_to_all_clients (&cnm.header, GNUNET_YES, 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:
n->last_activity = GNUNET_TIME_absolute_get ();
if (n->keep_alive_task != GNUNET_SCHEDULER_NO_TASK)
- GNUNET_SCHEDULER_cancel (sched, n->keep_alive_task);
+ GNUNET_SCHEDULER_cancel (n->keep_alive_task);
n->keep_alive_task
- = GNUNET_SCHEDULER_add_delayed (sched,
- GNUNET_TIME_relative_divide (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, 2),
+ = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, 2),
&send_keep_alive,
n);
handle_peer_status_change (n);
*
* @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;
t = GNUNET_TIME_absolute_ntoh (m->creation_time);
if (((n->status == PEER_STATE_KEY_RECEIVED) ||
(n->status == PEER_STATE_KEY_CONFIRMED)) &&
- (t.value < n->decrypt_key_created.value))
+ (t.abs_value < n->decrypt_key_created.abs_value))
{
/* this could rarely happen due to massive re-ordering of
messages on the network level, but is most likely either
1,
GNUNET_NO);
n->decrypt_key = k;
- if (n->decrypt_key_created.value != t.value)
+ if (n->decrypt_key_created.abs_value != t.abs_value)
{
/* fresh key, reset sequence numbers */
n->last_sequence_number_received = 0;
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->distance = htonl (sender->last_distance);
- ntm->latency = GNUNET_TIME_relative_hton (sender->last_latency);
+ 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];
GNUNET_HashCode ph;
uint32_t snum;
struct GNUNET_TIME_Absolute t;
- GNUNET_HashCode iv;
+ struct GNUNET_CRYPTO_AesInitializationVector iv;
+ struct GNUNET_CRYPTO_AuthKey auth_key;
#if DEBUG_CORE
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Core service receives `%s' request from `%4s'.\n",
"ENCRYPTED_MESSAGE", GNUNET_i2s (&n->peer));
#endif
- GNUNET_CRYPTO_hash (&m->iv_seed, sizeof (uint32_t), &iv);
- /* decrypt */
- if (GNUNET_OK !=
- do_decrypt (n,
- &iv,
- &m->hmac,
- &buf[ENCRYPTED_HEADER_SIZE],
- size - ENCRYPTED_HEADER_SIZE))
- return;
- pt = (struct EncryptedMessage *) buf;
/* validate hash */
- GNUNET_CRYPTO_hmac (&n->decrypt_key,
- &pt->sequence_number,
- size - ENCRYPTED_HEADER_SIZE - sizeof (GNUNET_HashCode), &ph);
-#if DEBUG_HANDSHAKE
+ derive_auth_key (&auth_key,
+ &n->decrypt_key,
+ m->iv_seed,
+ n->decrypt_key_created);
+ GNUNET_CRYPTO_hmac (&auth_key,
+ &m->sequence_number,
+ size - ENCRYPTED_HEADER_SIZE, &ph);
+#if DEBUG_HANDSHAKE
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "V-Hashed %u bytes of plaintext (`%s') using IV `%d'\n",
- (unsigned int) (size - ENCRYPTED_HEADER_SIZE - sizeof (GNUNET_HashCode)),
- GNUNET_h2s (&ph),
- (int) m->iv_seed);
+ "Re-Authenticated %u bytes of ciphertext (`%u'): `%s'\n",
+ (unsigned int) size - ENCRYPTED_HEADER_SIZE,
+ GNUNET_CRYPTO_crc32_n (&m->sequence_number,
+ size - ENCRYPTED_HEADER_SIZE),
+ GNUNET_h2s (&ph));
#endif
- if (0 != memcmp (&ph,
- &pt->hmac,
+
+ if (0 != memcmp (&ph,
+ &m->hmac,
sizeof (GNUNET_HashCode)))
{
/* checksum failed */
GNUNET_break_op (0);
return;
}
+ derive_iv (&iv, &n->decrypt_key, m->iv_seed, &my_identity);
+ /* decrypt */
+ if (GNUNET_OK !=
+ do_decrypt (n,
+ &iv,
+ &m->sequence_number,
+ &buf[ENCRYPTED_HEADER_SIZE],
+ size - ENCRYPTED_HEADER_SIZE))
+ return;
+ pt = (struct EncryptedMessage *) buf;
/* validate sequence number */
snum = ntohl (pt->sequence_number);
}
if (n->last_sequence_number_received < snum)
{
- n->last_packets_bitmap <<= (snum - n->last_sequence_number_received);
+ int shift = (snum - n->last_sequence_number_received);
+ if (shift >= 8 * sizeof(n->last_packets_bitmap))
+ n->last_packets_bitmap = 0;
+ else
+ n->last_packets_bitmap <<= shift;
n->last_sequence_number_received = snum;
}
/* check timestamp */
t = GNUNET_TIME_absolute_ntoh (pt->timestamp);
- if (GNUNET_TIME_absolute_get_duration (t).value > MAX_MESSAGE_AGE.value)
+ if (GNUNET_TIME_absolute_get_duration (t).rel_value > MAX_MESSAGE_AGE.rel_value)
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
_
("Message received far too old (%llu ms). Content ignored.\n"),
- GNUNET_TIME_absolute_get_duration (t).value);
+ GNUNET_TIME_absolute_get_duration (t).rel_value);
GNUNET_STATISTICS_set (stats,
gettext_noop ("# bytes dropped (ancient message)"),
size,
}
n->last_activity = GNUNET_TIME_absolute_get ();
if (n->keep_alive_task != GNUNET_SCHEDULER_NO_TASK)
- GNUNET_SCHEDULER_cancel (sched, n->keep_alive_task);
+ GNUNET_SCHEDULER_cancel (n->keep_alive_task);
n->keep_alive_task
- = GNUNET_SCHEDULER_add_delayed (sched,
- GNUNET_TIME_relative_divide (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, 2),
+ = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, 2),
&send_keep_alive,
n);
GNUNET_STATISTICS_set (stats,
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 = (latency.value != n->last_latency.value) || (distance != n->last_distance);
- n->last_latency = latency;
- n->last_distance = distance;
+ changed = GNUNET_YES; /* FIXME... */
up = (n->status == PEER_STATE_KEY_CONFIRMED);
type = ntohs (message->type);
size = ntohs (message->size);
return;
}
GNUNET_STATISTICS_update (stats, gettext_noop ("# session keys received"), 1, GNUNET_NO);
- handle_set_key (n, (const struct SetKeyMessage *) message);
+ handle_set_key (n,
+ (const struct SetKeyMessage *) message,
+ ats, ats_count);
break;
case GNUNET_MESSAGE_TYPE_CORE_ENCRYPTED_MESSAGE:
if (size < sizeof (struct EncryptedMessage) +
GNUNET_break_op (0);
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,
n->time_established = now;
}
if (n->keep_alive_task != GNUNET_SCHEDULER_NO_TASK)
- GNUNET_SCHEDULER_cancel (sched, n->keep_alive_task);
+ GNUNET_SCHEDULER_cancel (n->keep_alive_task);
n->keep_alive_task
- = GNUNET_SCHEDULER_add_delayed (sched,
- GNUNET_TIME_relative_divide (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, 2),
+ = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, 2),
&send_keep_alive,
n);
}
{
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;
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).value > GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.value) &&
- (GNUNET_TIME_absolute_get_duration (n->time_established).value > GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.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
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
(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;
- n->last_latency = latency;
- n->last_distance = distance;
+ update_neighbour_performance (n, ats, ats_count);
GNUNET_BANDWIDTH_tracker_init (&n->available_send_window,
n->bw_out,
MAX_WINDOW_TIME_S);
{
struct DisconnectNotifyMessage cnm;
struct Neighbour *n;
+ struct ClientActiveRequest *car;
struct GNUNET_TIME_Relative left;
#if DEBUG_CORE
cnm.header.size = htons (sizeof (struct DisconnectNotifyMessage));
cnm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_DISCONNECT);
cnm.peer = *peer;
- send_to_all_clients (&cnm.header, GNUNET_YES, GNUNET_CORE_OPTION_SEND_DISCONNECT);
+ send_to_all_clients (&cnm.header, GNUNET_NO, GNUNET_CORE_OPTION_SEND_DISCONNECT);
}
+
+ /* 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,
+ n->active_client_request_tail,
+ car);
+ GNUNET_CONTAINER_multihashmap_remove (car->client->requests,
+ &n->peer.hashPubKey,
+ car);
+ GNUNET_free (car);
+ }
+
GNUNET_STATISTICS_update (stats,
gettext_noop ("# peers connected (transport)"),
-1,
GNUNET_NO);
if (n->dead_clean_task != GNUNET_SCHEDULER_NO_TASK)
- GNUNET_SCHEDULER_cancel (sched,
- n->dead_clean_task);
+ GNUNET_SCHEDULER_cancel (n->dead_clean_task);
left = GNUNET_TIME_relative_subtract (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
GNUNET_CONSTANTS_DISCONNECT_SESSION_TIMEOUT);
n->last_activity = GNUNET_TIME_absolute_subtract (GNUNET_TIME_absolute_get (),
left);
- n->dead_clean_task = GNUNET_SCHEDULER_add_delayed (sched,
- GNUNET_CONSTANTS_DISCONNECT_SESSION_TIMEOUT,
+ n->dead_clean_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_DISCONNECT_SESSION_TIMEOUT,
&consider_free_task,
n);
}
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Core service shutting down.\n");
#endif
- GNUNET_assert (transport != NULL);
- GNUNET_TRANSPORT_disconnect (transport);
- transport = NULL;
while (NULL != (n = neighbours))
{
neighbours = n->next;
neighbour_count--;
free_neighbour (n);
}
+ GNUNET_assert (transport != NULL);
+ GNUNET_TRANSPORT_disconnect (transport);
+ transport = NULL;
GNUNET_STATISTICS_set (stats, gettext_noop ("# neighbour entries allocated"), neighbour_count, GNUNET_NO);
GNUNET_SERVER_notification_context_destroy (notifier);
notifier = NULL;
* Initiate core service.
*
* @param cls closure
- * @param s scheduler to use
* @param server the initialized server
* @param c configuration to use
*/
static void
run (void *cls,
- struct GNUNET_SCHEDULER_Handle *s,
struct GNUNET_SERVER_Handle *server,
const struct GNUNET_CONFIGURATION_Handle *c)
{
static const struct GNUNET_SERVER_MessageHandler handlers[] = {
{&handle_client_init, NULL,
GNUNET_MESSAGE_TYPE_CORE_INIT, 0},
- {&handle_client_request_info, NULL,
- GNUNET_MESSAGE_TYPE_CORE_REQUEST_INFO,
- sizeof (struct RequestInfoMessage)},
{&handle_client_iterate_peers, NULL,
GNUNET_MESSAGE_TYPE_CORE_ITERATE_PEERS,
sizeof (struct GNUNET_MessageHeader)},
+ {&handle_client_request_info, NULL,
+ GNUNET_MESSAGE_TYPE_CORE_REQUEST_INFO,
+ sizeof (struct RequestInfoMessage)},
+ {&handle_client_send_request, NULL,
+ GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST,
+ sizeof (struct SendMessageRequest)},
{&handle_client_send, NULL,
GNUNET_MESSAGE_TYPE_CORE_SEND, 0},
{&handle_client_request_connect, NULL,
};
char *keyfile;
- sched = s;
cfg = c;
/* parse configuration */
if (
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
_
("Core service is lacking key configuration settings. Exiting.\n"));
- GNUNET_SCHEDULER_shutdown (s);
+ GNUNET_SCHEDULER_shutdown ();
return;
}
- peerinfo = GNUNET_PEERINFO_connect (sched, cfg);
+ peerinfo = GNUNET_PEERINFO_connect (cfg);
if (NULL == peerinfo)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
_("Could not access PEERINFO service. Exiting.\n"));
- GNUNET_SCHEDULER_shutdown (s);
+ GNUNET_SCHEDULER_shutdown ();
GNUNET_free (keyfile);
return;
}
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
_("Core service could not access hostkey. Exiting.\n"));
GNUNET_PEERINFO_disconnect (peerinfo);
- GNUNET_SCHEDULER_shutdown (s);
+ GNUNET_SCHEDULER_shutdown ();
return;
}
GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
MAX_NOTIFY_QUEUE);
GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL);
/* setup transport connection */
- transport = GNUNET_TRANSPORT_connect (sched,
- cfg,
+ transport = GNUNET_TRANSPORT_connect (cfg,
&my_identity,
NULL,
&handle_transport_receive,
&handle_transport_notify_connect,
&handle_transport_notify_disconnect);
GNUNET_assert (NULL != transport);
- stats = GNUNET_STATISTICS_create (sched, "core", cfg);
+ stats = GNUNET_STATISTICS_create ("core", cfg);
+
+ GNUNET_STATISTICS_set (stats, gettext_noop ("# discarded CORE_SEND requests"), 0, GNUNET_NO);
+ GNUNET_STATISTICS_set (stats, gettext_noop ("# discarded lower priority CORE_SEND requests"), 0, GNUNET_NO);
+
mst = GNUNET_SERVER_mst_create (&deliver_message,
NULL);
- GNUNET_SCHEDULER_add_delayed (sched,
- GNUNET_TIME_UNIT_FOREVER_REL,
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
&cleaning_task, NULL);
/* process client requests */
GNUNET_SERVER_add_handlers (server, handlers);