X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Ftransport%2Fgnunet-service-transport_neighbours.c;h=01546ded4d059e1a58fa928012b364ae55419fe2;hb=9bbe1dc9c3dfa9de90759e540d715de6547e43cd;hp=c4886520b0d3a045be2b90d862c6745775c28451;hpb=9408c72ce1cbc03d7001a778e793359cb94d4798;p=oweals%2Fgnunet.git diff --git a/src/transport/gnunet-service-transport_neighbours.c b/src/transport/gnunet-service-transport_neighbours.c index c4886520b..01546ded4 100644 --- a/src/transport/gnunet-service-transport_neighbours.c +++ b/src/transport/gnunet-service-transport_neighbours.c @@ -14,8 +14,8 @@ You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ /** @@ -157,6 +157,26 @@ struct SessionKeepAliveMessage uint32_t nonce GNUNET_PACKED; }; + +/** + * Message a peer sends to another when connected to indicate that + * the other peer should limit transmissions to the indicated + * quota. + */ +struct SessionQuotaMessage +{ + /** + * Header of type #GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_QUOTA. + */ + struct GNUNET_MessageHeader header; + + /** + * Quota to use (for sending), in bytes per second. + */ + uint32_t quota GNUNET_PACKED; +}; + + /** * Message we send to the other peer to notify him that we intentionally * are disconnecting (to reduce timeouts). This is just a friendly @@ -336,7 +356,7 @@ struct NeighbourMapEntry /** * Main task that drives this peer (timeouts, keepalives, etc.). - * Always runs the 'master_task'. + * Always runs the #master_task(). */ struct GNUNET_SCHEDULER_Task *task; @@ -371,7 +391,7 @@ struct NeighbourMapEntry /** * Time where we should cut the connection (timeout) if we don't * make progress in the state machine (or get a KEEPALIVE_RESPONSE - * if we are in #S_CONNECTED). + * if we are in #GNUNET_TRANSPORT_PS_CONNECTED). */ struct GNUNET_TIME_Absolute timeout; @@ -387,6 +407,13 @@ struct NeighbourMapEntry */ unsigned int quota_violation_count; + /** + * Latest quota the other peer send us in bytes per second. + * We should not send more, least the other peer throttle + * receiving our traffic. + */ + struct GNUNET_BANDWIDTH_Value32NBO neighbour_receive_quota; + /** * The current state of the peer. */ @@ -641,13 +668,15 @@ test_connected (struct NeighbourMapEntry *n) /** * Send information about a new outbound quota to our clients. + * Note that the outbound quota is enforced client-side (i.e. + * in libgnunettransport). * * @param target affected peer * @param quota new quota */ static void -send_outbound_quota (const struct GNUNET_PeerIdentity *target, - struct GNUNET_BANDWIDTH_Value32NBO quota) +send_outbound_quota_to_clients (const struct GNUNET_PeerIdentity *target, + struct GNUNET_BANDWIDTH_Value32NBO quota) { struct QuotaSetMessage q_msg; @@ -826,6 +855,9 @@ set_alternative_address (struct NeighbourMapEntry *n, n->alternative_address.session = session; n->alternative_address.ats_active = GNUNET_NO; n->alternative_address.keep_alive_nonce = 0; + GNUNET_assert (GNUNET_YES == + GST_ats_is_known (n->alternative_address.address, + n->alternative_address.session)); } @@ -860,8 +892,8 @@ set_primary_address (struct NeighbourMapEntry *n, if (n->primary_address.bandwidth_out.value__ != bandwidth_out.value__) { n->primary_address.bandwidth_out = bandwidth_out; - send_outbound_quota (&address->peer, - bandwidth_out); + send_outbound_quota_to_clients (&address->peer, + bandwidth_out); } return; } @@ -890,13 +922,16 @@ set_primary_address (struct NeighbourMapEntry *n, n->primary_address.bandwidth_out = bandwidth_out; n->primary_address.session = session; n->primary_address.keep_alive_nonce = 0; + GNUNET_assert (GNUNET_YES == + GST_ats_is_known (n->primary_address.address, + n->primary_address.session)); /* subsystems about address use */ GST_validation_set_address_use (n->primary_address.address, GNUNET_YES); GST_neighbours_set_incoming_quota (&address->peer, bandwidth_in); - send_outbound_quota (&address->peer, - bandwidth_out); + send_outbound_quota_to_clients (&address->peer, + bandwidth_out); GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Neighbour `%s' switched to address `%s'\n", GNUNET_i2s (&n->id), @@ -1224,13 +1259,20 @@ disconnect_neighbour (struct NeighbourMapEntry *n) static void transmit_send_continuation (void *cls, const struct GNUNET_PeerIdentity *receiver, - int success, size_t size_payload, size_t physical) + int success, + size_t size_payload, + size_t physical) { struct MessageQueue *mq = cls; struct NeighbourMapEntry *n; if (NULL == (n = lookup_neighbour (receiver))) { + if (NULL != mq->cont) + mq->cont (mq->cont_cls, + GNUNET_SYSERR /* not connected */, + size_payload, + 0); GNUNET_free (mq); return; /* disconnect or other error while transmitting, can happen */ } @@ -1241,7 +1283,8 @@ transmit_send_continuation (void *cls, n->is_active = NULL; if (NULL != n->task) GNUNET_SCHEDULER_cancel (n->task); - n->task = GNUNET_SCHEDULER_add_now (&master_task, n); + n->task = GNUNET_SCHEDULER_add_now (&master_task, + n); } if (bytes_in_send_queue < mq->message_buf_size) { @@ -1255,18 +1298,17 @@ transmit_send_continuation (void *cls, 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 - ("# bytes in message queue for other peers"), - bytes_in_send_queue, GNUNET_NO); + gettext_noop ("# bytes in message queue for other peers"), + bytes_in_send_queue, + GNUNET_NO); if (GNUNET_OK == success) GNUNET_STATISTICS_update (GST_stats, - gettext_noop - ("# messages transmitted to other peers"), - 1, GNUNET_NO); + gettext_noop ("# messages transmitted to other peers"), + 1, + GNUNET_NO); else GNUNET_STATISTICS_update (GST_stats, gettext_noop @@ -1279,7 +1321,10 @@ transmit_send_continuation (void *cls, mq->message_buf_size, (success == GNUNET_OK) ? "success" : "FAILURE"); if (NULL != mq->cont) - mq->cont (mq->cont_cls, success, size_payload, physical); + mq->cont (mq->cont_cls, + success, + size_payload, + physical); GNUNET_free (mq); } @@ -1327,9 +1372,9 @@ try_transmission_to_peer (struct NeighbourMapEntry *n) if (timeout.rel_value_us > 0) break; GNUNET_STATISTICS_update (GST_stats, - gettext_noop - ("# messages timed out while in transport queue"), - 1, GNUNET_NO); + gettext_noop ("# messages timed out while in transport queue"), + 1, + GNUNET_NO); GNUNET_CONTAINER_DLL_remove (n->messages_head, n->messages_tail, mq); @@ -1384,10 +1429,11 @@ send_keepalive (struct NeighbourMapEntry *n) nonce = 0; /* 0 indicates 'not set' */ while (0 == nonce) - nonce = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX); + nonce = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, + UINT32_MAX); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Sending keep alive to peer `%s' with nonce %u\n", + "Sending KEEPALIVE to peer `%s' with nonce %u\n", GNUNET_i2s (&n->id), nonce); m.header.size = htons (sizeof (struct SessionKeepAliveMessage)); @@ -1455,6 +1501,10 @@ GST_neighbours_keepalive (const struct GNUNET_PeerIdentity *neighbour, "Received KEEPALIVE request from peer `%s' with nonce %u\n", GNUNET_i2s (&n->id), ntohl (msg_in->nonce)); + GNUNET_STATISTICS_update (GST_stats, + gettext_noop ("# KEEPALIVES received in good order"), + 1, + GNUNET_NO); /* send reply to allow neighbour to measure latency */ msg.header.size = htons (sizeof (struct SessionKeepAliveMessage)); @@ -1497,7 +1547,7 @@ GST_neighbours_keepalive_response (const struct GNUNET_PeerIdentity *neighbour, if (NULL == (n = lookup_neighbour (neighbour))) { GNUNET_STATISTICS_update (GST_stats, - gettext_noop ("# KEEPALIVE_RESPONSE messages discarded (not connected)"), + gettext_noop ("# KEEPALIVE_RESPONSEs discarded (not connected)"), 1, GNUNET_NO); return; @@ -1506,7 +1556,7 @@ GST_neighbours_keepalive_response (const struct GNUNET_PeerIdentity *neighbour, (GNUNET_YES != n->expect_latency_response) ) { GNUNET_STATISTICS_update (GST_stats, - gettext_noop ("# KEEPALIVE_RESPONSE messages discarded (not expected)"), + gettext_noop ("# KEEPALIVE_RESPONSEs discarded (not expected)"), 1, GNUNET_NO); return; @@ -1514,21 +1564,27 @@ GST_neighbours_keepalive_response (const struct GNUNET_PeerIdentity *neighbour, if (NULL == n->primary_address.address) { GNUNET_STATISTICS_update (GST_stats, - gettext_noop ("# KEEPALIVE_RESPONSE messages discarded (address changed)"), + gettext_noop ("# KEEPALIVE_RESPONSEs discarded (address changed)"), 1, GNUNET_NO); return; } if (n->primary_address.keep_alive_nonce != ntohl (msg->nonce)) { - GNUNET_STATISTICS_update (GST_stats, - gettext_noop ("# KEEPALIVE_RESPONSE messages discarded (wrong nonce)"), - 1, - GNUNET_NO); + if (0 == n->primary_address.keep_alive_nonce) + GNUNET_STATISTICS_update (GST_stats, + gettext_noop ("# KEEPALIVE_RESPONSEs discarded (no nonce)"), + 1, + GNUNET_NO); + else + GNUNET_STATISTICS_update (GST_stats, + gettext_noop ("# KEEPALIVE_RESPONSEs discarded (bad nonce)"), + 1, + GNUNET_NO); return; } GNUNET_STATISTICS_update (GST_stats, - gettext_noop ("# KEEPALIVE_RESPONSE messages received in good order"), + gettext_noop ("# KEEPALIVE_RESPONSEs received (OK)"), 1, GNUNET_NO); @@ -2084,6 +2140,7 @@ setup_neighbour (const struct GNUNET_PeerIdentity *peer) n->id = *peer; n->ack_state = ACK_UNDEFINED; n->last_util_transmission = GNUNET_TIME_absolute_get(); + n->neighbour_receive_quota = GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT; GNUNET_BANDWIDTH_tracker_init (&n->in_tracker, &inbound_bw_tracker_update, n, @@ -2124,16 +2181,6 @@ struct BlacklistCheckSwitchContext */ struct GST_BlacklistCheck *blc; - /** - * Address we are asking the blacklist subsystem about. - */ - struct GNUNET_HELLO_Address *address; - - /** - * Session we should use in conjunction with @e address, can be NULL. - */ - struct Session *session; - /** * Inbound bandwidth that was assigned to @e address. */ @@ -2152,11 +2199,17 @@ struct BlacklistCheckSwitchContext * * @param cls blc_ctx bl context * @param peer the peer - * @param result the result + * @param address address associated with the request + * @param session session associated with the request + * @param result #GNUNET_OK if the connection is allowed, + * #GNUNET_NO if not, + * #GNUNET_SYSERR if operation was aborted */ static void try_connect_bl_check_cont (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_HELLO_Address *address, + struct Session *session, int result) { struct BlacklistCheckSwitchContext *blc_ctx = cls; @@ -2264,7 +2317,9 @@ GST_neighbours_try_connect (const struct GNUNET_PeerIdentity *target) (blc = GST_blacklist_test_allowed (target, NULL, &try_connect_bl_check_cont, - blc_ctx))) + blc_ctx, + NULL, + NULL))) { blc_ctx->blc = blc; } @@ -2275,7 +2330,7 @@ GST_neighbours_try_connect (const struct GNUNET_PeerIdentity *target) * We received a 'SYN' message from the other peer. * Consider switching to it. * - * @param message possibly a 'struct TransportSynMessage' (check format) + * @param message possibly a `struct TransportSynMessage` (check format) * @param peer identity of the peer to switch the address for * @return #GNUNET_OK if the message was fine, #GNUNET_SYSERR on serious error */ @@ -2426,6 +2481,7 @@ try_run_fast_ats_update (const struct GNUNET_HELLO_Address *address, struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out) { struct NeighbourMapEntry *n; + struct GNUNET_BANDWIDTH_Value32NBO bandwidth_min; n = lookup_neighbour (&address->peer); if ( (NULL == n) || @@ -2440,13 +2496,24 @@ try_run_fast_ats_update (const struct GNUNET_HELLO_Address *address, /* switch to a different session, but keeping same address; could happen if there is a 2nd inbound connection */ n->primary_address.session = session; + GNUNET_assert (GNUNET_YES == + GST_ats_is_known (n->primary_address.address, + n->primary_address.session)); + } + if (n->primary_address.bandwidth_in.value__ != bandwidth_in.value__) + { + n->primary_address.bandwidth_in = bandwidth_in; + GST_neighbours_set_incoming_quota (&address->peer, + bandwidth_in); + } + if (n->primary_address.bandwidth_out.value__ != bandwidth_out.value__) + { + n->primary_address.bandwidth_out = bandwidth_out; + bandwidth_min = GNUNET_BANDWIDTH_value_min (bandwidth_out, + n->neighbour_receive_quota); + send_outbound_quota_to_clients (&address->peer, + bandwidth_min); } - n->primary_address.bandwidth_in = bandwidth_in; - n->primary_address.bandwidth_out = bandwidth_out; - GST_neighbours_set_incoming_quota (&address->peer, - bandwidth_in); - send_outbound_quota (&address->peer, - bandwidth_out); return GNUNET_OK; } @@ -2458,54 +2525,66 @@ try_run_fast_ats_update (const struct GNUNET_HELLO_Address *address, * @param cls the `struct BlacklistCheckSwitchContext` with * the information about the future address * @param peer the peer we may switch addresses on - * @param result #GNUNET_NO if we are not allowed to use the new - * address + * @param address address associated with the request + * @param session session associated with the request + * @param result #GNUNET_OK if the connection is allowed, + * #GNUNET_NO if not, + * #GNUNET_SYSERR if operation was aborted */ static void switch_address_bl_check_cont (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_HELLO_Address *address, + struct Session *session, int result) { struct BlacklistCheckSwitchContext *blc_ctx = cls; struct GNUNET_TRANSPORT_PluginFunctions *papi; struct NeighbourMapEntry *n; - if (result == GNUNET_NO) + if (GNUNET_SYSERR == result) + goto cleanup; + + papi = GST_plugins_find (address->transport_name); + GNUNET_assert (NULL != papi); + + if (GNUNET_NO == result) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Blacklist denied to switch to suggested address `%s' session %p for peer `%s'\n", - GST_plugins_a2s (blc_ctx->address), - blc_ctx->session, - GNUNET_i2s (&blc_ctx->address->peer)); + GST_plugins_a2s (address), + session, + GNUNET_i2s (peer)); GNUNET_STATISTICS_update (GST_stats, "# ATS suggestions ignored (blacklist denied)", 1, GNUNET_NO); - /* FIXME: tell plugin to force killing session here and now - (note: _proper_ plugin API for this does not yet exist) */ - GST_ats_block_address (blc_ctx->address, - blc_ctx->session); + papi->disconnect_session (papi->cls, + session); + if (GNUNET_YES != + GNUNET_HELLO_address_check_option (address, + GNUNET_HELLO_ADDRESS_INFO_INBOUND)) + GST_ats_block_address (address, + NULL); goto cleanup; } - papi = GST_plugins_find (blc_ctx->address->transport_name); - GNUNET_assert (NULL != papi); - if (NULL == blc_ctx->session) + if (NULL == session) { /* need to create a session, ATS only gave us an address */ - blc_ctx->session = papi->get_session (papi->cls, - blc_ctx->address); + 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 (&blc_ctx->address->peer), - GST_plugins_a2s (blc_ctx->address), - blc_ctx->session); - if (NULL != blc_ctx->session) - GST_ats_new_session (blc_ctx->address, - blc_ctx->session); + GNUNET_i2s (&address->peer), + GST_plugins_a2s (address), + session); + if (NULL != session) + GST_ats_new_session (address, + session); } - if (NULL == blc_ctx->session) + if (NULL == session) { /* session creation failed, bad!, fail! */ GNUNET_STATISTICS_update (GST_stats, @@ -2515,10 +2594,10 @@ switch_address_bl_check_cont (void *cls, /* No session could be obtained, remove blacklist check and clean up */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to obtain new session for peer `%s' and address '%s'\n", - GNUNET_i2s (&blc_ctx->address->peer), - GST_plugins_a2s (blc_ctx->address)); - GST_ats_block_address (blc_ctx->address, - blc_ctx->session); + GNUNET_i2s (&address->peer), + GST_plugins_a2s (address)); + GST_ats_block_address (address, + session); goto cleanup; } @@ -2526,8 +2605,8 @@ switch_address_bl_check_cont (void *cls, it is theoretically possible that the situation changed in the meantime, hence we check again here */ if (GNUNET_OK == - try_run_fast_ats_update (blc_ctx->address, - blc_ctx->session, + try_run_fast_ats_update (address, + session, blc_ctx->bandwidth_in, blc_ctx->bandwidth_out)) goto cleanup; /* was just a minor update, we're done */ @@ -2541,23 +2620,23 @@ switch_address_bl_check_cont (void *cls, GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Peer `%s' switches to address `%s'\n", - GNUNET_i2s (&blc_ctx->address->peer), - GST_plugins_a2s (blc_ctx->address)); + GNUNET_i2s (&address->peer), + GST_plugins_a2s (address)); switch (n->state) { case GNUNET_TRANSPORT_PS_NOT_CONNECTED: GNUNET_break (0); - GST_ats_block_address (blc_ctx->address, - blc_ctx->session); + GST_ats_block_address (address, + session); free_neighbour (n); return; case GNUNET_TRANSPORT_PS_INIT_ATS: /* We requested an address and ATS suggests one: * set primary address and send SYN message*/ set_primary_address (n, - blc_ctx->address, - blc_ctx->session, + address, + session, blc_ctx->bandwidth_in, blc_ctx->bandwidth_out); if (ACK_SEND_SYN_ACK == n->ack_state) @@ -2577,8 +2656,8 @@ switch_address_bl_check_cont (void *cls, * Switch and send new SYN */ /* ATS suggests a different address, switch again */ set_primary_address (n, - blc_ctx->address, - blc_ctx->session, + address, + session, blc_ctx->bandwidth_in, blc_ctx->bandwidth_out); if (ACK_SEND_SYN_ACK == n->ack_state) @@ -2597,8 +2676,8 @@ switch_address_bl_check_cont (void *cls, /* We requested an address and ATS suggests one: * set primary address and send SYN_ACK message*/ set_primary_address (n, - blc_ctx->address, - blc_ctx->session, + address, + session, blc_ctx->bandwidth_in, blc_ctx->bandwidth_out); /* Send an ACK message as a response to the SYN msg */ @@ -2621,8 +2700,8 @@ switch_address_bl_check_cont (void *cls, n->connect_ack_timestamp); } set_primary_address (n, - blc_ctx->address, - blc_ctx->session, + address, + session, blc_ctx->bandwidth_in, blc_ctx->bandwidth_out); set_state_and_timeout (n, @@ -2632,12 +2711,12 @@ switch_address_bl_check_cont (void *cls, case GNUNET_TRANSPORT_PS_CONNECTED: GNUNET_assert (NULL != n->primary_address.address); GNUNET_assert (NULL != n->primary_address.session); - GNUNET_break (n->primary_address.session != blc_ctx->session); + GNUNET_break (n->primary_address.session != session); /* ATS asks us to switch a life connection; see if we can get a SYN_ACK on it before we actually do this! */ set_alternative_address (n, - blc_ctx->address, - blc_ctx->session, + address, + session, blc_ctx->bandwidth_in, blc_ctx->bandwidth_out); set_state_and_timeout (n, @@ -2651,8 +2730,8 @@ switch_address_bl_check_cont (void *cls, break; case GNUNET_TRANSPORT_PS_RECONNECT_ATS: set_primary_address (n, - blc_ctx->address, - blc_ctx->session, + address, + session, blc_ctx->bandwidth_in, blc_ctx->bandwidth_out); if (ACK_SEND_SYN_ACK == n->ack_state) @@ -2671,8 +2750,8 @@ switch_address_bl_check_cont (void *cls, /* ATS asks us to switch while we were trying to reconnect; switch to new address and send SYN again */ set_primary_address (n, - blc_ctx->address, - blc_ctx->session, + address, + session, blc_ctx->bandwidth_in, blc_ctx->bandwidth_out); set_state_and_timeout (n, @@ -2682,8 +2761,8 @@ switch_address_bl_check_cont (void *cls, break; case GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT: if ( (0 == GNUNET_HELLO_address_cmp (n->primary_address.address, - blc_ctx->address)) && - (n->primary_address.session == blc_ctx->session) ) + address)) && + (n->primary_address.session == session) ) { /* ATS switches back to still-active session */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, @@ -2696,8 +2775,8 @@ switch_address_bl_check_cont (void *cls, } /* ATS asks us to switch a life connection, send */ set_alternative_address (n, - blc_ctx->address, - blc_ctx->session, + address, + session, blc_ctx->bandwidth_in, blc_ctx->bandwidth_out); set_state_and_timeout (n, @@ -2726,7 +2805,6 @@ switch_address_bl_check_cont (void *cls, GNUNET_CONTAINER_DLL_remove (pending_bc_head, pending_bc_tail, blc_ctx); - GNUNET_HELLO_address_free (blc_ctx->address); GNUNET_free (blc_ctx); } @@ -2794,8 +2872,6 @@ GST_neighbours_switch_to_address (const struct GNUNET_HELLO_Address *address, /* Perform blacklist check */ blc_ctx = GNUNET_new (struct BlacklistCheckSwitchContext); - blc_ctx->address = GNUNET_HELLO_address_copy (address); - blc_ctx->session = session; blc_ctx->bandwidth_in = bandwidth_in; blc_ctx->bandwidth_out = bandwidth_out; GNUNET_CONTAINER_DLL_insert (pending_bc_head, @@ -2804,7 +2880,9 @@ GST_neighbours_switch_to_address (const struct GNUNET_HELLO_Address *address, if (NULL != (blc = GST_blacklist_test_allowed (&address->peer, address->transport_name, &switch_address_bl_check_cont, - blc_ctx))) + blc_ctx, + address, + session))) { blc_ctx->blc = blc; } @@ -3372,6 +3450,9 @@ GST_neighbours_session_terminated (const struct GNUNET_PeerIdentity *peer, /* Destroy the inbound address since it cannot be used */ free_address (&n->primary_address); n->primary_address = n->alternative_address; + GNUNET_assert (GNUNET_YES == + GST_ats_is_known (n->primary_address.address, + n->primary_address.session)); memset (&n->alternative_address, 0, sizeof (struct NeighbourAddress)); @@ -3447,8 +3528,9 @@ GST_neighbours_handle_session_ack (const struct GNUNET_MessageHeader *message, now wait for the ACK to finally be connected - If we sent a SYN_ACK to this peer before */ - if ( (GNUNET_TRANSPORT_PS_SYN_RECV_ACK != n->state) && - (ACK_SEND_ACK != n->ack_state)) + if ( ( (GNUNET_TRANSPORT_PS_SYN_RECV_ACK != n->state) && + (ACK_SEND_ACK != n->ack_state) ) || + (NULL == n->primary_address.address) ) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Received unexpected ACK message from peer `%s' in state %s/%s\n", @@ -3457,7 +3539,8 @@ GST_neighbours_handle_session_ack (const struct GNUNET_MessageHeader *message, print_ack_state (n->ack_state)); GNUNET_STATISTICS_update (GST_stats, - gettext_noop ("# unexpected ACK messages"), 1, + gettext_noop ("# unexpected ACK messages"), + 1, GNUNET_NO); return GNUNET_OK; } @@ -3472,7 +3555,19 @@ GST_neighbours_handle_session_ack (const struct GNUNET_MessageHeader *message, GNUNET_TRANSPORT_PS_CONNECTED, GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT)); - /* Reset backoff for primary address */ + if (NULL == n->primary_address.address) { + /* See issue #3693. + * We are in state = PSY_SYN_RECV_ACK or ack_state = ACK_SEND_ACK, which + * really means we did try (and succeed) to send a SYN and are waiting for + * an ACK. + * That suggests that the primary_address used to be non-NULL, but maybe it + * got reset to NULL without the state being changed appropriately? + */ + GNUNET_break (0); + return GNUNET_OK; + } + + /* Reset backoff for primary address */ GST_ats_block_reset (n->primary_address.address, n->primary_address.session); return GNUNET_OK; @@ -3493,7 +3588,9 @@ GST_neighbours_test_connected (const struct GNUNET_PeerIdentity *target) /** - * Change the incoming quota for the given peer. + * Change the incoming quota for the given peer. Updates + * our own receive rate and informs the neighbour about + * the new quota. * * @param neighbour identity of peer to change qutoa for * @param quota new quota @@ -3517,7 +3614,21 @@ GST_neighbours_set_incoming_quota (const struct GNUNET_PeerIdentity *neighbour, ntohl (quota.value__), GNUNET_i2s (&n->id)); GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker, quota); if (0 != ntohl (quota.value__)) + { + struct SessionQuotaMessage sqm; + + sqm.header.size = htons (sizeof (struct SessionQuotaMessage)); + sqm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_QUOTA); + sqm.quota = quota.value__; + (void) send_with_session (n, + &sqm, + sizeof (sqm), + UINT32_MAX - 1, + GNUNET_TIME_UNIT_FOREVER_REL, + GNUNET_NO, + NULL, NULL); return; + } GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Disconnecting peer `%4s' due to SET_QUOTA\n", GNUNET_i2s (&n->id)); @@ -3549,6 +3660,54 @@ delayed_disconnect (void *cls, } +/** + * We received a quoat message from the given peer, + * validate and process. + * + * @param peer sender of the message + * @param msg the quota message + */ +void +GST_neighbours_handle_quota_message (const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *msg) +{ + struct NeighbourMapEntry *n; + const struct SessionQuotaMessage *sqm; + struct GNUNET_BANDWIDTH_Value32NBO bandwidth_min; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received QUOTA message from peer `%s'\n", + GNUNET_i2s (peer)); + if (ntohs (msg->size) != sizeof (struct SessionQuotaMessage)) + { + GNUNET_break_op (0); + GNUNET_STATISTICS_update (GST_stats, + gettext_noop ("# quota messages ignored (malformed)"), + 1, + GNUNET_NO); + return; + } + GNUNET_STATISTICS_update (GST_stats, + gettext_noop + ("# QUOTA messages received"), + 1, GNUNET_NO); + sqm = (const struct SessionQuotaMessage *) msg; + if (NULL == (n = lookup_neighbour (peer))) + { + /* gone already */ + return; + } + n->neighbour_receive_quota + = GNUNET_BANDWIDTH_value_max (GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT, + GNUNET_BANDWIDTH_value_init (ntohl (sqm->quota))); + + bandwidth_min = GNUNET_BANDWIDTH_value_min (n->primary_address.bandwidth_out, + n->neighbour_receive_quota); + send_outbound_quota_to_clients (peer, + bandwidth_min); +} + + /** * We received a disconnect message from the given peer, * validate and process. @@ -3563,7 +3722,7 @@ GST_neighbours_handle_disconnect_message (const struct GNUNET_PeerIdentity *peer struct NeighbourMapEntry *n; const struct SessionDisconnectMessage *sdm; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received DISCONNECT message from peer `%s'\n", GNUNET_i2s (peer)); if (ntohs (msg->size) != sizeof (struct SessionDisconnectMessage)) @@ -3571,7 +3730,8 @@ GST_neighbours_handle_disconnect_message (const struct GNUNET_PeerIdentity *peer GNUNET_break_op (0); GNUNET_STATISTICS_update (GST_stats, gettext_noop - ("# disconnect messages ignored (malformed)"), 1, + ("# disconnect messages ignored (malformed)"), + 1, GNUNET_NO); return; } @@ -3623,7 +3783,11 @@ GST_neighbours_handle_disconnect_message (const struct GNUNET_PeerIdentity *peer GNUNET_break_op (0); return; } - n->delayed_disconnect_task = GNUNET_SCHEDULER_add_now (&delayed_disconnect, n); + if (NULL == n->delayed_disconnect_task) + { + n->delayed_disconnect_task = GNUNET_SCHEDULER_add_now (&delayed_disconnect, + n); + } } @@ -3818,8 +3982,6 @@ GST_neighbours_stop () GST_blacklist_test_cancel (cur->blc); cur->blc = NULL; } - if (NULL != cur->address) - GNUNET_HELLO_address_free (cur->address); GNUNET_free (cur); } }