*/
#include "platform.h"
#include "gnunet_client_lib.h"
+#include "gnunet_constants.h"
#include "gnunet_getopt_lib.h"
#include "gnunet_hello_lib.h"
#include "gnunet_os_lib.h"
/**
* How long until a HELLO verification attempt should time out?
+ * Must be rather small, otherwise a partially successful HELLO
+ * validation (some addresses working) might not be available
+ * before a client's request for a connection fails for good.
+ * Besides, if a single request to an address takes a long time,
+ * then the peer is unlikely worthwhile anyway.
*/
-#define HELLO_VERIFICATION_TIMEOUT GNUNET_TIME_UNIT_MINUTES
+#define HELLO_VERIFICATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 3)
+
+/**
+ * How long will we allow sending of a ping to be delayed?
+ */
+#define TRANSPORT_DEFAULT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
+
+#define TRANSPORT_DEFAULT_PRIORITY 4 /* Tired of remembering arbitrary priority names */
/**
* How often do we re-add (cheaper) plugins to our list of plugins
*/
#define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)
-/**
- * After how long do we consider a connection to a peer dead
- * if we don't receive messages from the peer?
- */
-#define IDLE_CONNECTION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
-
/**
* Entry in linked list of network addresses.
int rebuild;
};
-struct NeighbourList;
+struct NeighborList;
/**
- * For each neighbour we keep a list of messages
- * that we still want to transmit to the neighbour.
+ * For each neighbor we keep a list of messages
+ * that we still want to transmit to the neighbor.
*/
struct MessageQueue
{
struct TransportClient *client;
/**
- * Neighbour this entry belongs to.
+ * Neighbor this entry belongs to.
*/
- struct NeighbourList *neighbour;
+ struct NeighborList *neighbor;
/**
* Plugin that we used for the transmission.
*/
int internal_msg;
+ /**
+ * How important is the message?
+ */
+ unsigned int priority;
+
};
/**
- * For a given Neighbour, which plugins are available
+ * For a given Neighbor, which plugins are available
* to talk to this peer and what are their costs?
*/
struct ReadyList
struct TransportPlugin *plugin;
/**
- * Neighbour this entry belongs to.
- */
- struct NeighbourList *neighbour;
-
- /**
- * Opaque handle (specific to the plugin) for the
- * connection to our target; can be NULL.
+ * Neighbor this entry belongs to.
*/
- void *plugin_handle;
+ struct NeighborList *neighbor;
/**
* What was the last latency observed for this plugin
struct GNUNET_TIME_Relative latency;
/**
- * If we did not successfully transmit a message to the
- * given peer via this connection during the specified
- * time, we should consider the connection to be dead.
- * This is used in the case that a TCP transport simply
- * stalls writing to the stream but does not formerly
- * get a signal that the other peer died.
+ * If we did not successfully transmit a message to the given peer
+ * via this connection during the specified time, we should consider
+ * the connection to be dead. This is used in the case that a TCP
+ * transport simply stalls writing to the stream but does not
+ * formerly get a signal that the other peer died.
*/
struct GNUNET_TIME_Absolute timeout;
unsigned int connect_attempts;
/**
- * Is this plugin ready to transmit to the specific
- * target? GNUNET_NO if not. Initially, all plugins
- * are marked ready. If a transmission is in progress,
- * "transmit_ready" is set to GNUNET_NO.
+ * Is this plugin ready to transmit to the specific target?
+ * GNUNET_NO if not. Initially, all plugins are marked ready. If a
+ * transmission is in progress, "transmit_ready" is set to
+ * GNUNET_NO.
*/
int transmit_ready;
/**
- * Entry in linked list of all of our current neighbours.
+ * Entry in linked list of all of our current neighbors.
*/
-struct NeighbourList
+struct NeighborList
{
/**
* This is a linked list.
*/
- struct NeighbourList *next;
+ struct NeighborList *next;
/**
* Which of our transports is connected to this peer
struct MessageQueue *messages;
/**
- * Identity of this neighbour.
+ * Identity of this neighbor.
*/
struct GNUNET_PeerIdentity id;
+ /*
+ * Opaque addr of this peer, only known to the plugin
+ */
+ char *addr;
+
+ /*
+ * Size of addr
+ */
+ size_t addr_len;
+
/**
* ID of task scheduled to run when this peer is about to
* time out (will free resources associated with the peer).
uint64_t last_received;
/**
- * Global quota for outbound traffic for the neighbour in bytes/ms.
+ * Global quota for inbound traffic for the neighbor in bytes/ms.
*/
uint32_t quota_in;
- /**
- * What is the latest version of our HELLO that we have
- * sent to this neighbour?
- */
- unsigned int hello_version_sent;
-
/**
* How often has the other peer (recently) violated the
* inbound traffic limit? Incremented by 10 per violation,
unsigned int quota_violation_count;
/**
- * Have we seen an ACK from this neighbour in the past?
+ * Have we seen an ACK from this neighbor in the past?
* (used to make up a fake ACK for clients connecting after
- * the neighbour connected to us).
+ * the neighbor connected to us).
*/
int saw_ack;
-};
+ /* The latency we have seen for this particular address for
+ * this particular peer. This latency may have been calculated
+ * over multiple transports. This value reflects how long it took
+ * us to receive a response when SENDING via this particular
+ * transport/neighbor/address combination!
+ */
+ struct GNUNET_TIME_RelativeNBO latency;
+};
/**
- * Linked list of messages to be transmitted to
- * the client. Each entry is followed by the
- * actual message.
+ * Message used to ask a peer to validate receipt (to check an address
+ * from a HELLO). Followed by the address used. Note that the
+ * recipients response does not affirm that he has this address,
+ * only that he got the challenge message.
*/
-struct ClientMessageQueueEntry
+struct TransportPingMessage
{
+
/**
- * This is a linked list.
+ * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PING
*/
- struct ClientMessageQueueEntry *next;
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * Random challenge number (in network byte order).
+ */
+ uint32_t challenge GNUNET_PACKED;
+
+ /**
+ * Who is the intended recipient?
+ */
+ struct GNUNET_PeerIdentity target;
+
};
/**
- * Client connected to the transport service.
+ * Message used to validate a HELLO. The challenge is included in the
+ * confirmation to make matching of replies to requests possible. The
+ * signature signs the original challenge number, our public key, the
+ * sender's address (so that the sender can check that the address we
+ * saw is plausible for him and possibly detect a MiM attack) and a
+ * timestamp (to limit replay).<p>
+ *
+ * This message is followed by the address of the
+ * client that we are observing (which is part of what
+ * is being signed).
*/
-struct TransportClient
+struct TransportPongMessage
{
/**
- * This is a linked list.
+ * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PONG
*/
- struct TransportClient *next;
+ struct GNUNET_MessageHeader header;
/**
- * Handle to the client.
+ * For padding, always zero.
*/
- struct GNUNET_SERVER_Client *client;
+ uint32_t reserved GNUNET_PACKED;
/**
- * Linked list of messages yet to be transmitted to
- * the client.
+ * Signature.
*/
- struct ClientMessageQueueEntry *message_queue_head;
+ struct GNUNET_CRYPTO_RsaSignature signature;
/**
- * Tail of linked list of messages yet to be transmitted to the
- * client.
+ * What are we signing and why?
*/
- struct ClientMessageQueueEntry *message_queue_tail;
+ struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
/**
- * Is a call to "transmit_send_continuation" pending? If so, we
- * must not free this struct (even if the corresponding client
- * disconnects) and instead only remove it from the linked list and
- * set the "client" field to NULL.
+ * Random challenge number (in network byte order).
*/
- int tcs_pending;
+ uint32_t challenge GNUNET_PACKED;
/**
- * Length of the list of messages pending for this client.
+ * Who signed this message?
*/
- unsigned int message_count;
+ struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded signer;
};
-
/**
- * Message used to ask a peer to validate receipt (to check an address
- * from a HELLO). Followed by the address used. Note that the
- * recipients response does not affirm that he has this address,
- * only that he got the challenge message.
+ * Linked list of messages to be transmitted to
+ * the client. Each entry is followed by the
+ * actual message.
*/
-struct ValidationChallengeMessage
+struct ClientMessageQueueEntry
{
-
/**
- * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PING
+ * This is a linked list.
*/
- struct GNUNET_MessageHeader header;
+ struct ClientMessageQueueEntry *next;
+};
- /**
- * What are we signing and why?
- */
- struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
+
+/**
+ * Client connected to the transport service.
+ */
+struct TransportClient
+{
/**
- * Random challenge number (in network byte order).
+ * This is a linked list.
*/
- uint32_t challenge GNUNET_PACKED;
+ struct TransportClient *next;
/**
- * Who is the intended recipient?
+ * Handle to the client.
*/
- struct GNUNET_PeerIdentity target;
-};
-
-
-/**
- * Message used to validate a HELLO. If this was
- * the right recipient, the response is a signature
- * of the original validation request. The
- * challenge is included in the confirmation to make
- * matching of replies to requests possible.
- */
-struct ValidationChallengeResponse
-{
+ struct GNUNET_SERVER_Client *client;
/**
- * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PONG
+ * Linked list of messages yet to be transmitted to
+ * the client.
*/
- struct GNUNET_MessageHeader header;
+ struct ClientMessageQueueEntry *message_queue_head;
/**
- * Random challenge number (in network byte order).
+ * Tail of linked list of messages yet to be transmitted to the
+ * client.
*/
- uint32_t challenge GNUNET_PACKED;
+ struct ClientMessageQueueEntry *message_queue_tail;
/**
- * Who signed this message?
+ * Is a call to "transmit_send_continuation" pending? If so, we
+ * must not free this struct (even if the corresponding client
+ * disconnects) and instead only remove it from the linked list and
+ * set the "client" field to NULL.
*/
- struct GNUNET_PeerIdentity sender;
+ int tcs_pending;
/**
- * Signature.
+ * Length of the list of messages pending for this client.
*/
- struct GNUNET_CRYPTO_RsaSignature signature;
+ unsigned int message_count;
};
*/
struct ValidationAddress *next;
- /**
- * Our challenge message. Points to after this
- * struct, so this field should not be freed.
- */
- struct ValidationChallengeMessage *msg;
-
/**
* Name of the transport.
*/
*/
size_t addr_len;
+ /**
+ * Challenge number we used.
+ */
+ uint32_t challenge;
+
/**
* Set to GNUNET_YES if the challenge was met,
* GNUNET_SYSERR if we know it failed, GNUNET_NO
/**
* "version" of "our_hello". Used to see if a given
- * neighbour has already been sent the latest version
+ * neighbor has already been sent the latest version
* of our HELLO message.
*/
static unsigned int our_hello_version;
/**
* Our configuration.
*/
-struct GNUNET_CONFIGURATION_Handle *cfg;
+const struct GNUNET_CONFIGURATION_Handle *cfg;
/**
* Linked list of all clients to this service.
static struct GNUNET_SERVER_Handle *server;
/**
- * All known neighbours and their HELLOs.
- */
-static struct NeighbourList *neighbours;
-
-/**
- * Default bandwidth quota for receiving for new peers in bytes/ms.
- */
-static uint32_t default_quota_in;
-
-/**
- * Default bandwidth quota for sending for new peers in bytes/ms.
+ * All known neighbors and their HELLOs.
*/
-static uint32_t default_quota_out;
+static struct NeighborList *neighbors;
/**
- * Number of neighbours we'd like to have.
+ * Number of neighbors we'd like to have.
*/
static uint32_t max_connect_per_transport;
/**
- * Find an entry in the neighbour list for a particular peer.
+ * Find an entry in the neighbor list for a particular peer.
+ * if sender_address is not specified (NULL) then return the
+ * first matching entry. If sender_address is specified, then
+ * make sure that the address and address_len also matches.
*
* @return NULL if not found.
*/
-static struct NeighbourList *
-find_neighbour (const struct GNUNET_PeerIdentity *key)
+static struct NeighborList *
+find_neighbor (const struct GNUNET_PeerIdentity *key, const char *sender_address,
+ size_t sender_address_len)
{
- struct NeighbourList *head = neighbours;
- while ((head != NULL) &&
- (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
- head = head->next;
+ struct NeighborList *head = neighbors;
+ if (sender_address == NULL)
+ {
+ while ((head != NULL) &&
+ (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
+ head = head->next;
+ }
+ else
+ {
+ while ((head != NULL) &&
+ (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))) &&
+ (sender_address_len != head->addr_len) &&
+ (0 != memcmp (sender_address, &head->addr, head->addr_len)))
+ head = head->next;
+ }
return head;
}
/**
- * Update the quota values for the given neighbour now.
+ * Update the quota values for the given neighbor now.
*/
static void
-update_quota (struct NeighbourList *n)
+update_quota (struct NeighborList *n)
{
struct GNUNET_TIME_Relative delta;
uint64_t allowed;
uint16_t msize;
size_t tsize;
const struct GNUNET_MessageHeader *msg;
- struct GNUNET_NETWORK_TransmitHandle *th;
+ struct GNUNET_CONNECTION_TransmitHandle *th;
char *cbuf;
if (buf == NULL)
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Transmission to client failed, closing connection.\n");
+ "Transmission to client failed, closing connection.\n");
/* fatal error with client, free message queue! */
while (NULL != (q = client->message_queue_head))
{
msize = ntohs (msg->size);
if (msize + tsize > size)
break;
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Transmitting message of type %u to client.\n",
+ ntohs (msg->type));
+#endif
client->message_queue_head = q->next;
if (q->next == NULL)
client->message_queue_tail = NULL;
GNUNET_free (q);
client->message_count--;
}
- GNUNET_assert (tsize > 0);
if (NULL != q)
{
+ GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
th = GNUNET_SERVER_notify_transmit_ready (client->client,
msize,
GNUNET_TIME_UNIT_FOREVER_REL,
{
struct ClientMessageQueueEntry *q;
uint16_t msize;
- struct GNUNET_NETWORK_TransmitHandle *th;
+ struct GNUNET_CONNECTION_TransmitHandle *th;
if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
{
}
client->message_count++;
msize = ntohs (msg->size);
+ GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
memcpy (&q[1], msg, msize);
/* append to message queue */
/**
* Find alternative plugins for communication.
*
- * @param neighbour for which neighbour should we try to find
+ * @param neighbor for which neighbor should we try to find
* more plugins?
*/
static void
-try_alternative_plugins (struct NeighbourList *neighbour)
+try_alternative_plugins (struct NeighborList *neighbor)
{
struct ReadyList *rl;
- if ((neighbour->plugins != NULL) &&
- (neighbour->retry_plugins_time.value >
+ if ((neighbor->plugins != NULL) &&
+ (neighbor->retry_plugins_time.value >
GNUNET_TIME_absolute_get ().value))
return; /* don't try right now */
- neighbour->retry_plugins_time
+ neighbor->retry_plugins_time
= GNUNET_TIME_relative_to_absolute (PLUGIN_RETRY_FREQUENCY);
- rl = neighbour->plugins;
+ rl = neighbor->plugins;
while (rl != NULL)
{
if (rl->connect_attempts > 0)
/**
- * Check the ready list for the given neighbour and
+ * The peer specified by the given neighbor has timed-out or a plugin
+ * has disconnected. We may either need to do nothing (other plugins
+ * still up), or trigger a full disconnect and clean up. This
+ * function updates our state and do the necessary notifications.
+ * Also notifies our clients that the neighbor is now officially
+ * gone.
+ *
+ * @param n the neighbor list entry for the peer
+ * @param check should we just check if all plugins
+ * disconnected or must we ask all plugins to
+ * disconnect?
+ */
+static void disconnect_neighbor (struct NeighborList *n, int check);
+
+
+/**
+ * Check the ready list for the given neighbor and
* if a plugin is ready for transmission (and if we
* have a message), do so!
*
- * @param neighbour target peer for which to check the plugins
+ * @param neighbor target peer for which to check the plugins
*/
-static void try_transmission_to_peer (struct NeighbourList *neighbour);
+static void try_transmission_to_peer (struct NeighborList *neighbor);
/**
* @param cls closure, identifies the entry on the
* message queue that was transmitted and the
* client responsible for queueing the message
- * @param rl identifies plugin used for the transmission for
- * this neighbour; needs to be re-enabled for
- * future transmissions
* @param target the peer receiving the message
* @param result GNUNET_OK on success, if the transmission
* failed, we should not tell the client to transmit
*/
static void
transmit_send_continuation (void *cls,
- struct ReadyList *rl,
const struct GNUNET_PeerIdentity *target,
int result)
{
struct MessageQueue *mq = cls;
+ struct ReadyList *rl;
struct SendOkMessage send_ok_msg;
- struct NeighbourList *n;
+ struct NeighborList *n;
GNUNET_assert (mq != NULL);
- n = mq->neighbour;
+ n = mq->neighbor;
GNUNET_assert (n != NULL);
GNUNET_assert (0 ==
memcmp (&n->id, target,
sizeof (struct GNUNET_PeerIdentity)));
- if (rl == NULL)
- {
- rl = n->plugins;
- while ((rl != NULL) && (rl->plugin != mq->plugin))
- rl = rl->next;
- GNUNET_assert (rl != NULL);
- }
+ rl = n->plugins;
+ while ((rl != NULL) && (rl->plugin != mq->plugin))
+ rl = rl->next;
+ GNUNET_assert (rl != NULL);
if (result == GNUNET_OK)
{
- rl->timeout = GNUNET_TIME_relative_to_absolute (IDLE_CONNECTION_TIMEOUT);
+ rl->timeout =
+ GNUNET_TIME_relative_to_absolute
+ (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
}
else
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Transmission failed, marking connection as down.\n");
+ "Transmission to peer `%s' failed, marking connection as down.\n",
+ GNUNET_i2s (target));
rl->connected = GNUNET_NO;
}
if (!mq->internal_msg)
rl->transmit_ready = GNUNET_YES;
if (mq->client != NULL)
{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Notifying client %p about failed transission to peer `%4s'.\n",
+ mq->client, GNUNET_i2s (target));
send_ok_msg.header.size = htons (sizeof (send_ok_msg));
send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
send_ok_msg.success = htonl (result);
GNUNET_free (mq);
/* one plugin just became ready again, try transmitting
another message (if available) */
- try_transmission_to_peer (n);
-}
-
-
-
-
-/**
- * We could not use an existing (or validated) connection to
- * talk to a peer. Try addresses that have not yet been
- * validated.
- *
- * @param n neighbour we want to communicate with
- * @return plugin ready to talk, or NULL if none is available
- */
-static struct ReadyList *
-try_unvalidated_addresses (struct NeighbourList *n)
-{
- struct ValidationList *vl;
- struct ValidationAddress *va;
- struct GNUNET_PeerIdentity id;
- struct GNUNET_TIME_Absolute now;
- unsigned int total;
- unsigned int cnt;
- struct ReadyList *rl;
- struct TransportPlugin *plugin;
-
-#if DEBUG_TRANSPORT
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Trying to connect to `%4s' using unvalidated addresses\n",
- GNUNET_i2s (&n->id));
-#endif
- /* NOTE: this function needs to not only identify the
- plugin but also setup "plugin_handle", binding it to the
- right address using the plugin's "send_to" API */
- now = GNUNET_TIME_absolute_get ();
- vl = pending_validations;
- while (vl != NULL)
- {
- GNUNET_CRYPTO_hash (&vl->publicKey,
- sizeof (struct
- GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
- &id.hashPubKey);
- if (0 == memcmp (&id, &n->id, sizeof (struct GNUNET_PeerIdentity)))
- break;
- vl = vl->next;
- }
- if (vl == NULL)
- {
-#if DEBUG_TRANSPORT
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "No unvalidated address found for peer `%4s'\n",
- GNUNET_i2s (&n->id));
-#endif
- return NULL;
- }
- total = 0;
- cnt = 0;
- va = vl->addresses;
- while (va != NULL)
- {
- cnt++;
- if (va->expiration.value > now.value)
- total++;
- va = va->next;
- }
- if (total == 0)
- {
-#if DEBUG_TRANSPORT
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "All %u unvalidated addresses for peer have expired\n",
- cnt);
-#endif
- return NULL;
- }
- total = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, total);
- for (va = vl->addresses; va != NULL; va = va->next)
- {
- if (va->expiration.value <= now.value)
- continue;
- if (total > 0)
- {
- total--;
- continue;
- }
-#if DEBUG_TRANSPORT
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
- "Trying unvalidated address of `%s' transport\n",
- va->transport_name);
-#endif
- plugin = find_transport (va->transport_name);
- if (plugin == NULL)
- {
- GNUNET_break (0);
- break;
- }
- rl = GNUNET_malloc (sizeof (struct ReadyList));
- rl->next = n->plugins;
- n->plugins = rl;
- rl->plugin = plugin;
- rl->plugin_handle = plugin->api->send_to (plugin->api->cls,
- &n->id,
- NULL,
- NULL,
- GNUNET_TIME_UNIT_ZERO,
- &va->msg[1], va->addr_len);
- rl->transmit_ready = GNUNET_YES;
- return rl;
- }
- return NULL;
+ if (result == GNUNET_OK)
+ try_transmission_to_peer (n);
+ else
+ disconnect_neighbor (n, GNUNET_YES);
}
/**
- * Check the ready list for the given neighbour and
+ * Check the ready list for the given neighbor and
* if a plugin is ready for transmission (and if we
* have a message), do so!
*/
static void
-try_transmission_to_peer (struct NeighbourList *neighbour)
+try_transmission_to_peer (struct NeighborList *neighbor)
{
struct ReadyList *pos;
struct GNUNET_TIME_Relative min_latency;
struct MessageQueue *mq;
struct GNUNET_TIME_Absolute now;
- if (neighbour->messages == NULL)
+ if (neighbor->messages == NULL)
return; /* nothing to do */
- try_alternative_plugins (neighbour);
+ try_alternative_plugins (neighbor);
min_latency = GNUNET_TIME_UNIT_FOREVER_REL;
rl = NULL;
- mq = neighbour->messages;
+ mq = neighbor->messages;
now = GNUNET_TIME_absolute_get ();
- pos = neighbour->plugins;
+ pos = neighbor->plugins;
while (pos != NULL)
{
/* set plugins that are inactive for a long time back to disconnected */
#if DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Marking long-time inactive connection to `%4s' as down.\n",
- GNUNET_i2s (&neighbour->id));
+ GNUNET_i2s (&neighbor->id));
#endif
pos->connected = GNUNET_NO;
}
}
pos = pos->next;
}
- if (rl == NULL)
- rl = try_unvalidated_addresses (neighbour);
if (rl == NULL)
{
#if DEBUG_TRANSPORT
{
rl->connect_attempts++;
rl->connected = GNUNET_YES;
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Establishing fresh connection with `%4s' via plugin `%s'\n",
+ GNUNET_i2s (&neighbor->id), rl->plugin->short_name);
+#endif
}
- neighbour->messages = mq->next;
+ neighbor->messages = mq->next;
mq->plugin = rl->plugin;
if (!mq->internal_msg)
rl->transmit_ready = GNUNET_NO;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Giving message of type `%u' for `%4s' to plugin `%s'\n",
ntohs (mq->message->type),
- GNUNET_i2s (&neighbour->id), rl->plugin->short_name);
+ GNUNET_i2s (&neighbor->id), rl->plugin->short_name);
#endif
- rl->plugin_handle
- = rl->plugin->api->send (rl->plugin->api->cls,
- rl->plugin_handle,
- rl,
- &neighbour->id,
- mq->message,
- IDLE_CONNECTION_TIMEOUT,
- &transmit_send_continuation, mq);
+
+ rl->plugin->api->send (rl->plugin->api->cls,
+ &neighbor->id,
+ mq->message,
+ mq->priority,
+ GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
+ rl->neighbor->addr,
+ rl->neighbor->addr_len,
+ GNUNET_NO,
+ &transmit_send_continuation, mq);
}
* Send the specified message to the specified peer.
*
* @param client source of the transmission request (can be NULL)
+ * @param priority how important is the message
* @param msg message to send
* @param is_internal is this an internal message
- * @param neighbour handle to the neighbour for transmission
+ * @param neighbor handle to the neighbor for transmission
*/
static void
transmit_to_peer (struct TransportClient *client,
+ unsigned int priority,
const struct GNUNET_MessageHeader *msg,
- int is_internal, struct NeighbourList *neighbour)
+ int is_internal, struct NeighborList *neighbor)
{
struct MessageQueue *mq;
struct MessageQueue *mqe;
#if DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
_("Sending message of type %u to peer `%4s'\n"),
- ntohs (msg->type), GNUNET_i2s (&neighbour->id));
+ ntohs (msg->type), GNUNET_i2s (&neighbor->id));
#endif
if (client != NULL)
{
/* check for duplicate submission */
- mq = neighbour->messages;
+ mq = neighbor->messages;
while (NULL != mq)
{
if (mq->client == client)
m = GNUNET_malloc (ntohs (msg->size));
memcpy (m, msg, ntohs (msg->size));
mq->message = m;
- mq->neighbour = neighbour;
+ mq->neighbor = neighbor;
mq->internal_msg = is_internal;
+ mq->priority = priority;
/* find tail */
- mqe = neighbour->messages;
+ mqe = neighbor->messages;
if (mqe != NULL)
while (mqe->next != NULL)
mqe = mqe->next;
if (mqe == NULL)
{
/* new head */
- neighbour->messages = mq;
- try_transmission_to_peer (neighbour);
+ neighbor->messages = mq;
+ try_transmission_to_peer (neighbor);
}
else
{
}
+/**
+ * FIXME: document.
+ */
struct GeneratorContext
{
struct TransportPlugin *plug_pos;
};
+/**
+ * FIXME: document.
+ */
static size_t
address_generator (void *cls, size_t max, void *buf)
{
{
struct GNUNET_HELLO_Message *hello;
struct TransportClient *cpos;
- struct NeighbourList *npos;
+ struct NeighborList *npos;
struct GeneratorContext gc;
#if DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
- "Refreshing my HELLO\n");
+ "Refreshing my `%s'\n", "HELLO");
#endif
gc.plug_pos = plugins;
gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
GNUNET_free_non_null (our_hello);
our_hello = hello;
our_hello_version++;
- npos = neighbours;
+ GNUNET_PEERINFO_add_peer (cfg, sched, &my_identity, our_hello);
+ npos = neighbors;
while (npos != NULL)
{
- transmit_to_peer (NULL,
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
+ "Transmitting updated `%s' to neighbor `%4s'\n",
+ "HELLO", GNUNET_i2s (&npos->id));
+#endif
+ transmit_to_peer (NULL, 0,
(const struct GNUNET_MessageHeader *) our_hello,
GNUNET_YES, npos);
npos = npos->next;
struct AddressList *next;
int expired;
- if (plugin->address_update_task != GNUNET_SCHEDULER_NO_PREREQUISITE_TASK)
+ if (plugin->address_update_task != GNUNET_SCHEDULER_NO_TASK)
GNUNET_SCHEDULER_cancel (plugin->env.sched, plugin->address_update_task);
- plugin->address_update_task = GNUNET_SCHEDULER_NO_PREREQUISITE_TASK;
+ plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
now = GNUNET_TIME_absolute_get ();
min_remaining = GNUNET_TIME_UNIT_FOREVER_REL;
expired = GNUNET_NO;
if (min_remaining.value < GNUNET_TIME_UNIT_FOREVER_REL.value)
plugin->address_update_task
= GNUNET_SCHEDULER_add_delayed (plugin->env.sched,
- GNUNET_NO,
- GNUNET_SCHEDULER_PRIORITY_IDLE,
- GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
min_remaining,
&expire_address_task, plugin);
expire_address_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
{
struct TransportPlugin *plugin = cls;
- plugin->address_update_task = GNUNET_SCHEDULER_NO_PREREQUISITE_TASK;
+ plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
update_addresses (plugin, GNUNET_NO);
}
struct AddressList *al;
struct GNUNET_TIME_Absolute abex;
-#if DEBUG_TRANSPORT
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Plugin `%s' informs us about a new address `%s'\n", name,
- GNUNET_a2s(addr, addrlen));
-#endif
abex = GNUNET_TIME_relative_to_absolute (expires);
GNUNET_assert (p == find_transport (name));
}
al = al->next;
}
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Plugin `%s' informs us about a new address `%s'\n", name,
+ GNUNET_a2s (addr, addrlen));
+#endif
al = GNUNET_malloc (sizeof (struct AddressList) + addrlen);
al->addr = &al[1];
al->next = p->addresses;
}
-struct LookupHelloContext
-{
- GNUNET_TRANSPORT_AddressCallback iterator;
-
- void *iterator_cls;
-};
-
-
-static int
-lookup_address_callback (void *cls,
- const char *tname,
- struct GNUNET_TIME_Absolute expiration,
- const void *addr, size_t addrlen)
+/**
+ * Notify all of our clients about a peer connecting.
+ */
+static void
+notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
+ struct GNUNET_TIME_Relative latency)
{
- struct LookupHelloContext *lhc = cls;
- lhc->iterator (lhc->iterator_cls, tname, addr, addrlen);
- return GNUNET_OK;
-}
-
-
-static void
-lookup_hello_callback (void *cls,
- const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_HELLO_Message *h, uint32_t trust)
-{
- struct LookupHelloContext *lhc = cls;
-
- if (peer == NULL)
- {
- lhc->iterator (lhc->iterator_cls, NULL, NULL, 0);
- GNUNET_free (lhc);
- return;
- }
- if (h == NULL)
- return;
- GNUNET_HELLO_iterate_addresses (h,
- GNUNET_NO, &lookup_address_callback, lhc);
-}
-
-
-/**
- * Function that allows a transport to query the known
- * network addresses for a given peer.
- *
- * @param cls closure
- * @param timeout after how long should we time out?
- * @param target which peer are we looking for?
- * @param iter function to call for each known address
- * @param iter_cls closure for iter
- */
-static void
-plugin_env_lookup_address (void *cls,
- struct GNUNET_TIME_Relative timeout,
- const struct GNUNET_PeerIdentity *target,
- GNUNET_TRANSPORT_AddressCallback iter,
- void *iter_cls)
-{
- struct LookupHelloContext *lhc;
-
- lhc = GNUNET_malloc (sizeof (struct LookupHelloContext));
- lhc->iterator = iter;
- lhc->iterator_cls = iter_cls;
- GNUNET_PEERINFO_for_all (cfg,
- sched,
- target, 0, timeout, &lookup_hello_callback, &lhc);
-}
-
-
-/**
- * Notify all of our clients about a peer connecting.
- */
-static void
-notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
- struct GNUNET_TIME_Relative latency)
-{
- struct ConnectInfoMessage cim;
- struct TransportClient *cpos;
+ struct ConnectInfoMessage cim;
+ struct TransportClient *cpos;
#if DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
#endif
cim.header.size = htons (sizeof (struct ConnectInfoMessage));
cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
- cim.quota_out = htonl (default_quota_out);
+ cim.quota_out = htonl (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT / (60 * 1000));
cim.latency = GNUNET_TIME_relative_hton (latency);
memcpy (&cim.id, peer, sizeof (struct GNUNET_PeerIdentity));
cpos = clients;
return 0;
ret = GNUNET_HELLO_add_address ((*va)->transport_name,
(*va)->expiration,
- &(*va)->msg[1], (*va)->addr_len, buf, max);
+ &(*va)[1], (*va)->addr_len, buf, max);
*va = (*va)->next;
return ret;
}
struct ValidationList *pos;
struct ValidationList *prev;
struct GNUNET_TIME_Absolute now;
+ struct GNUNET_TIME_Absolute first;
struct GNUNET_HELLO_Message *hello;
struct GNUNET_PeerIdentity pid;
+ struct NeighborList *n;
#if DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
"HELLO", GNUNET_i2s (&pid));
#endif
GNUNET_PEERINFO_add_peer (cfg, sched, &pid, hello);
+ n = find_neighbor (&pid, NULL, 0);
+ if (NULL != n)
+ try_transmission_to_peer (n);
GNUNET_free (hello);
while (NULL != (va = pos->addresses))
{
else
pos = prev->next;
continue;
- }
+ }
prev = pos;
pos = pos->next;
}
/* finally, reschedule cleanup if needed; list is
ordered by timeout, so we need the last element... */
+ if (NULL != pending_validations)
+ {
+ first = pending_validations->timeout;
+ pos = pending_validations;
+ while (pos != NULL)
+ {
+ first = GNUNET_TIME_absolute_min (first, pos->timeout);
+ pos = pos->next;
+ }
+ GNUNET_SCHEDULER_add_delayed (sched,
+ GNUNET_TIME_absolute_get_remaining
+ (first), &cleanup_validation, NULL);
+ }
+}
+
+
+static struct GNUNET_MessageHeader *
+createPingMessage (struct GNUNET_PeerIdentity * target, struct ValidationAddress *va)
+{
+
+ struct TransportPingMessage *ping;
+ ping = GNUNET_malloc(sizeof(struct TransportPingMessage));
+
+ ping->challenge = htonl(va->challenge);
+ ping->header.size = sizeof(struct TransportPingMessage);
+ ping->header.type = GNUNET_MESSAGE_TYPE_TRANSPORT_PING;
+ memcpy(&ping->target, target, sizeof(struct GNUNET_PeerIdentity));
+
+ return &ping->header;
+}
+
+/**
+ * Function that will be called if we receive a validation
+ * of an address challenge that we transmitted to another
+ * peer. Note that the validation should only be considered
+ * acceptable if the challenge matches AND if the sender
+ * address is at least a plausible address for this peer
+ * (otherwise we may be seeing a MiM attack).
+ *
+ * @param cls closure
+ * @param name name of the transport that generated the address
+ * @param peer who responded to our challenge
+ * @param challenge the challenge number we presumably used
+ * @param sender_addr string describing our sender address (as observed
+ * by the other peer in human-readable format)
+ */
+static void
+handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
+ const struct GNUNET_PeerIdentity *peer,
+ const char *sender_address,
+ size_t sender_address_len)
+{
+ unsigned int not_done;
+ int matched;
+ struct ValidationList *pos;
+ struct ValidationAddress *va;
+ struct GNUNET_PeerIdentity id;
+ struct TransportPongMessage *pong = (struct TransportPongMessage *)message;
+
+ unsigned int challenge = ntohl(pong->challenge);
pos = pending_validations;
- while ((pos != NULL) && (pos->next != NULL))
- pos = pos->next;
- if (NULL != pos)
- GNUNET_SCHEDULER_add_delayed (sched,
- GNUNET_NO,
- GNUNET_SCHEDULER_PRIORITY_IDLE,
- GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
- GNUNET_TIME_absolute_get_remaining
- (pos->timeout), &cleanup_validation, NULL);
+ while (pos != NULL)
+ {
+ GNUNET_CRYPTO_hash (&pos->publicKey,
+ sizeof (struct
+ GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
+ &id.hashPubKey);
+ if (0 == memcmp (peer, &id, sizeof (struct GNUNET_PeerIdentity)))
+ break;
+ pos = pos->next;
+ }
+ if (pos == NULL)
+ {
+ /* TODO: call statistics (unmatched PONG) */
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _
+ ("Received validation response but have no record of any validation request for `%4s'. Ignoring.\n"),
+ GNUNET_i2s (peer));
+ return;
+ }
+ not_done = 0;
+ matched = GNUNET_NO;
+ va = pos->addresses;
+ while (va != NULL)
+ {
+ if (va->challenge == challenge)
+ {
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Confirmed validity of address, peer `%4s' has address `%s'.\n",
+ GNUNET_i2s (peer),
+ GNUNET_a2s ((const struct sockaddr *) &va[1],
+ va->addr_len));
+#endif
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
+ _
+ ("Another peer saw us using the address `%s' via `FIXME'. If this is not plausible, this address should be listed in the configuration as implausible to avoid MiM attacks.\n"),
+ sender_address);
+ va->ok = GNUNET_YES;
+ va->expiration =
+ GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
+ matched = GNUNET_YES;
+ }
+ if (va->ok != GNUNET_YES)
+ not_done++;
+ va = va->next;
+ }
+ if (GNUNET_NO == matched)
+ {
+ /* TODO: call statistics (unmatched PONG) */
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _
+ ("Received `%s' message but have no record of a matching `%s' message. Ignoring.\n"),
+ "PONG", "PING");
+ }
+ if (0 == not_done)
+ {
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "All addresses validated, will now construct `%s' for `%4s'.\n",
+ "HELLO", GNUNET_i2s (peer));
+#endif
+ pos->timeout.value = 0;
+ GNUNET_SCHEDULER_add_with_priority (sched,
+ GNUNET_SCHEDULER_PRIORITY_IDLE,
+ &cleanup_validation, NULL);
+ }
+ else
+ {
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Still waiting for %u additional `%s' messages before constructing `%s' for `%4s'.\n",
+ not_done, "PONG", "HELLO", GNUNET_i2s (peer));
+#endif
+ }
}
*/
struct ValidationList *e;
+ /**
+ * Context for peerinfo iteration.
+ * NULL after we are done processing peerinfo's information.
+ */
+ struct GNUNET_PEERINFO_IteratorContext *piter;
+
};
struct ValidationList *e = cls;
struct TransportPlugin *tp;
struct ValidationAddress *va;
- struct ValidationChallengeMessage *vcm;
struct GNUNET_PeerIdentity id;
-
+ struct GNUNET_MessageHeader *pingMessage;
tp = find_transport (tname);
if (tp == NULL)
{
return GNUNET_OK;
}
GNUNET_CRYPTO_hash (&e->publicKey,
- sizeof (struct
- GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
- &id.hashPubKey);
+ sizeof (struct
+ GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
+ &id.hashPubKey);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Scheduling validation of address `%s' via `%s' for `%4s'\n",
- GNUNET_a2s(addr, addrlen),
- tname,
- GNUNET_i2s(&id));
+ "Scheduling validation of address `%s' via `%s' for `%4s'\n",
+ GNUNET_a2s (addr, addrlen), tname, GNUNET_i2s (&id));
- va = GNUNET_malloc (sizeof (struct ValidationAddress) +
- sizeof (struct ValidationChallengeMessage) + addrlen);
+ va = GNUNET_malloc (sizeof (struct ValidationAddress) + addrlen);
va->next = e->addresses;
e->addresses = va;
- vcm = (struct ValidationChallengeMessage *) &va[1];
- va->msg = vcm;
va->transport_name = GNUNET_strdup (tname);
va->addr_len = addrlen;
- vcm->header.size =
- htons (sizeof (struct ValidationChallengeMessage) + addrlen);
- vcm->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
- vcm->purpose.size =
- htonl (sizeof (struct ValidationChallengeMessage) + addrlen -
- sizeof (struct GNUNET_MessageHeader));
- vcm->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_HELLO);
- vcm->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
- (unsigned int) -1);
- vcm->target = id;
- memcpy (&vcm[1], addr, addrlen);
+ va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
+ (unsigned int) -1);
+ memcpy (&va[1], addr, addrlen);
+
+ pingMessage = createPingMessage(&id, va);
+
+ tp->api->send(tp->api->cls, &id, pingMessage, GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+ TRANSPORT_DEFAULT_TIMEOUT, addr, addrlen, GNUNET_YES, NULL, NULL);
+
+ GNUNET_free(pingMessage);
+
return GNUNET_OK;
}
+/*
+ * @param cls handle to the plugin (for sending)
+ * @param target the peer identity of the peer we are sending to
+ * @param challenge the challenge number
+ * @param timeout how long to await validation?
+ * @param addr the address to validate
+ * @param addrlen the length of the address
+ *
+ * Perform address validation, which means sending a PING PONG to
+ * the address via the transport plugin. If not validated, then
+ * do not count this as a good peer/address...
+ *
+ */
+static void
+validate_address (void *cls, struct ValidationAddress *va,
+ const struct GNUNET_PeerIdentity *target,
+ struct GNUNET_TIME_Relative timeout,
+ const void *addr, size_t addrlen)
+{
+ /* struct Plugin *plugin = cls;
+ int challenge = va->challenge; */
+
+
+ return;
+}
+
/**
* Check if addresses in validated hello "h" overlap with
struct ValidationAddress *va;
struct TransportPlugin *tp;
int first_call;
+ struct GNUNET_PeerIdentity apeer;
first_call = GNUNET_NO;
if (chvc->e == NULL)
{
+ chvc->piter = NULL;
first_call = GNUNET_YES;
chvc->e = GNUNET_malloc (sizeof (struct ValidationList));
GNUNET_assert (GNUNET_OK ==
if (h != NULL)
return; /* wait for next call */
/* finally, transmit validation attempts */
+ GNUNET_assert (GNUNET_OK == GNUNET_HELLO_get_id (chvc->hello, &apeer));
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Ready to validate addresses from `%s' message for peer `%4s'\n",
+ "HELLO", GNUNET_i2s (&apeer));
+#endif
va = chvc->e->addresses;
while (va != NULL)
{
#if DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Establishing `%s' connection to validate `%s' of `%4s' (sending our `%s')\n",
+ "Establishing `%s' connection to validate `%s' address `%s' of `%4s'\n",
va->transport_name,
- "HELLO", GNUNET_i2s (&va->msg->target), "HELLO");
+ "HELLO",
+ GNUNET_a2s ((const struct sockaddr *) &va[1],
+ va->addr_len), GNUNET_i2s (&apeer));
#endif
tp = find_transport (va->transport_name);
GNUNET_assert (tp != NULL);
- if (NULL ==
- tp->api->send_to (tp->api->cls,
- &va->msg->target,
- (const struct GNUNET_MessageHeader *) our_hello,
- &va->msg->header,
- HELLO_VERIFICATION_TIMEOUT,
- &va->msg[1], va->addr_len))
- va->ok = GNUNET_SYSERR;
+ /* This validation should happen inside the transport, not from the plugin! */
+ validate_address (tp->api->cls, va, &apeer,
+ HELLO_VERIFICATION_TIMEOUT,
+ &va[1], va->addr_len);
+ /* va->ok = GNUNET_SYSERR; will be set by validate_address! */
va = va->next;
}
- if (chvc->e->next == NULL)
- GNUNET_SCHEDULER_add_delayed (sched,
- GNUNET_NO,
- GNUNET_SCHEDULER_PRIORITY_IDLE,
- GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
- GNUNET_TIME_absolute_get_remaining
- (chvc->e->timeout), &cleanup_validation,
- NULL);
+ GNUNET_SCHEDULER_add_delayed (sched,
+ GNUNET_TIME_absolute_get_remaining (chvc->
+ e->timeout),
+ &cleanup_validation, NULL);
GNUNET_free (chvc);
}
{
/* TODO: call to stats? */
#if DEBUG_TRANSPORT
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "`%s' message for peer `%4s' is already pending; ignoring new message\n",
- "HELLO", GNUNET_i2s (&target));
-#endif
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "`%s' message for peer `%4s' is already pending; ignoring new message\n",
+ "HELLO", GNUNET_i2s (&target));
+#endif
return GNUNET_OK;
}
e = e->next;
memcpy (chvc->hello, hello, hsize);
/* finally, check if HELLO was previously validated
(continuation will then schedule actual validation) */
- GNUNET_PEERINFO_for_all (cfg,
- sched,
- &target,
- 0,
- HELLO_VERIFICATION_TIMEOUT,
- &check_hello_validated, chvc);
+ chvc->piter = GNUNET_PEERINFO_iterate (cfg,
+ sched,
+ &target,
+ 0,
+ HELLO_VERIFICATION_TIMEOUT,
+ &check_hello_validated, chvc);
return GNUNET_OK;
}
/**
- * Handle PING-message. If the plugin that gave us the message is
- * able to queue the PONG immediately, we only queue one PONG.
- * Otherwise we send at most TWO PONG messages, one via an unconfirmed
- * transport and one via a confirmed transport. Both addresses are
- * selected randomly among those available.
+ * The peer specified by the given neighbor has timed-out or a plugin
+ * has disconnected. We may either need to do nothing (other plugins
+ * still up), or trigger a full disconnect and clean up. This
+ * function updates our state and do the necessary notifications.
+ * Also notifies our clients that the neighbor is now officially
+ * gone.
*
- * @param plugin plugin that gave us the message
- * @param sender claimed sender of the PING
- * @param plugin_context context that might be used to send response
- * @param message the actual message
+ * @param n the neighbor list entry for the peer
+ * @param check should we just check if all plugins
+ * disconnected or must we ask all plugins to
+ * disconnect?
*/
static void
-process_ping (struct TransportPlugin *plugin,
- const struct GNUNET_PeerIdentity *sender,
- void *plugin_context,
- const struct GNUNET_MessageHeader *message)
+disconnect_neighbor (struct NeighborList *n, int check)
{
- const struct ValidationChallengeMessage *vcm;
- struct ValidationChallengeResponse vcr;
- uint16_t msize;
- struct NeighbourList *n;
-
-#if DEBUG_TRANSPORT
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
- "Processing PING\n");
-#endif
- msize = ntohs (message->size);
- if (msize < sizeof (struct ValidationChallengeMessage))
- {
- GNUNET_break_op (0);
- return;
- }
- vcm = (const struct ValidationChallengeMessage *) message;
- if (0 != memcmp (&vcm->target,
- &my_identity, sizeof (struct GNUNET_PeerIdentity)))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- _("Received `%s' message not destined for me!\n"), "PING");
- /* TODO: call statistics */
- return;
- }
- if ((ntohl (vcm->purpose.size) !=
- msize - sizeof (struct GNUNET_MessageHeader))
- || (ntohl (vcm->purpose.purpose) !=
- GNUNET_SIGNATURE_PURPOSE_TRANSPORT_HELLO))
- {
- GNUNET_break_op (0);
- return;
- }
- msize -= sizeof (struct ValidationChallengeMessage);
- if (GNUNET_OK !=
- plugin->api->address_suggested (plugin->api->cls, &vcm[1], msize))
- {
- GNUNET_break_op (0);
- return;
- }
- vcr.header.size = htons (sizeof (struct ValidationChallengeResponse));
- vcr.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
- vcr.challenge = vcm->challenge;
- vcr.sender = my_identity;
- GNUNET_assert (GNUNET_OK ==
- GNUNET_CRYPTO_rsa_sign (my_private_key,
- &vcm->purpose, &vcr.signature));
-#if EXTRA_CHECKS
- GNUNET_assert (GNUNET_OK ==
- GNUNET_CRYPTO_rsa_verify
- (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_HELLO, &vcm->purpose,
- &vcr.signature, &my_public_key));
-#endif
-#if DEBUG_TRANSPORT
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
- "Trying to transmit PONG using inbound connection\n");
-#endif
- n = find_neighbour (sender);
- if (n == NULL)
- {
- GNUNET_break (0);
- return;
- }
- transmit_to_peer (NULL, &vcr.header, GNUNET_YES, n);
-}
-
-
-/**
- * Handle PONG-message.
- *
- * @param message the actual message
- */
-static void
-process_pong (struct TransportPlugin *plugin,
- const struct GNUNET_MessageHeader *message)
-{
- const struct ValidationChallengeResponse *vcr;
- struct ValidationList *pos;
- struct GNUNET_PeerIdentity peer;
- struct ValidationAddress *va;
- int all_done;
- int matched;
+ struct ReadyList *rpos;
+ struct NeighborList *npos;
+ struct NeighborList *nprev;
+ struct MessageQueue *mq;
-#if DEBUG_TRANSPORT
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
- "Processing PONG\n");
-#endif
- vcr = (const struct ValidationChallengeResponse *) message;
- pos = pending_validations;
- while (pos != NULL)
+ if (GNUNET_YES == check)
{
- GNUNET_CRYPTO_hash (&pos->publicKey,
- sizeof (struct
- GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
- &peer.hashPubKey);
- if (0 ==
- memcmp (&peer, &vcr->sender, sizeof (struct GNUNET_PeerIdentity)))
- break;
- pos = pos->next;
- }
- if (pos == NULL)
- {
- /* TODO: call statistics (unmatched PONG) */
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- _
- ("Received `%s' message but have no record of a matching `%s' message. Ignoring.\n"),
- "PONG", "PING");
- return;
- }
- all_done = GNUNET_YES;
- matched = GNUNET_NO;
- va = pos->addresses;
- while (va != NULL)
- {
- if (va->msg->challenge == vcr->challenge)
+ rpos = n->plugins;
+ while (NULL != rpos)
{
- if (GNUNET_OK !=
- GNUNET_CRYPTO_rsa_verify
- (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_HELLO, &va->msg->purpose,
- &vcr->signature, &pos->publicKey))
- {
- /* this could rarely happen if we used the same
- challenge number for the peer for two different
- transports / addresses, but the likelihood is
- very small... */
- GNUNET_break_op (0);
- }
- else
- {
-#if DEBUG_TRANSPORT
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Confirmed validity of peer address.\n");
-#endif
- va->ok = GNUNET_YES;
- va->expiration =
- GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
- matched = GNUNET_YES;
- }
+ if (GNUNET_YES == rpos->connected)
+ return; /* still connected */
+ rpos = rpos->next;
}
- if (va->ok != GNUNET_YES)
- all_done = GNUNET_NO;
- va = va->next;
- }
- if (GNUNET_NO == matched)
- {
- /* TODO: call statistics (unmatched PONG) */
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- _
- ("Received `%s' message but have no record of a matching `%s' message. Ignoring.\n"),
- "PONG", "PING");
}
- if (GNUNET_YES == all_done)
- {
- pos->timeout.value = 0;
- GNUNET_SCHEDULER_add_delayed (sched,
- GNUNET_NO,
- GNUNET_SCHEDULER_PRIORITY_IDLE,
- GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
- GNUNET_TIME_UNIT_ZERO,
- &cleanup_validation, NULL);
- }
-}
-
-
-/**
- * The peer specified by the given neighbour has timed-out. Update
- * our state and do the necessary notifications. Also notifies
- * our clients that the neighbour is now officially gone.
- *
- * @param n the neighbour list entry for the peer
- */
-static void
-disconnect_neighbour (struct NeighbourList *n)
-{
- struct ReadyList *rpos;
- struct NeighbourList *npos;
- struct NeighbourList *nprev;
- struct MessageQueue *mq;
#if DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
- "Disconnecting from neighbour\n");
+ "Disconnecting from `%4s'\n", GNUNET_i2s (&n->id));
#endif
- /* remove n from neighbours list */
+ /* remove n from neighbors list */
nprev = NULL;
- npos = neighbours;
+ npos = neighbors;
while ((npos != NULL) && (npos != n))
{
nprev = npos;
}
GNUNET_assert (npos != NULL);
if (nprev == NULL)
- neighbours = n->next;
+ neighbors = n->next;
else
nprev->next = n->next;
/* notify all clients about disconnect */
notify_clients_disconnect (&n->id);
- /* clean up all plugins, cancel connections & pending transmissions */
+ /* clean up all plugins, cancel connections and pending transmissions */
while (NULL != (rpos = n->plugins))
{
n->plugins = rpos->next;
- GNUNET_assert (rpos->neighbour == n);
- rpos->plugin->api->cancel (rpos->plugin->api->cls,
- rpos->plugin_handle, rpos, &n->id);
+ GNUNET_assert (rpos->neighbor == n);
+ if (GNUNET_YES == rpos->connected)
+ rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
GNUNET_free (rpos);
}
while (NULL != (mq = n->messages))
{
n->messages = mq->next;
- GNUNET_assert (mq->neighbour == n);
+ GNUNET_assert (mq->neighbor == n);
GNUNET_free (mq);
}
-
+ if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (sched, n->timeout_task);
/* finally, free n itself */
GNUNET_free (n);
}
/**
* Add an entry for each of our transport plugins
* (that are able to send) to the list of plugins
- * for this neighbour.
+ * for this neighbor.
*
- * @param neighbour to initialize
+ * @param neighbor to initialize
*/
static void
-add_plugins (struct NeighbourList *neighbour)
+add_plugins (struct NeighborList *neighbor)
{
struct TransportPlugin *tp;
struct ReadyList *rl;
- neighbour->retry_plugins_time
+ neighbor->retry_plugins_time
= GNUNET_TIME_relative_to_absolute (PLUGIN_RETRY_FREQUENCY);
tp = plugins;
while (tp != NULL)
if (tp->api->send != NULL)
{
rl = GNUNET_malloc (sizeof (struct ReadyList));
- rl->next = neighbour->plugins;
- neighbour->plugins = rl;
+ rl->next = neighbor->plugins;
+ neighbor->plugins = rl;
rl->plugin = tp;
- rl->neighbour = neighbour;
+ rl->neighbor = neighbor;
rl->transmit_ready = GNUNET_YES;
}
tp = tp->next;
static void
-neighbour_timeout_task (void *cls,
+neighbor_timeout_task (void *cls,
const struct GNUNET_SCHEDULER_TaskContext *tc)
{
- struct NeighbourList *n = cls;
+ struct NeighborList *n = cls;
#if DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
- "Neighbour has timed out!\n");
+ "Neighbor `%4s' has timed out!\n", GNUNET_i2s (&n->id));
#endif
- n->timeout_task = GNUNET_SCHEDULER_NO_PREREQUISITE_TASK;
- disconnect_neighbour (n);
+ n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
+ disconnect_neighbor (n, GNUNET_NO);
}
-
/**
- * Create a fresh entry in our neighbour list for the given peer.
- * Will try to transmit our current HELLO to the new neighbour. Also
+ * Create a fresh entry in our neighbor list for the given peer.
+ * Will try to transmit our current HELLO to the new neighbor. Also
* notifies our clients about the new "connection".
*
* @param peer the peer for which we create the entry
- * @return the new neighbour list entry
+ * @return the new neighbor list entry
*/
-static struct NeighbourList *
-setup_new_neighbour (const struct GNUNET_PeerIdentity *peer)
+static struct NeighborList *
+setup_new_neighbor (const struct GNUNET_PeerIdentity *peer, const char *addr, size_t sender_address_len)
{
- struct NeighbourList *n;
+ struct NeighborList *n;
#if DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
- "Setting up new neighbour `%4s', sending our HELLO to introduce ourselves\n",
+ "Setting up new neighbor `%4s', sending our HELLO to introduce ourselves\n",
GNUNET_i2s (peer));
#endif
GNUNET_assert (our_hello != NULL);
- n = GNUNET_malloc (sizeof (struct NeighbourList));
- n->next = neighbours;
- neighbours = n;
+ n = GNUNET_malloc (sizeof (struct NeighborList));
+ n->next = neighbors;
+ neighbors = n;
n->id = *peer;
n->last_quota_update = GNUNET_TIME_absolute_get ();
n->peer_timeout =
- GNUNET_TIME_relative_to_absolute (IDLE_CONNECTION_TIMEOUT);
- n->quota_in = default_quota_in;
+ GNUNET_TIME_relative_to_absolute
+ (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
+ n->quota_in = (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT + 59999) / (60 * 1000);
add_plugins (n);
- n->hello_version_sent = our_hello_version;
n->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
- GNUNET_NO,
- GNUNET_SCHEDULER_PRIORITY_IDLE,
- GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
- IDLE_CONNECTION_TIMEOUT,
- &neighbour_timeout_task, n);
- transmit_to_peer (NULL,
+ GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
+ &neighbor_timeout_task, n);
+ transmit_to_peer (NULL, 0,
(const struct GNUNET_MessageHeader *) our_hello,
GNUNET_YES, n);
notify_clients_connect (peer, GNUNET_TIME_UNIT_FOREVER_REL);
return n;
}
+/*
+ * We have received a PING message from someone. Need to send a PONG message
+ * in response to the peer by any means necessary. Of course, with something
+ * like TCP where a connection exists, we may want to send it that way. But
+ * we may not be able to make that distinction...
+ */
+static int handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
+ const struct GNUNET_PeerIdentity *peer,
+ const char *sender_address,
+ size_t sender_address_len)
+{
+ struct TransportPlugin *plugin = cls;
+ struct TransportPingMessage *ping;
+ struct TransportPongMessage *pong;
+ uint16_t msize;
+
+ pong = GNUNET_malloc(sizeof(struct TransportPongMessage));
+
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
+ "Processing `%s' from `%s'\n",
+ "PING", GNUNET_a2s ((const struct sockaddr *)sender_address, sender_address_len));
+#endif
+
+ msize = ntohs (message->size);
+ if (msize < sizeof (struct TransportPingMessage))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ ping = (struct TransportPingMessage *) message;
+ if (0 != memcmp (&ping->target,
+ plugin->env.my_identity,
+ sizeof (struct GNUNET_PeerIdentity)))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _("Received `%s' message not destined for me!\n"), "PING");
+ return GNUNET_SYSERR;
+ }
+
+ msize -= sizeof (struct TransportPingMessage);
+/*
+ * if (GNUNET_OK != tcp_plugin_address_suggested (plugin, &vcm[1], msize))
+ {
+ GNUNET_break_op (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+
+ if (GNUNET_OK != GNUNET_SERVER_client_get_address (client, &addr, &addrlen))
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+*/
+ pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len);
+ pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len);
+ pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
+ pong->purpose.size =
+ htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
+ sizeof (uint32_t) +
+ sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + sender_address_len);
+ pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_TCP_PING);
+ pong->challenge = ping->challenge;
+
+ memcpy(&pong->signer, &my_public_key, sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
+ memcpy (&pong[1], sender_address, sender_address_len);
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CRYPTO_rsa_sign (my_private_key,
+ &pong->purpose, &pong->signature));
+
+ transmit_to_peer(NULL, TRANSPORT_DEFAULT_PRIORITY, &pong->header, GNUNET_NO, find_neighbor(peer, NULL, 0));
+ /* plugin->api->send(); */ /* We can't directly send back along received address, because
+ the port we saw for the peer (for TCP especially) will not
+ likely be the open port on the other side! */
+ GNUNET_free(pong);
+ return GNUNET_OK;
+}
/**
* Function called by the plugin for each received message.
* reducing the rate at which they read from the socket
* and generally forward to our receive callback.
*
- * @param plugin_context value to pass to this plugin
- * to respond to the given peer (use is optional,
- * but may speed up processing)
- * @param service_context value passed to the transport-service
- * to identify the neighbour; will be NULL on the first
- * call for a given peer
- * @param latency estimated latency for communicating with the
- * given peer
- * @param peer (claimed) identity of the other peer
+ * @param cls the "struct TransportPlugin *" we gave to the plugin
* @param message the message, NULL if peer was disconnected
+ * @param distance the transport cost to this peer (not latency!)
+ * @param sender_address the address that the sender reported
+ * (opaque to transport service)
+ * @param sender_address_len the length of the sender address
+ * @param peer (claimed) identity of the other peer
* @return the new service_context that the plugin should use
* for future receive calls for messages from this
* particular peer
+ *
*/
-static struct ReadyList *
-plugin_env_receive (void *cls,
- void *plugin_context,
- struct ReadyList *service_context,
- struct GNUNET_TIME_Relative latency,
- const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_MessageHeader *message)
+static void
+plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_MessageHeader *message,
+ unsigned int distance, const char *sender_address,
+ size_t sender_address_len)
{
const struct GNUNET_MessageHeader ack = {
htons (sizeof (struct GNUNET_MessageHeader)),
htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ACK)
};
+ struct ReadyList *service_context;
struct TransportPlugin *plugin = cls;
struct TransportClient *cpos;
struct InboundMessage *im;
uint16_t msize;
- struct NeighbourList *n;
+ struct NeighborList *n;
- if (service_context != NULL)
+ n = find_neighbor (peer, sender_address, sender_address_len);
+ if (n == NULL)
{
- n = service_context->neighbour;
- GNUNET_assert (n != NULL);
- }
- else
- {
- n = find_neighbour (peer);
- if (n == NULL)
- {
- if (message == NULL)
- return NULL; /* disconnect of peer already marked down */
- n = setup_new_neighbour (peer);
- }
- service_context = n->plugins;
- while ((service_context != NULL) && (plugin != service_context->plugin))
- service_context = service_context->next;
- GNUNET_assert ((plugin->api->send == NULL) ||
- (service_context != NULL));
+ if (message == NULL)
+ return; /* disconnect of peer already marked down */
+ n = setup_new_neighbor (peer, sender_address, sender_address_len);
}
+ service_context = n->plugins;
+ while ((service_context != NULL) && (plugin != service_context->plugin))
+ service_context = service_context->next;
+ GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
if (message == NULL)
{
- if ((service_context != NULL) &&
- (service_context->plugin_handle == plugin_context))
- {
- service_context->connected = GNUNET_NO;
- service_context->plugin_handle = NULL;
- }
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
+ "Receive failed from `%4s', triggering disconnect\n",
+ GNUNET_i2s (&n->id));
+#endif
/* TODO: call stats */
- return NULL;
+ if (service_context != NULL)
+ service_context->connected = GNUNET_NO;
+ disconnect_neighbor (n, GNUNET_YES);
+ return;
}
#if DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
service_context->connect_attempts++;
}
service_context->timeout
- = GNUNET_TIME_relative_to_absolute (IDLE_CONNECTION_TIMEOUT);
- service_context->plugin_handle = plugin_context;
- service_context->latency = latency;
+ =
+ GNUNET_TIME_relative_to_absolute
+ (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
+ /* service_context->latency = latency; */ /* This value should be set by us! */
}
/* update traffic received amount ... */
msize = ntohs (message->size);
n->last_received += msize;
GNUNET_SCHEDULER_cancel (sched, n->timeout_task);
n->peer_timeout =
- GNUNET_TIME_relative_to_absolute (IDLE_CONNECTION_TIMEOUT);
+ GNUNET_TIME_relative_to_absolute
+ (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
n->timeout_task =
- GNUNET_SCHEDULER_add_delayed (sched, GNUNET_NO,
- GNUNET_SCHEDULER_PRIORITY_IDLE,
- GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
- IDLE_CONNECTION_TIMEOUT,
- &neighbour_timeout_task, n);
+ GNUNET_SCHEDULER_add_delayed (sched,
+ GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
+ &neighbor_timeout_task, n);
update_quota (n);
if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
{
_
("Dropping incoming message due to repeated bandwidth quota violations.\n"));
/* TODO: call stats */
- GNUNET_assert (NULL != service_context->neighbour);
- return service_context;
+ GNUNET_assert ((service_context == NULL) ||
+ (NULL != service_context->neighbor));
+ return;
}
switch (ntohs (message->type))
{
case GNUNET_MESSAGE_TYPE_HELLO:
#if DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Receiving `%s' message from other peer.\n", "HELLO");
+ "Receiving `%s' message from `%4s'.\n", "HELLO",
+ GNUNET_i2s (peer));
#endif
process_hello (plugin, message);
#if DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Sending `%s' message to connecting peer.\n", "ACK");
+ "Sending `%s' message to connecting peer `%4s'.\n", "ACK",
+ GNUNET_i2s (peer));
#endif
- transmit_to_peer (NULL, &ack, GNUNET_YES, n);
+ transmit_to_peer (NULL, 0, &ack, GNUNET_YES, n);
break;
case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
- process_ping (plugin, peer, plugin_context, message);
- break;
+ handle_ping(plugin, message, peer, sender_address, sender_address_len);
case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
- process_pong (plugin, message);
- break;
+ handle_pong(plugin, message, peer, sender_address, sender_address_len);
+ //plugin_env_notify_validation();
case GNUNET_MESSAGE_TYPE_TRANSPORT_ACK:
n->saw_ack = GNUNET_YES;
/* intentional fall-through! */
default:
#if DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Received message of type %u from other peer, sending to all clients.\n",
- ntohs (message->type));
+ "Received message of type %u from `%4s', sending to all clients.\n",
+ ntohs (message->type), GNUNET_i2s (peer));
#endif
/* transmit message to all clients */
im = GNUNET_malloc (sizeof (struct InboundMessage) + msize);
im->header.size = htons (sizeof (struct InboundMessage) + msize);
im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
- im->latency = GNUNET_TIME_relative_hton (latency);
+ im->latency = n->latency;
im->peer = *peer;
memcpy (&im[1], message, msize);
}
GNUNET_free (im);
}
- GNUNET_assert (NULL != service_context->neighbour);
- return service_context;
+ GNUNET_assert ((service_context == NULL) ||
+ (NULL != service_context->neighbor));
}
{
struct TransportClient *c;
struct ConnectInfoMessage cim;
- struct NeighbourList *n;
+ struct NeighborList *n;
struct InboundMessage *im;
struct GNUNET_MessageHeader *ack;
{
#if DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Sending our own HELLO to new client\n");
+ "Sending our own `%s' to new client\n", "HELLO");
#endif
transmit_to_client (c,
(const struct GNUNET_MessageHeader *) our_hello,
/* tell new client about all existing connections */
cim.header.size = htons (sizeof (struct ConnectInfoMessage));
cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
- cim.quota_out = htonl (default_quota_out);
+ cim.quota_out =
+ htonl (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT / (60 * 1000));
cim.latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO); /* FIXME? */
im = GNUNET_malloc (sizeof (struct InboundMessage) +
sizeof (struct GNUNET_MessageHeader));
ack = (struct GNUNET_MessageHeader *) &im[1];
ack->size = htons (sizeof (struct GNUNET_MessageHeader));
ack->type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ACK);
- for (n = neighbours; n != NULL; n = n->next)
+ for (n = neighbors; n != NULL; n = n->next)
{
cim.id = n->id;
transmit_to_client (c, &cim.header, GNUNET_NO);
const struct GNUNET_MessageHeader *message)
{
struct TransportClient *tc;
- struct NeighbourList *n;
+ struct NeighborList *n;
const struct OutboundMessage *obm;
const struct GNUNET_MessageHeader *obmm;
uint16_t size;
GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
return;
}
- n = find_neighbour (&obm->peer);
+ n = find_neighbor (&obm->peer, NULL, 0);
if (n == NULL)
- n = setup_new_neighbour (&obm->peer);
+ n = setup_new_neighbor (&obm->peer, NULL, 0);
tc = clients;
while ((tc != NULL) && (tc->client != client))
tc = tc->next;
ntohs (obmm->size),
ntohs (obmm->type), GNUNET_i2s (&obm->peer));
#endif
- transmit_to_peer (tc, obmm, GNUNET_NO, n);
+ transmit_to_peer (tc, ntohl (obm->priority), obmm, GNUNET_NO, n);
GNUNET_SERVER_receive_done (client, GNUNET_OK);
}
{
const struct QuotaSetMessage *qsm =
(const struct QuotaSetMessage *) message;
- struct NeighbourList *n;
+ struct NeighborList *n;
struct TransportPlugin *p;
struct ReadyList *rl;
"Received `%s' request from client for peer `%4s'\n",
"SET_QUOTA", GNUNET_i2s (&qsm->peer));
#endif
- n = find_neighbour (&qsm->peer);
+ n = find_neighbor (&qsm->peer, NULL, 0);
if (n == NULL)
{
GNUNET_SERVER_receive_done (client, GNUNET_OK);
tcm = (const struct TryConnectMessage *) message;
#if DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Received `%s' request from client asking to connect to `%4s'\n",
- "TRY_CONNECT", GNUNET_i2s (&tcm->peer));
+ "Received `%s' request from client %p asking to connect to `%4s'\n",
+ "TRY_CONNECT", client, GNUNET_i2s (&tcm->peer));
+#endif
+ if (NULL == find_neighbor (&tcm->peer, NULL, 0))
+ setup_new_neighbor (&tcm->peer, NULL, 0); /* Can we set up a truly _new_ neighbor without
+ knowing its address? Should we ask the plugin
+ for more information about this peer? I don't
+ think we can... Or set up new peer should only
+ happen when transport notifies us of an address,
+ and this setup should check for an address in
+ the existing list only */
+#if DEBUG_TRANSPORT
+ else
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Client asked to connect to `%4s', but connection already exists\n",
+ "TRY_CONNECT", GNUNET_i2s (&tcm->peer));
#endif
- if (NULL == find_neighbour (&tcm->peer))
- setup_new_neighbour (&tcm->peer);
GNUNET_SERVER_receive_done (client, GNUNET_OK);
}
+static void
+transmit_address_to_client (void *cls, const char *address)
+{
+ struct GNUNET_SERVER_TransmitContext *tc = cls;
+ size_t slen;
+
+ if (NULL == address)
+ slen = 0;
+ else
+ slen = strlen (address) + 1;
+ GNUNET_SERVER_transmit_context_append (tc, address, slen,
+ GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
+ if (NULL == address)
+ GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
+}
+
+/**
+ * Handle AddressLookup-message.
+ *
+ * @param cls closure (always NULL)
+ * @param client identification of the client
+ * @param message the actual message
+ */
+static void
+handle_address_lookup (void *cls,
+ struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ const struct AddressLookupMessage *alum;
+ struct TransportPlugin *lsPlugin;
+ const char *nameTransport;
+ const char *address;
+ uint16_t size;
+ struct GNUNET_SERVER_TransmitContext *tc;
+
+ size = ntohs (message->size);
+ if (size < sizeof (struct AddressLookupMessage))
+ {
+ GNUNET_break_op (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ alum = (const struct AddressLookupMessage *) message;
+ uint32_t addressLen = ntohl (alum->addrlen);
+ if (size <= sizeof (struct AddressLookupMessage) + addressLen)
+ {
+ GNUNET_break_op (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ address = (const char *) &alum[1];
+ nameTransport = (const char *) &address[addressLen];
+ if (nameTransport
+ [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
+ {
+ GNUNET_break_op (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ struct GNUNET_TIME_Absolute timeout =
+ GNUNET_TIME_absolute_ntoh (alum->timeout);
+ struct GNUNET_TIME_Relative rtimeout =
+ GNUNET_TIME_absolute_get_remaining (timeout);
+ lsPlugin = find_transport (nameTransport);
+ if (NULL == lsPlugin)
+ {
+ tc = GNUNET_SERVER_transmit_context_create (client);
+ GNUNET_SERVER_transmit_context_append (tc, NULL, 0,
+ GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
+ GNUNET_SERVER_transmit_context_run (tc, rtimeout);
+ return;
+ }
+ tc = GNUNET_SERVER_transmit_context_create (client);
+ lsPlugin->api->address_pretty_printer (cls, nameTransport,
+ address, addressLen, GNUNET_YES,
+ rtimeout,
+ &transmit_address_to_client, tc);
+}
/**
* List of handlers for the messages understood by this
{&handle_try_connect, NULL,
GNUNET_MESSAGE_TYPE_TRANSPORT_TRY_CONNECT,
sizeof (struct TryConnectMessage)},
+ {&handle_address_lookup, NULL,
+ GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
+ 0},
{NULL, NULL, 0, 0}
};
{
plug->env.cfg = cfg;
plug->env.sched = sched;
- plug->env.my_public_key = &my_public_key;
+ plug->env.my_identity = &my_identity;
plug->env.cls = plug;
plug->env.receive = &plugin_env_receive;
- plug->env.lookup = &plugin_env_lookup_address;
plug->env.notify_address = &plugin_env_notify_address;
- plug->env.default_quota_in = default_quota_in;
+ plug->env.default_quota_in =
+ (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT + 59999) / (60 * 1000);
plug->env.max_connections = max_connect_per_transport;
}
struct TransportClient *prev;
struct ClientMessageQueueEntry *mqe;
+ if (client == NULL)
+ return;
#if DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
"Client disconnected, cleaning up.\n");
}
+/**
+ * Function called when the service shuts down. Unloads our plugins.
+ *
+ * @param cls closure, unused
+ * @param tc task context (unused)
+ */
+static void
+unload_plugins (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct TransportPlugin *plug;
+ struct AddressList *al;
+
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Transport service is unloading plugins...\n");
+#endif
+ while (NULL != (plug = plugins))
+ {
+ plugins = plug->next;
+ GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
+ GNUNET_free (plug->lib_name);
+ GNUNET_free (plug->short_name);
+ while (NULL != (al = plug->addresses))
+ {
+ plug->addresses = al->next;
+ GNUNET_free (al);
+ }
+ GNUNET_free (plug);
+ }
+ if (my_private_key != NULL)
+ GNUNET_CRYPTO_rsa_key_free (my_private_key);
+ GNUNET_free_non_null (our_hello);
+}
+
+
/**
* Initiate transport service.
*
static void
run (void *cls,
struct GNUNET_SCHEDULER_Handle *s,
- struct GNUNET_SERVER_Handle *serv, struct GNUNET_CONFIGURATION_Handle *c)
+ struct GNUNET_SERVER_Handle *serv,
+ const struct GNUNET_CONFIGURATION_Handle *c)
{
char *plugs;
char *pos;
int no_transports;
- unsigned long long qin;
- unsigned long long qout;
unsigned long long tneigh;
char *keyfile;
cfg = c;
/* parse configuration */
if ((GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_number (c,
- "TRANSPORT",
- "DEFAULT_QUOTA_IN",
- &qin)) ||
- (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_number (c,
- "TRANSPORT",
- "DEFAULT_QUOTA_OUT",
- &qout)) ||
- (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_number (c,
"TRANSPORT",
"NEIGHBOUR_LIMIT",
return;
}
max_connect_per_transport = (uint32_t) tneigh;
- default_quota_in = (uint32_t) qin;
- default_quota_out = (uint32_t) qout;
my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
GNUNET_free (keyfile);
if (my_private_key == NULL)
}
GNUNET_free (plugs);
}
+ GNUNET_SCHEDULER_add_delayed (sched,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ &unload_plugins, NULL);
if (no_transports)
refresh_hello ();
+#if DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
+#endif
/* process client requests */
GNUNET_SERVER_add_handlers (server, handlers);
}
-/**
- * Function called when the service shuts
- * down. Unloads our plugins.
- *
- * @param cls closure
- * @param cfg configuration to use
- */
-static void
-unload_plugins (void *cls, struct GNUNET_CONFIGURATION_Handle *cfg)
-{
- struct TransportPlugin *plug;
- struct AddressList *al;
-
-#if DEBUG_TRANSPORT
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Transport service is unloading plugins...\n");
-#endif
- while (NULL != (plug = plugins))
- {
- plugins = plug->next;
- GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
- GNUNET_free (plug->lib_name);
- GNUNET_free (plug->short_name);
- while (NULL != (al = plug->addresses))
- {
- plug->addresses = al->next;
- GNUNET_free (al);
- }
- GNUNET_free (plug);
- }
- if (my_private_key != NULL)
- GNUNET_CRYPTO_rsa_key_free (my_private_key);
-}
-
-
/**
* The main function for the transport service.
*
GNUNET_SERVICE_run (argc,
argv,
"transport",
- &run, NULL, &unload_plugins, NULL)) ? 0 : 1;
+ GNUNET_SERVICE_OPTION_NONE,
+ &run, NULL)) ? 0 : 1;
}
/* end of gnunet-service-transport.c */