|
@@ -32,6 +32,9 @@ safe_or_conn_link_protocol_version_cb(event_label_t label, event_data_t data,
|
|
static void
|
|
static void
|
|
safe_or_conn_open_cb(event_label_t label, event_data_t data, void *context);
|
|
safe_or_conn_open_cb(event_label_t label, event_data_t data, void *context);
|
|
|
|
|
|
|
|
+static void
|
|
|
|
+safe_or_conn_closed_cb(event_label_t label, event_data_t data, void *context);
|
|
|
|
+
|
|
static tor_error_t
|
|
static tor_error_t
|
|
safe_or_connection_update_state(safe_or_connection_t *safe_or_conn,
|
|
safe_or_connection_update_state(safe_or_connection_t *safe_or_conn,
|
|
or_conn_state_t new_state);
|
|
or_conn_state_t new_state);
|
|
@@ -233,7 +236,7 @@ safe_connection_set_socket(safe_connection_t *safe_conn, tor_socket_t socket)
|
|
tor_assert(!safe_conn->linked);
|
|
tor_assert(!safe_conn->linked);
|
|
tor_assert(SOCKET_OK(socket));
|
|
tor_assert(SOCKET_OK(socket));
|
|
|
|
|
|
- if (safe_conn->socket != TOR_INVALID_SOCKET) {
|
|
|
|
|
|
+ if (SOCKET_OK(safe_conn->socket)) {
|
|
log_warn(LD_BUG, "We're overwriting a previous socket");
|
|
log_warn(LD_BUG, "We're overwriting a previous socket");
|
|
}
|
|
}
|
|
safe_conn->socket = socket;
|
|
safe_conn->socket = socket;
|
|
@@ -245,6 +248,25 @@ safe_connection_set_socket(safe_connection_t *safe_conn, tor_socket_t socket)
|
|
tor_mutex_release(&safe_conn->lock);
|
|
tor_mutex_release(&safe_conn->lock);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static void
|
|
|
|
+safe_connection_close_socket(safe_connection_t *safe_conn)
|
|
|
|
+{
|
|
|
|
+ tor_assert(safe_conn != NULL);
|
|
|
|
+ tor_mutex_acquire(&safe_conn->lock);
|
|
|
|
+
|
|
|
|
+ safe_connection_unregister_events(safe_conn);
|
|
|
|
+ event_listener_detach(safe_conn->event_listener);
|
|
|
|
+ // assume it's safe at this point we don't care about any more events
|
|
|
|
+ // TODO: improve this (possibly with something like a sentinel event)
|
|
|
|
+
|
|
|
|
+ if (SOCKET_OK(safe_conn->socket)) {
|
|
|
|
+ tor_close_socket(safe_conn->socket);
|
|
|
|
+ safe_conn->socket = TOR_INVALID_SOCKET;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ tor_mutex_release(&safe_conn->lock);
|
|
|
|
+}
|
|
|
|
+
|
|
static void
|
|
static void
|
|
safe_connection_read_cb(evutil_socket_t ev_sock, short fd, void *void_safe_conn)
|
|
safe_connection_read_cb(evutil_socket_t ev_sock, short fd, void *void_safe_conn)
|
|
{
|
|
{
|
|
@@ -343,7 +365,10 @@ safe_connection_unregister_events(safe_connection_t *safe_conn)
|
|
if (safe_conn->write_event != NULL) {
|
|
if (safe_conn->write_event != NULL) {
|
|
tor_event_free(safe_conn->write_event);
|
|
tor_event_free(safe_conn->write_event);
|
|
}
|
|
}
|
|
- event_listener_detach(safe_conn->event_listener);
|
|
|
|
|
|
+
|
|
|
|
+ // we may still want to receive events, so we don't detach the
|
|
|
|
+ // event listener yet
|
|
|
|
+ // TODO: figure out a better way of handling this
|
|
|
|
|
|
tor_mutex_release(&safe_conn->lock);
|
|
tor_mutex_release(&safe_conn->lock);
|
|
}
|
|
}
|
|
@@ -360,6 +385,7 @@ safe_connection_register_events(safe_connection_t *safe_conn,
|
|
// is either linked or has a socket, but not both (or neither)
|
|
// is either linked or has a socket, but not both (or neither)
|
|
|
|
|
|
safe_connection_unregister_events(safe_conn);
|
|
safe_connection_unregister_events(safe_conn);
|
|
|
|
+ event_listener_detach(safe_conn->event_listener);
|
|
|
|
|
|
safe_conn->read_event = tor_event_new(event_base, safe_conn->socket,
|
|
safe_conn->read_event = tor_event_new(event_base, safe_conn->socket,
|
|
EV_READ|EV_PERSIST,
|
|
EV_READ|EV_PERSIST,
|
|
@@ -536,6 +562,9 @@ safe_or_connection_new(bool requires_buffers, bool is_outgoing,
|
|
event_listener_set_callback(TO_SAFE_CONN(safe_or_conn)->event_listener,
|
|
event_listener_set_callback(TO_SAFE_CONN(safe_or_conn)->event_listener,
|
|
or_conn_open_ev,
|
|
or_conn_open_ev,
|
|
NULL, safe_or_conn_open_cb);
|
|
NULL, safe_or_conn_open_cb);
|
|
|
|
+ event_listener_set_callback(TO_SAFE_CONN(safe_or_conn)->event_listener,
|
|
|
|
+ or_conn_closed_ev,
|
|
|
|
+ NULL, safe_or_conn_closed_cb);
|
|
event_listener_set_callback(TO_SAFE_CONN(safe_or_conn)->event_listener,
|
|
event_listener_set_callback(TO_SAFE_CONN(safe_or_conn)->event_listener,
|
|
or_conn_outgoing_packed_cell,
|
|
or_conn_outgoing_packed_cell,
|
|
NULL, safe_or_conn_outgoing_cell_cb);
|
|
NULL, safe_or_conn_outgoing_cell_cb);
|
|
@@ -553,6 +582,9 @@ safe_or_connection_new(bool requires_buffers, bool is_outgoing,
|
|
event_source_subscribe(conn_event_source,
|
|
event_source_subscribe(conn_event_source,
|
|
TO_SAFE_CONN(safe_or_conn)->event_listener,
|
|
TO_SAFE_CONN(safe_or_conn)->event_listener,
|
|
or_conn_open_ev);
|
|
or_conn_open_ev);
|
|
|
|
+ event_source_subscribe(conn_event_source,
|
|
|
|
+ TO_SAFE_CONN(safe_or_conn)->event_listener,
|
|
|
|
+ or_conn_closed_ev);
|
|
event_source_subscribe(conn_event_source,
|
|
event_source_subscribe(conn_event_source,
|
|
TO_SAFE_CONN(safe_or_conn)->event_listener,
|
|
TO_SAFE_CONN(safe_or_conn)->event_listener,
|
|
or_conn_outgoing_packed_cell);
|
|
or_conn_outgoing_packed_cell);
|
|
@@ -686,6 +718,27 @@ safe_or_conn_open_cb(event_label_t label, event_data_t data, void *context)
|
|
tor_mutex_release(&TO_SAFE_CONN(safe_or_conn)->lock);
|
|
tor_mutex_release(&TO_SAFE_CONN(safe_or_conn)->lock);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static void
|
|
|
|
+safe_or_conn_closed_cb(event_label_t label, event_data_t data, void *context)
|
|
|
|
+{
|
|
|
|
+ (void)data;
|
|
|
|
+
|
|
|
|
+ safe_or_connection_t *safe_or_conn = TO_SAFE_OR_CONN(context);
|
|
|
|
+ tor_assert(label == or_conn_closed_ev);
|
|
|
|
+ tor_assert(safe_or_conn != NULL);
|
|
|
|
+ tor_mutex_acquire(&TO_SAFE_CONN(safe_or_conn)->lock);
|
|
|
|
+
|
|
|
|
+ // TODO: we should support closing forcefully and closing gracefully
|
|
|
|
+ // with a CLOSING state (which only flushes remaining data)
|
|
|
|
+
|
|
|
|
+ if (safe_or_conn->state != SAFE_OR_CONN_STATE_CLOSED) {
|
|
|
|
+ // if we're already closed, then just ignore it
|
|
|
|
+ safe_or_connection_update_state(safe_or_conn, SAFE_OR_CONN_STATE_CLOSED);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ tor_mutex_release(&TO_SAFE_CONN(safe_or_conn)->lock);
|
|
|
|
+}
|
|
|
|
+
|
|
// TODO: we should get rid of this at some point
|
|
// TODO: we should get rid of this at some point
|
|
void
|
|
void
|
|
safe_or_connection_get_tls_desc(safe_or_connection_t *safe_or_conn,
|
|
safe_or_connection_get_tls_desc(safe_or_connection_t *safe_or_conn,
|
|
@@ -926,6 +979,8 @@ safe_or_connection_update_state(safe_or_connection_t *safe_or_conn,
|
|
log_warn(LD_OR, "Could not create a new tor TLS object");
|
|
log_warn(LD_OR, "Could not create a new tor TLS object");
|
|
return E_ERROR;
|
|
return E_ERROR;
|
|
}
|
|
}
|
|
|
|
+ tor_tls_release_socket(safe_or_conn->tls);
|
|
|
|
+ // we want to have control over closing the socket
|
|
if (safe_or_conn->remote_address_str != NULL) {
|
|
if (safe_or_conn->remote_address_str != NULL) {
|
|
tor_tls_set_logged_address(safe_or_conn->tls,
|
|
tor_tls_set_logged_address(safe_or_conn->tls,
|
|
safe_or_conn->remote_address_str);
|
|
safe_or_conn->remote_address_str);
|
|
@@ -993,6 +1048,11 @@ safe_or_connection_update_state(safe_or_connection_t *safe_or_conn,
|
|
TO_SAFE_CONN(safe_or_conn));
|
|
TO_SAFE_CONN(safe_or_conn));
|
|
event_source_publish(TO_SAFE_CONN(safe_or_conn)->event_source,
|
|
event_source_publish(TO_SAFE_CONN(safe_or_conn)->event_source,
|
|
safe_or_conn_closed_ev, null_data, NULL);
|
|
safe_or_conn_closed_ev, null_data, NULL);
|
|
|
|
+ if (safe_or_conn->tls != NULL) {
|
|
|
|
+ tor_tls_free(safe_or_conn->tls);
|
|
|
|
+ safe_or_conn->tls = NULL;
|
|
|
|
+ }
|
|
|
|
+ safe_connection_close_socket(TO_SAFE_CONN(safe_or_conn));
|
|
break;
|
|
break;
|
|
default:
|
|
default:
|
|
log_warn(LD_OR, "Unexpected state");
|
|
log_warn(LD_OR, "Unexpected state");
|