#include "transport.h"
+
/**
* Size of the neighbour hash map.
*/
S_DISCONNECT,
/**
- * We're finished with the disconnect; clean up state now!
+ * We're finished with the disconnect; and are cleaning up the state
+ * now! We put the struct into this state when we are really in the
+ * task that calls 'free' on it and are about to remove the record
+ * from the map. We should never find a 'struct NeighbourMapEntry'
+ * in this state in the map. Accessing a 'struct NeighbourMapEntry'
+ * in this state virtually always means using memory that has been
+ * freed (the exception being the cleanup code in 'free_neighbour').
*/
S_DISCONNECT_FINISHED
};
/**
* Function to call when we connected to a neighbour.
*/
-static GNUNET_TRANSPORT_NotifyConnect connect_notify_cb;
+static NotifyConnect connect_notify_cb;
/**
* Function to call when we disconnected from a neighbour.
{
case S_NOT_CONNECTED:
return "S_NOT_CONNECTED";
- break;
case S_INIT_ATS:
return "S_INIT_ATS";
- break;
case S_INIT_BLACKLIST:
return "S_INIT_BLACKLIST";
- break;
case S_CONNECT_SENT:
return "S_CONNECT_SENT";
- break;
case S_CONNECT_RECV_BLACKLIST_INBOUND:
return "S_CONNECT_RECV_BLACKLIST_INBOUND";
- break;
case S_CONNECT_RECV_ATS:
return "S_CONNECT_RECV_ATS";
- break;
case S_CONNECT_RECV_BLACKLIST:
return "S_CONNECT_RECV_BLACKLIST";
- break;
case S_CONNECT_RECV_ACK:
return "S_CONNECT_RECV_ACK";
- break;
case S_CONNECTED:
return "S_CONNECTED";
- break;
case S_RECONNECT_ATS:
return "S_RECONNECT_ATS";
- break;
case S_RECONNECT_BLACKLIST:
return "S_RECONNECT_BLACKLIST";
- break;
case S_RECONNECT_SENT:
return "S_RECONNECT_SENT";
- break;
case S_CONNECTED_SWITCHING_BLACKLIST:
return "S_CONNECTED_SWITCHING_BLACKLIST";
- break;
case S_CONNECTED_SWITCHING_CONNECT_SENT:
return "S_CONNECTED_SWITCHING_CONNECT_SENT";
- break;
case S_DISCONNECT:
return "S_DISCONNECT";
- break;
case S_DISCONNECT_FINISHED:
return "S_DISCONNECT_FINISHED";
- break;
default:
- return "UNDEFINED";
GNUNET_break (0);
- break;
+ return "UNDEFINED";
}
- GNUNET_break (0);
return "UNDEFINED";
}
{
GST_validation_set_address_use (na->address, na->session, GNUNET_NO, __LINE__);
GNUNET_ATS_address_in_use (GST_ats, na->address, na->session, GNUNET_NO);
- GNUNET_ATS_address_destroyed (GST_ats, na->address, na->session);
}
+
na->ats_active = GNUNET_NO;
if (NULL != na->address)
{
{
struct MessageQueue *mq;
struct GNUNET_TRANSPORT_PluginFunctions *papi;
+ struct GNUNET_HELLO_Address *backup_primary;
n->is_active = NULL; /* always free'd by its own continuation! */
{
GNUNET_CONTAINER_DLL_remove (n->messages_head, n->messages_tail, mq);
if (NULL != mq->cont)
- mq->cont (mq->cont_cls, GNUNET_SYSERR);
+ mq->cont (mq->cont_cls, GNUNET_SYSERR, mq->message_buf_size, 0);
GNUNET_free (mq);
}
/* It is too late to send other peer disconnect notifications, but at
disconnect_notify_cb (callback_cls, &n->id);
}
+ n->state = S_DISCONNECT_FINISHED;
+
+ if (NULL != n->primary_address.address)
+ backup_primary = GNUNET_HELLO_address_copy(n->primary_address.address);
+ else
+ backup_primary = NULL;
+
+ /* free addresses and mark as unused */
+ free_address (&n->primary_address);
+ free_address (&n->alternative_address);
+
/* FIXME-PLUGIN-API: This does not seem to guarantee that all
transport sessions eventually get killed due to inactivity; they
MUST have their own timeout logic (but at least TCP doesn't have
API gives us not even the means to selectively kill only one of
them! Killing all sessions like this seems to be very, very
wrong. */
+
+ /* cut transport-level connection */
if ((GNUNET_NO == keep_sessions) &&
- (NULL != n->primary_address.address) &&
- (NULL != (papi = GST_plugins_find (n->primary_address.address->transport_name))))
+ (NULL != backup_primary) &&
+ (NULL != (papi = GST_plugins_find (backup_primary->transport_name))))
papi->disconnect (papi->cls, &n->id);
- n->state = S_DISCONNECT_FINISHED;
+ GNUNET_free_non_null (backup_primary);
GNUNET_assert (GNUNET_YES ==
GNUNET_CONTAINER_multihashmap_remove (neighbours,
&n->id.hashPubKey, n));
- /* cut transport-level connection */
- free_address (&n->primary_address);
- free_address (&n->alternative_address);
-
// FIXME-ATS-API: we might want to be more specific about
// which states we do this from in the future (ATS should
// have given us a 'suggest_address' handle, and if we have
GNUNET_free (n);
}
-
/**
* Transmit a message using the current session of the given
* neighbour.
struct GNUNET_TRANSPORT_PluginFunctions *papi;
GNUNET_assert (n->primary_address.session != NULL);
- if ( ( (NULL == (papi = GST_plugins_find (n->primary_address.address->transport_name))) ||
+ if ( ((NULL == (papi = GST_plugins_find (n->primary_address.address->transport_name)) ||
(-1 == papi->send (papi->cls,
n->primary_address.session,
msgbuf, msgbuf_size,
priority,
timeout,
- cont, cont_cls))) &&
- (NULL != cont) )
- cont (cont_cls, &n->id, GNUNET_SYSERR);
+ cont, cont_cls)))) &&
+ (NULL != cont))
+ cont (cont_cls, &n->id, GNUNET_SYSERR, msgbuf_size, 0);
GNUNET_break (NULL != papi);
}
* @param cls NULL
* @param target identity of the neighbour that was disconnected
* @param result GNUNET_OK if the disconnect got out successfully
+ * @param payload bytes payload
+ * @param physical bytes physical
*/
static void
send_disconnect_cont (void *cls, const struct GNUNET_PeerIdentity *target,
- int result)
+ int result, size_t payload, size_t physical)
{
struct NeighbourMapEntry *n;
* @param cls the 'struct MessageQueue' of the message
* @param receiver intended receiver
* @param success whether it worked or not
+ * @param size_payload bytes payload sent
+ * @param physical bytes sent on wire
*/
static void
transmit_send_continuation (void *cls,
const struct GNUNET_PeerIdentity *receiver,
- int success)
+ int success, size_t size_payload, size_t physical)
{
struct MessageQueue *mq = cls;
struct NeighbourMapEntry *n;
GNUNET_SCHEDULER_cancel (n->task);
n->task = GNUNET_SCHEDULER_add_now (&master_task, n);
}
- GNUNET_assert (bytes_in_send_queue >= mq->message_buf_size);
+ if (bytes_in_send_queue < mq->message_buf_size)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "bytes_in_send_queue `%u' mq->message_buf_size %u\n",
+ bytes_in_send_queue, mq->message_buf_size );
+ GNUNET_break (0);
+ }
+
+
+ GNUNET_break (size_payload == mq->message_buf_size);
bytes_in_send_queue -= mq->message_buf_size;
GNUNET_STATISTICS_set (GST_stats,
gettext_noop
ntohs (((struct GNUNET_MessageHeader *) mq->message_buf)->type),
(success == GNUNET_OK) ? "success" : "FAILURE");
if (NULL != mq->cont)
- mq->cont (mq->cont_cls, success);
+ mq->cont (mq->cont_cls, success, size_payload, physical);
GNUNET_free (mq);
}
1, GNUNET_NO);
GNUNET_CONTAINER_DLL_remove (n->messages_head, n->messages_tail, mq);
n->is_active = mq;
- transmit_send_continuation (mq, &n->id, GNUNET_SYSERR); /* timeout */
+ transmit_send_continuation (mq, &n->id, GNUNET_SYSERR, mq->message_buf_size, 0); /* timeout */
}
if (NULL == mq)
return; /* no more messages */
/**
* Send keepalive message to the neighbour. Must only be called
- * if we are on 'connected' state. Will internally determine
- * if a keepalive is truly needed (so can always be called).
+ * if we are on 'connected' state or while trying to switch addresses.
+ * Will internally determine if a keepalive is truly needed (so can
+ * always be called).
*
* @param n neighbour that went idle and needs a keepalive
*/
{
struct GNUNET_MessageHeader m;
- GNUNET_assert (S_CONNECTED == n->state);
+ GNUNET_assert ((S_CONNECTED == n->state) ||
+ (S_CONNECTED_SWITCHING_BLACKLIST == n->state) ||
+ (S_CONNECTED_SWITCHING_CONNECT_SENT));
if (GNUNET_TIME_absolute_get_remaining (n->keep_alive_time).rel_value > 0)
return; /* no keepalive needed at this time */
m.size = htons (sizeof (struct GNUNET_MessageHeader));
{
GNUNET_break (0);
if (NULL != cont)
- cont (cont_cls, GNUNET_SYSERR);
+ cont (cont_cls, GNUNET_SYSERR, msg_size, 0);
return;
}
if (GNUNET_YES != test_connected (n))
{
GNUNET_break (0);
if (NULL != cont)
- cont (cont_cls, GNUNET_SYSERR);
+ cont (cont_cls, GNUNET_SYSERR, msg_size, 0);
return;
}
bytes_in_send_queue += msg_size;
{
struct GNUNET_TRANSPORT_PluginFunctions *papi;
struct SessionConnectMessage connect_msg;
-
+
if (NULL == (papi = GST_plugins_find (na->address->transport_name)))
{
GNUNET_break (0);
UINT_MAX,
GNUNET_TIME_UNIT_FOREVER_REL,
NULL, NULL);
+
}
{
struct GNUNET_TRANSPORT_PluginFunctions *papi;
struct SessionConnectMessage connect_msg;
-
+
if (NULL == (papi = GST_plugins_find (address->transport_name)))
{
GNUNET_break (0);
UINT_MAX,
GNUNET_TIME_UNIT_FOREVER_REL,
NULL, NULL);
+
}
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Received CONNECT message from peer `%s'\n",
GNUNET_i2s (peer));
+
if (ntohs (message->size) != sizeof (struct SessionConnectMessage))
{
GNUNET_break_op (0);
n = setup_neighbour (peer);
n->send_connect_ack = 1;
n->connect_ack_timestamp = ts;
+
switch (n->state)
{
case S_NOT_CONNECTED:
check_blacklist (peer, ts, address, session, ats, ats_count);
break;
case S_INIT_ATS:
+ /* CONNECT message takes priority over us asking ATS for address */
+ n->state = S_CONNECT_RECV_BLACKLIST_INBOUND;
+ /* fallthrough */
case S_INIT_BLACKLIST:
case S_CONNECT_SENT:
+ case S_CONNECT_RECV_BLACKLIST_INBOUND:
case S_CONNECT_RECV_ATS:
case S_CONNECT_RECV_BLACKLIST:
case S_CONNECT_RECV_ACK:
GNUNET_ATS_address_destroyed (GST_ats, address, NULL);
return;
}
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "ATS tells us to switch to address '%s' session %p for "
+ "peer `%s' in state %s (quota in/out %u %u )\n",
+ (address->address_length != 0) ? GST_plugins_a2s (address): "<inbound>",
+ session,
+ GNUNET_i2s (peer),
+ print_state (n->state),
+ ntohl (bandwidth_in.value__),
+ ntohl (bandwidth_out.value__));
+
if (NULL == session)
+ {
session = papi->get_session (papi->cls, address);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Obtained new session for peer `%s' and address '%s': %p\n",
+ GNUNET_i2s (&address->peer), GST_plugins_a2s (address), session);
+ }
if (NULL == session)
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
GNUNET_ATS_address_destroyed (GST_ats, address, NULL);
return;
}
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "ATS tells us to switch to address '%s' for peer `%s'\n",
- (address->address_length != 0) ? GST_plugins_a2s (address): "<inbound>",
- GNUNET_i2s (peer));
switch (n->state)
{
case S_NOT_CONNECTED:
n->task = GNUNET_SCHEDULER_NO_TASK;
delay = GNUNET_TIME_absolute_get_remaining (n->timeout);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "master task runs for neighbour `%s' in state %d with timeout in %llu ms\n",
+ "Master task runs for neighbour `%s' in state %s with timeout in %llu ms\n",
GNUNET_i2s (&n->id),
- n->state,
+ print_state(n->state),
(unsigned long long) delay.rel_value);
switch (n->state)
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Cleaning up connection to `%s' after sending DISCONNECT\n",
GNUNET_i2s (&n->id));
- n->state = S_DISCONNECT_FINISHED;
free_neighbour (n, GNUNET_NO);
return;
case S_DISCONNECT_FINISHED:
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Received CONNECT_ACK message from peer `%s'\n",
GNUNET_i2s (peer));
+
if (ntohs (message->size) != sizeof (struct SessionConnectMessage))
{
GNUNET_break_op (0);
gettext_noop ("# peers connected"),
++neighbours_connected,
GNUNET_NO);
- connect_notify_cb (callback_cls, &n->id, ats, ats_count);
+ connect_notify_cb (callback_cls, &n->id, ats, ats_count,
+ n->primary_address.bandwidth_in,
+ n->primary_address.bandwidth_out);
/* Tell ATS that the outbound session we created to send CONNECT was successfull */
- GNUNET_ATS_address_add(GST_ats,
- n->primary_address.address,
- n->primary_address.session,
- ats, ats_count);
+ GNUNET_ATS_address_add (GST_ats,
+ n->primary_address.address,
+ n->primary_address.session,
+ ats, ats_count);
set_address (&n->primary_address,
n->primary_address.address,
n->primary_address.session,
n->state = S_CONNECTED;
n->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
GNUNET_break (GNUNET_NO == n->alternative_address.ats_active);
+ GNUNET_ATS_address_add(GST_ats,
+ n->alternative_address.address,
+ n->alternative_address.session,
+ ats, ats_count);
set_address (&n->primary_address,
n->alternative_address.address,
n->alternative_address.session,
*
* @param peer identity of the peer where the session died
* @param session session that is gone
- * @param GNUNET_YES if this was a session used, GNUNET_NO if
+ * @return GNUNET_YES if this was a session used, GNUNET_NO if
* this session was not in use
*/
int
break;
case S_DISCONNECT_FINISHED:
/* neighbour was freed and plugins told to terminate session */
+ return GNUNET_NO;
break;
default:
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unhandled state `%s' \n",print_state (n->state));
gettext_noop ("# peers connected"),
++neighbours_connected,
GNUNET_NO);
- connect_notify_cb (callback_cls, &n->id, ats, ats_count);
+ connect_notify_cb (callback_cls, &n->id, ats, ats_count,
+ n->primary_address.bandwidth_in,
+ n->primary_address.bandwidth_out);
+ GNUNET_ATS_address_add(GST_ats,
+ n->primary_address.address,
+ n->primary_address.session,
+ ats, ats_count);
set_address (&n->primary_address,
n->primary_address.address,
n->primary_address.session,
struct NeighbourMapEntry *n = value;
if (GNUNET_YES == test_connected (n))
- ic->cb (ic->cb_cls, &n->id, NULL, 0, n->primary_address.address);
+ {
+ struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in;
+ struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out;
+
+ if (NULL != n->primary_address.address)
+ {
+ bandwidth_in = n->primary_address.bandwidth_in;
+ bandwidth_out = n->primary_address.bandwidth_out;
+ }
+ else
+ {
+ bandwidth_in = GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT;
+ bandwidth_out = GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT;
+ }
+
+ ic->cb (ic->cb_cls, &n->id, NULL, 0,
+ n->primary_address.address,
+ bandwidth_in, bandwidth_out);
+ }
return GNUNET_OK;
}
switch (n->state)
{
case S_CONNECTED:
+ case S_CONNECTED_SWITCHING_CONNECT_SENT:
+ case S_CONNECTED_SWITCHING_BLACKLIST:
case S_RECONNECT_SENT:
case S_RECONNECT_ATS:
+ case S_RECONNECT_BLACKLIST:
return n->latency;
case S_NOT_CONNECTED:
case S_INIT_BLACKLIST:
case S_INIT_ATS:
case S_CONNECT_RECV_BLACKLIST_INBOUND:
- case S_CONNECT_SENT:
+ case S_CONNECT_RECV_ATS:
case S_CONNECT_RECV_BLACKLIST:
+ case S_CONNECT_RECV_ACK:
+ case S_CONNECT_SENT:
case S_DISCONNECT:
case S_DISCONNECT_FINISHED:
return GNUNET_TIME_UNIT_FOREVER_REL;
*/
void
GST_neighbours_start (void *cls,
- GNUNET_TRANSPORT_NotifyConnect connect_cb,
+ NotifyConnect connect_cb,
GNUNET_TRANSPORT_NotifyDisconnect disconnect_cb,
GNUNET_TRANSPORT_PeerIterateCallback peer_address_cb)
{
connect_notify_cb = connect_cb;
disconnect_notify_cb = disconnect_cb;
address_change_cb = peer_address_cb;
- neighbours = GNUNET_CONTAINER_multihashmap_create (NEIGHBOUR_TABLE_SIZE);
+ neighbours = GNUNET_CONTAINER_multihashmap_create (NEIGHBOUR_TABLE_SIZE, GNUNET_NO);
}