From 25fea659b134e2716aa95edc8f6267603e08ce61 Mon Sep 17 00:00:00 2001 From: Matthias Wachs Date: Thu, 27 Mar 2014 16:51:32 +0000 Subject: [PATCH] added functionality to use the CLI to disconnect peers fixed DISCONNECT functionality --- .../gnunet-service-transport_clients.c | 64 ++++++++++---- .../gnunet-service-transport_neighbours.c | 70 ++++++++------- src/transport/gnunet-transport.c | 87 ++++++++++++++++++- src/transport/transport.h | 4 +- src/transport/transport_api.c | 62 ++++++++++++- 5 files changed, 233 insertions(+), 54 deletions(-) diff --git a/src/transport/gnunet-service-transport_clients.c b/src/transport/gnunet-service-transport_clients.c index 10da37088..d9a750e29 100644 --- a/src/transport/gnunet-service-transport_clients.c +++ b/src/transport/gnunet-service-transport_clients.c @@ -794,27 +794,59 @@ clients_handle_request_connect (void *cls, struct GNUNET_SERVER_Client *client, const struct TransportRequestConnectMessage *trcm = (const struct TransportRequestConnectMessage *) message; - GNUNET_STATISTICS_update (GST_stats, - gettext_noop - ("# REQUEST CONNECT messages received"), 1, - GNUNET_NO); + if (GNUNET_YES == ntohl (trcm->connect)) + { + GNUNET_STATISTICS_update (GST_stats, + gettext_noop + ("# REQUEST CONNECT messages received"), 1, + GNUNET_NO); + + if (0 == memcmp (&trcm->peer, &GST_my_identity, + sizeof (struct GNUNET_PeerIdentity))) + { + GNUNET_break_op (0); + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Received a request connect message myself `%s'\n", + GNUNET_i2s (&trcm->peer)); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Received a request connect message for peer `%s'\n"), + GNUNET_i2s (&trcm->peer)); - if (0 == memcmp (&trcm->peer, &GST_my_identity, - sizeof (struct GNUNET_PeerIdentity))) + (void) GST_blacklist_test_allowed (&trcm->peer, NULL, &try_connect_if_allowed, + NULL); + } + } + else if (GNUNET_NO == ntohl (trcm->connect)) { - GNUNET_break_op (0); - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Received a request connect message myself `%s'\n", - GNUNET_i2s (&trcm->peer)); + GNUNET_STATISTICS_update (GST_stats, + gettext_noop + ("# REQUEST DISCONNECT messages received"), 1, + GNUNET_NO); + + if (0 == memcmp (&trcm->peer, &GST_my_identity, + sizeof (struct GNUNET_PeerIdentity))) + { + GNUNET_break_op (0); + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Received a request disconnect message myself `%s'\n", + GNUNET_i2s (&trcm->peer)); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Received a request disconnect message for peer `%s'\n"), + GNUNET_i2s (&trcm->peer)); + (void) GST_neighbours_force_disconnect (&trcm->peer); + } } else { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - _("Received a request connect message for peer `%s'\n"), - GNUNET_i2s (&trcm->peer)); - - (void) GST_blacklist_test_allowed (&trcm->peer, NULL, &try_connect_if_allowed, - NULL); + GNUNET_break_op (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; } GNUNET_SERVER_receive_done (client, GNUNET_OK); } diff --git a/src/transport/gnunet-service-transport_neighbours.c b/src/transport/gnunet-service-transport_neighbours.c index 025cf5f76..7d2ceb524 100644 --- a/src/transport/gnunet-service-transport_neighbours.c +++ b/src/transport/gnunet-service-transport_neighbours.c @@ -46,7 +46,7 @@ * Time we give plugin to transmit DISCONNECT message before the * neighbour entry self-destructs. */ -#define DISCONNECT_SENT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100) +#define DISCONNECT_SENT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 500) /** * How often must a peer violate bandwidth quotas before we start @@ -1054,7 +1054,7 @@ send_disconnect (struct NeighbourMapEntry *n) { struct SessionDisconnectMessage disconnect_msg; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Sending DISCONNECT message to peer `%4s'\n", GNUNET_i2s (&n->id)); disconnect_msg.header.size = htons (sizeof (struct SessionDisconnectMessage)); @@ -1075,10 +1075,9 @@ send_disconnect (struct NeighbourMapEntry *n) &disconnect_msg.purpose, &disconnect_msg.signature)); - (void) send_with_session (n, - (const char *) &disconnect_msg, sizeof (disconnect_msg), - UINT32_MAX, GNUNET_TIME_UNIT_FOREVER_REL, - GNUNET_NO, &send_disconnect_cont, NULL); + (void) send_with_session (n, (const char *) &disconnect_msg, + sizeof (disconnect_msg), UINT32_MAX, GNUNET_TIME_UNIT_FOREVER_REL, + GNUNET_NO, &send_disconnect_cont, NULL ); GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# DISCONNECT messages sent"), 1, @@ -1113,7 +1112,6 @@ disconnect_neighbour (struct NeighbourMapEntry *n) break; case GNUNET_TRANSPORT_PS_CONNECT_RECV_ATS: /* we never ACK'ed the other peer's request, no need to send DISCONNECT */ - set_state (n, GNUNET_TRANSPORT_PS_DISCONNECT_FINISHED); free_neighbour (n, GNUNET_NO); return; case GNUNET_TRANSPORT_PS_CONNECT_RECV_ACK: @@ -1121,6 +1119,7 @@ disconnect_neighbour (struct NeighbourMapEntry *n) send_disconnect (n); set_state (n, GNUNET_TRANSPORT_PS_DISCONNECT); break; + case GNUNET_TRANSPORT_PS_CONNECTED_SWITCHING_CONNECT_SENT: case GNUNET_TRANSPORT_PS_CONNECTED: case GNUNET_TRANSPORT_PS_RECONNECT_SENT: /* we are currently connected, need to send disconnect and do @@ -1134,13 +1133,9 @@ disconnect_neighbour (struct NeighbourMapEntry *n) set_state (n, GNUNET_TRANSPORT_PS_DISCONNECT); break; case GNUNET_TRANSPORT_PS_RECONNECT_ATS: - /* ATS address request timeout, disconnect without sending disconnect message */ - GNUNET_STATISTICS_set (GST_stats, - gettext_noop ("# peers connected"), - --neighbours_connected, - GNUNET_NO); - disconnect_notify_cb (callback_cls, &n->id); - set_state (n, GNUNET_TRANSPORT_PS_DISCONNECT); + /* Disconnecting while waiting for an ATS address to reconnect, + * cannot send DISCONNECT */ + free_neighbour (n, GNUNET_NO); break; case GNUNET_TRANSPORT_PS_DISCONNECT: /* already disconnected, ignore */ @@ -1680,7 +1675,7 @@ send_session_connect_cont (void *cls, n->primary_address.session); GNUNET_ATS_address_destroyed (GST_ats, n->primary_address.address, NULL ); unset_primary_address (n); - set_state_and_timeout (n, GNUNET_TRANSPORT_PS_RECONNECT_ATS, + set_state_and_timeout (n, GNUNET_TRANSPORT_PS_INIT_ATS, GNUNET_TIME_relative_to_absolute (FAST_RECONNECT_TIMEOUT)); break; case GNUNET_TRANSPORT_PS_RECONNECT_SENT: @@ -1689,7 +1684,7 @@ send_session_connect_cont (void *cls, n->primary_address.session); GNUNET_ATS_address_destroyed (GST_ats, n->primary_address.address, NULL ); unset_primary_address (n); - set_state_and_timeout (n, GNUNET_TRANSPORT_PS_INIT_ATS, + set_state_and_timeout (n, GNUNET_TRANSPORT_PS_RECONNECT_ATS, GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT)); break; case GNUNET_TRANSPORT_PS_CONNECTED_SWITCHING_CONNECT_SENT: @@ -1769,7 +1764,7 @@ send_session_connect (struct NeighbourAddress *na) case GNUNET_TRANSPORT_PS_CONNECT_SENT: /* Remove address and request and additional one */ unset_primary_address (n); - set_state_and_timeout (n, GNUNET_TRANSPORT_PS_RECONNECT_ATS, + set_state_and_timeout (n, GNUNET_TRANSPORT_PS_INIT_ATS, GNUNET_TIME_relative_to_absolute (FAST_RECONNECT_TIMEOUT)); /* Hard failure to send the CONNECT message with this address: Destroy address and session */ @@ -1777,7 +1772,7 @@ send_session_connect (struct NeighbourAddress *na) case GNUNET_TRANSPORT_PS_RECONNECT_SENT: /* Remove address and request and additional one */ unset_primary_address (n); - set_state_and_timeout (n, GNUNET_TRANSPORT_PS_INIT_ATS, + set_state_and_timeout (n, GNUNET_TRANSPORT_PS_RECONNECT_ATS, GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT)); break; case GNUNET_TRANSPORT_PS_CONNECTED_SWITCHING_CONNECT_SENT: @@ -3284,6 +3279,7 @@ GST_neighbours_session_terminated (const struct GNUNET_PeerIdentity *peer, free_neighbour (n, GNUNET_NO); return GNUNET_YES; case GNUNET_TRANSPORT_PS_CONNECTED: + /* Our primary connection died, try a fast reconnect */ unset_primary_address (n); set_state_and_timeout (n, GNUNET_TRANSPORT_PS_RECONNECT_ATS, GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT)); @@ -3315,7 +3311,9 @@ GST_neighbours_session_terminated (const struct GNUNET_PeerIdentity *peer, free_address (&n->primary_address); n->primary_address = n->alternative_address; memset (&n->alternative_address, 0, sizeof (struct NeighbourAddress)); - set_state_and_timeout (n, GNUNET_TRANSPORT_PS_RECONNECT_ATS, GNUNET_TIME_relative_to_absolute (FAST_RECONNECT_TIMEOUT)); + /* FIXME: Why GNUNET_TRANSPORT_PS_RECONNECT_ATS ?*/ + set_state_and_timeout (n, GNUNET_TRANSPORT_PS_RECONNECT_ATS, + GNUNET_TIME_relative_to_absolute (FAST_RECONNECT_TIMEOUT)); break; case GNUNET_TRANSPORT_PS_DISCONNECT: free_address (&n->primary_address); @@ -3473,6 +3471,21 @@ GST_neighbours_set_incoming_quota (const struct GNUNET_PeerIdentity *neighbour, disconnect_neighbour (n); } +void delayed_disconnect (void *cls, + const struct GNUNET_SCHEDULER_TaskContext* tc) +{ + struct NeighbourMapEntry *n = cls; + if (GNUNET_YES == test_connected (n)) + GNUNET_STATISTICS_update (GST_stats, + gettext_noop + ("# other peer asked to disconnect from us"), 1, + GNUNET_NO); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Disconnecting by request from peer %s\n", + GNUNET_i2s (&n->id)); + free_neighbour (n, GNUNET_NO); +} + /** * We received a disconnect message from the given peer, @@ -3493,10 +3506,10 @@ GST_neighbours_handle_disconnect_message (const struct GNUNET_PeerIdentity *peer GNUNET_i2s (peer)); if (ntohs (msg->size) != sizeof (struct SessionDisconnectMessage)) { - // GNUNET_break_op (0); + GNUNET_break_op (0); GNUNET_STATISTICS_update (GST_stats, gettext_noop - ("# disconnect messages ignored (old format)"), 1, + ("# disconnect messages ignored (malformed)"), 1, GNUNET_NO); return; } @@ -3544,15 +3557,7 @@ GST_neighbours_handle_disconnect_message (const struct GNUNET_PeerIdentity *peer GNUNET_break_op (0); return; } - if (GNUNET_YES == test_connected (n)) - GNUNET_STATISTICS_update (GST_stats, - gettext_noop - ("# other peer asked to disconnect from us"), 1, - GNUNET_NO); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Disconnecting by request from peer %s\n", - GNUNET_i2s (peer)); - disconnect_neighbour (n); + GNUNET_SCHEDULER_add_now (&delayed_disconnect, n); } @@ -3782,9 +3787,8 @@ GST_neighbours_stop () util_transmission_tk = GNUNET_SCHEDULER_NO_TASK; } - GNUNET_CONTAINER_multipeermap_iterate (neighbours, - &disconnect_all_neighbours, - NULL); + GNUNET_CONTAINER_multipeermap_iterate (neighbours, &disconnect_all_neighbours, + NULL ); GNUNET_CONTAINER_multipeermap_destroy (neighbours); next = pending_bc_head; diff --git a/src/transport/gnunet-transport.c b/src/transport/gnunet-transport.c index 684b5a92c..119584810 100644 --- a/src/transport/gnunet-transport.c +++ b/src/transport/gnunet-transport.c @@ -123,6 +123,11 @@ static int monitor_validation; */ static int try_connect; +/** + * Option -D. + */ +static int try_disconnect; + /** * Option -n. */ @@ -836,6 +841,25 @@ notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) if (0 != memcmp (&pid, peer, sizeof(struct GNUNET_PeerIdentity))) return; + if (try_disconnect) + { + /* all done, terminate instantly */ + FPRINTF (stdout, _("Successfully disconnected from `%s'\n"), + GNUNET_i2s_full (peer)); + ret = 0; + + if (GNUNET_SCHEDULER_NO_TASK != op_timeout) + { + GNUNET_SCHEDULER_cancel (op_timeout); + op_timeout = GNUNET_SCHEDULER_NO_TASK; + } + + if (GNUNET_SCHEDULER_NO_TASK != end) + GNUNET_SCHEDULER_cancel (end); + end = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL ); + return; + } + if (NULL != th) { GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); @@ -1159,6 +1183,31 @@ try_connect_cb (void *cls, const int result) } } +static void +try_disconnect_cb (void *cls, const int result) +{ + static int retries = 0; + if (GNUNET_OK == result) + { + tc_handle = NULL; + return; + } + retries++; + if (retries < 10) + tc_handle = GNUNET_TRANSPORT_try_disconnect (handle, &pid, try_disconnect_cb, + NULL ); + else + { + FPRINTF (stderr, "%s", + _("Failed to send connect request to transport service\n") ); + if (GNUNET_SCHEDULER_NO_TASK != end) + GNUNET_SCHEDULER_cancel (end); + ret = 1; + end = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL ); + return; + } +} + /** * Function called with the result of the check if the 'transport' * service is running. @@ -1188,7 +1237,7 @@ testservice_task (void *cls, int result) } counter = benchmark_send + benchmark_receive + iterate_connections - + monitor_connections + monitor_connects + try_connect + + monitor_connections + monitor_connects + try_connect + try_disconnect + + iterate_validation + monitor_validation; if (1 < counter) @@ -1237,6 +1286,36 @@ testservice_task (void *cls, int result) op_timeout = GNUNET_SCHEDULER_add_delayed (OP_TIMEOUT, &operation_timeout, NULL ); + } + else if (try_disconnect) /* -D: Disconnect from peer */ + { + if (NULL == cpid) + { + FPRINTF (stderr, _("Option `%s' makes no sense without option `%s'.\n"), + "-D", "-p"); + ret = 1; + return; + } + handle = GNUNET_TRANSPORT_connect (cfg, NULL, NULL, ¬ify_receive, + ¬ify_connect, ¬ify_disconnect); + if (NULL == handle) + { + FPRINTF (stderr, "%s", _("Failed to connect to transport service\n") ); + ret = 1; + return; + } + tc_handle = GNUNET_TRANSPORT_try_disconnect (handle, &pid, try_disconnect_cb, + NULL ); + if (NULL == tc_handle) + { + FPRINTF (stderr, "%s", + _("Failed to send request to transport service\n") ); + ret = 1; + return; + } + op_timeout = GNUNET_SCHEDULER_add_delayed (OP_TIMEOUT, &operation_timeout, + NULL ); + } else if (benchmark_send) /* -s: Benchmark sending */ { @@ -1367,9 +1446,13 @@ main (int argc, char * const *argv) 0, &GNUNET_GETOPT_set_one, &iterate_all }, { 'b', "benchmark", NULL, gettext_noop ("measure how fast we are receiving data from all peers (until CTRL-C)"), - 0, &GNUNET_GETOPT_set_one, &benchmark_receive }, { 'C', "connect", + 0, &GNUNET_GETOPT_set_one, &benchmark_receive }, + { 'C', "connect", NULL, gettext_noop ("connect to a peer"), 0, &GNUNET_GETOPT_set_one, &try_connect }, + { 'D', "disconnect", + NULL, gettext_noop ("disconnect to a peer"), 0, + &GNUNET_GETOPT_set_one, &try_disconnect }, { 'd', "validation", NULL, gettext_noop ("print information for all pending validations "), 0, &GNUNET_GETOPT_set_one, &iterate_validation }, diff --git a/src/transport/transport.h b/src/transport/transport.h index eceda49d4..7aa6c06a9 100644 --- a/src/transport/transport.h +++ b/src/transport/transport.h @@ -176,9 +176,9 @@ struct TransportRequestConnectMessage struct GNUNET_MessageHeader header; /** - * For alignment. + * Connect (GNUNET_YES) or connect (GNUNET_NO). */ - uint32_t reserved; + uint32_t connect; /** * Identity of the peer we would like to connect to. diff --git a/src/transport/transport_api.c b/src/transport/transport_api.c index c6ee3e47d..27a281afd 100644 --- a/src/transport/transport_api.c +++ b/src/transport/transport_api.c @@ -203,6 +203,8 @@ struct GNUNET_TRANSPORT_TryConnectHandle GNUNET_TRANSPORT_TryConnectCallback cb; + int connect; + /** * Closure for @e cb. */ @@ -1166,7 +1168,7 @@ send_try_connect (void *cls, size_t size, void *buf) GNUNET_assert (size >= sizeof (struct TransportRequestConnectMessage)); msg.header.size = htons (sizeof (struct TransportRequestConnectMessage)); msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_CONNECT); - msg.reserved = htonl (0); + msg.connect = htonl (tch->connect); msg.peer = tch->pid; memcpy (buf, &msg, sizeof (msg)); if (NULL != tch->cb) @@ -1203,6 +1205,7 @@ GNUNET_TRANSPORT_try_connect (struct GNUNET_TRANSPORT_Handle *handle, tch->pid = *(target); tch->cb = cb; tch->cb_cls = cb_cls; + tch->connect = GNUNET_YES; tch->tth = schedule_control_transmit (handle, sizeof (struct TransportRequestConnectMessage), &send_try_connect, tch); @@ -1221,6 +1224,7 @@ void GNUNET_TRANSPORT_try_connect_cancel (struct GNUNET_TRANSPORT_TryConnectHandle *tch) { struct GNUNET_TRANSPORT_Handle *th; + GNUNET_assert (GNUNET_YES == tch->connect); th = tch->th; cancel_control_transmit (th, tch->tth); @@ -1228,6 +1232,62 @@ GNUNET_TRANSPORT_try_connect_cancel (struct GNUNET_TRANSPORT_TryConnectHandle *t GNUNET_free (tch); } +/** + * Ask the transport service to shutdown a connection to + * the given peer. + * + * @param handle connection to transport service + * @param target who we should try to connect to + * @param cb callback to be called when request was transmitted to transport + * service + * @param cb_cls closure for the callback + * @return a `struct GNUNET_TRANSPORT_TryConnectHandle` handle or + * NULL on failure (cb will not be called) + */ +struct GNUNET_TRANSPORT_TryConnectHandle * +GNUNET_TRANSPORT_try_disconnect (struct GNUNET_TRANSPORT_Handle *handle, + const struct GNUNET_PeerIdentity *target, + GNUNET_TRANSPORT_TryConnectCallback cb, + void *cb_cls) +{ + struct GNUNET_TRANSPORT_TryConnectHandle *tch = NULL; + + if (NULL == handle->client) + return NULL; + tch = GNUNET_new (struct GNUNET_TRANSPORT_TryConnectHandle); + tch->th = handle; + tch->pid = *(target); + tch->cb = cb; + tch->cb_cls = cb_cls; + tch->connect = GNUNET_NO; + tch->tth = schedule_control_transmit (handle, + sizeof (struct TransportRequestConnectMessage), + &send_try_connect, tch); + GNUNET_CONTAINER_DLL_insert(handle->tc_head, handle->tc_tail, tch); + return tch; +} + + +/** + * Cancel the request to transport to try a disconnect + * Callback will not be called + * + * @param tch the handle to cancel + */ +void +GNUNET_TRANSPORT_try_disconnect_cancel (struct GNUNET_TRANSPORT_TryConnectHandle *tch) +{ + struct GNUNET_TRANSPORT_Handle *th; + GNUNET_assert (GNUNET_NO == tch->connect); + + th = tch->th; + cancel_control_transmit (th, tch->tth); + GNUNET_CONTAINER_DLL_remove (th->tc_head, th->tc_tail, tch); + GNUNET_free (tch); +} + + + /** * Send HELLO message to the service. -- 2.25.1