/**
* 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 often do we re-add (cheaper) plugins to our list of plugins
/**
* Our configuration.
*/
-struct GNUNET_CONFIGURATION_Handle *cfg;
+const struct GNUNET_CONFIGURATION_Handle *cfg;
/**
* Linked list of all clients to this service.
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)
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 */
/**
- * Check the ready list for the given neighbour and
- * if a plugin is ready for transmission (and if we
- * have a message), do so!
+ * The peer specified by the given neighbour 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 neighbour is now officially
+ * gone.
*
- * @param neighbour target peer for which to check the plugins
+ * @param n the neighbour 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 try_transmission_to_peer (struct NeighbourList *neighbour);
+static void
+disconnect_neighbour (struct NeighbourList *n,
+ int check);
/**
- * 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.
+ * Check the ready list for the given neighbour and
+ * if a plugin is ready for transmission (and if we
+ * have a message), do so!
*
- * @param n the neighbour list entry for the peer
+ * @param neighbour target peer for which to check the plugins
*/
-static void
-disconnect_neighbour (struct NeighbourList *n);
+static void
+try_transmission_to_peer (struct NeighbourList *neighbour);
/**
"Transmission to peer `%s' failed, marking connection as down.\n",
GNUNET_i2s(target));
rl->connected = GNUNET_NO;
+ rl->plugin_handle = NULL;
}
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);
another message (if available) */
if (result == GNUNET_OK)
try_transmission_to_peer (n);
- else
- disconnect_neighbour (n);
+ else
+ disconnect_neighbour (n, GNUNET_YES);
}
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 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 NeighbourList *n;
/* finally, reschedule cleanup if needed; list is
ordered by timeout, so we need the last element... */
- 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);
+ 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);
+ }
}
uint32_t challenge,
const char *sender_addr)
{
- int all_done;
+ unsigned int not_done;
int matched;
struct ValidationList *pos;
struct ValidationAddress *va;
GNUNET_i2s(peer));
return;
}
- all_done = GNUNET_YES;
+ not_done = 0;
matched = GNUNET_NO;
va = pos->addresses;
while (va != NULL)
{
#if DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Confirmed validity of peer address.\n");
+ "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 `%s'. If this is not plausible, this address should be listed in the configuration as implausible to avoid MiM attacks.\n"),
matched = GNUNET_YES;
}
if (va->ok != GNUNET_YES)
- all_done = GNUNET_NO;
+ not_done++;
va = va->next;
}
if (GNUNET_NO == matched)
("Received `%s' message but have no record of a matching `%s' message. Ignoring.\n"),
"PONG", "PING");
}
- if (GNUNET_YES == all_done)
+ 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_delayed (sched,
- GNUNET_NO,
- GNUNET_SCHEDULER_PRIORITY_IDLE,
- GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
- GNUNET_TIME_UNIT_ZERO,
- &cleanup_validation, NULL);
+ 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
}
}
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'\n",
+ "Establishing `%s' connection to validate `%s' address `%s' of `%4s'\n",
va->transport_name,
"HELLO",
+ GNUNET_a2s ((const struct sockaddr*) &va[1],
+ va->addr_len),
GNUNET_i2s (&apeer));
#endif
tp = find_transport (va->transport_name);
va->ok = GNUNET_SYSERR;
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);
}
/**
- * 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.
+ * The peer specified by the given neighbour 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 neighbour is now officially
+ * gone.
*
* @param n the neighbour 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_neighbour (struct NeighbourList *n)
+disconnect_neighbour (struct NeighbourList *n,
+ int check)
{
struct ReadyList *rpos;
struct NeighbourList *npos;
struct NeighbourList *nprev;
struct MessageQueue *mq;
+
+ if (GNUNET_YES == check)
+ {
+ rpos = n->plugins;
+ while (NULL != rpos)
+ {
+ if (GNUNET_YES == rpos->connected)
+ return; /* still connected */
+ rpos = rpos->next;
+ }
+ }
#if DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
/* 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);
+ if (GNUNET_YES == rpos->connected)
+ rpos->plugin->api->cancel (rpos->plugin->api->cls,
+ rpos->plugin_handle,
+ rpos,
+ &n->id);
GNUNET_free (rpos);
}
GNUNET_assert (mq->neighbour == 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);
}
"Neighbour `%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_neighbour (n, GNUNET_NO);
}
n->quota_in = (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT + 59999) / (60 * 1000);
add_plugins (n);
n->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
- GNUNET_NO,
- GNUNET_SCHEDULER_PRIORITY_IDLE,
- GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
&neighbour_timeout_task, n);
transmit_to_peer (NULL, 0,
* reducing the rate at which they read from the socket
* and generally forward to our receive callback.
*
+ * @param cls the "struct TransportPlugin *" we gave to the plugin
* @param plugin_context value to pass to this plugin
* to respond to the given peer (use is optional,
* but may speed up processing)
}
if (message == 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 */
if ((service_context != NULL) &&
(service_context->plugin_handle == plugin_context))
{
service_context->connected = GNUNET_NO;
service_context->plugin_handle = NULL;
}
- /* TODO: call stats */
+ disconnect_neighbour (n, GNUNET_YES);
return NULL;
}
#if DEBUG_TRANSPORT
n->peer_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,
+ GNUNET_SCHEDULER_add_delayed (sched,
GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
&neighbour_timeout_task, n);
update_quota (n);
_
("Dropping incoming message due to repeated bandwidth quota violations.\n"));
/* TODO: call stats */
- GNUNET_assert (NULL != service_context->neighbour);
+ GNUNET_assert ( (service_context == NULL) ||
+ (NULL != service_context->neighbour) );
return service_context;
}
switch (ntohs (message->type))
}
GNUNET_free (im);
}
- GNUNET_assert (NULL != service_context->neighbour);
+ GNUNET_assert ( (service_context == NULL) ||
+ (NULL != service_context->neighbour) );
return service_context;
}
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_neighbour (&tcm->peer))
setup_new_neighbour (&tcm->peer);
}
+/**
+ * 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;
}
GNUNET_free (plugs);
}
+ GNUNET_SCHEDULER_add_delayed (sched,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ &unload_plugins, NULL);
if (no_transports)
refresh_hello ();
#if DEBUG_TRANSPORT
}
-/**
- * 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.
*
main (int argc, char *const *argv)
{
return (GNUNET_OK ==
- GNUNET_SERVICE_run (argc,
- argv,
- "transport",
- &run, NULL, &unload_plugins, NULL)) ? 0 : 1;
+ GNUNET_SERVICE_run (argc,
+ argv,
+ "transport",
+ &run, NULL)) ? 0 : 1;
}
/* end of gnunet-service-transport.c */