|
@@ -3,13 +3,19 @@
|
|
|
#include "lib/net/buffers_net.h"
|
|
|
#include "lib/tls/tortls.h"
|
|
|
#include "lib/tls/buffers_tls.h"
|
|
|
+#include "lib/malloc/malloc.h"
|
|
|
+#include "core/proto/proto_cell.h"
|
|
|
+#include "core/or/connection_or.h"
|
|
|
+#include "core/or/var_cell_st.h"
|
|
|
+#include "core/or/cell_st.h"
|
|
|
|
|
|
event_label_t safe_or_conn_tcp_connecting_ev = EVENT_LABEL_UNSET;
|
|
|
event_label_t safe_or_conn_tls_handshaking_ev = EVENT_LABEL_UNSET;
|
|
|
event_label_t safe_or_conn_link_handshaking_ev = EVENT_LABEL_UNSET;
|
|
|
event_label_t safe_or_conn_open_ev = EVENT_LABEL_UNSET;
|
|
|
event_label_t safe_or_conn_closed_ev = EVENT_LABEL_UNSET;
|
|
|
-event_label_t safe_or_conn_has_buffered_data_ev = EVENT_LABEL_UNSET;
|
|
|
+event_label_t safe_or_conn_fixed_cell_ev = EVENT_LABEL_UNSET;
|
|
|
+event_label_t safe_or_conn_var_cell_ev = EVENT_LABEL_UNSET;
|
|
|
|
|
|
static void
|
|
|
safe_connection_refresh_events(safe_connection_t *safe_conn);
|
|
@@ -39,6 +45,9 @@ safe_or_connection_socket_added_cb(safe_connection_t *safe_conn);
|
|
|
static void
|
|
|
safe_or_connection_outbuf_modified_cb(safe_connection_t *safe_conn);
|
|
|
|
|
|
+static void
|
|
|
+process_cells_from_inbuf(safe_or_connection_t *safe_or_conn);
|
|
|
+
|
|
|
/********************************************************/
|
|
|
|
|
|
safe_or_connection_t *
|
|
@@ -57,7 +66,8 @@ safe_or_conn_register_events(event_registry_t *registry)
|
|
|
tor_assert(safe_or_conn_link_handshaking_ev == EVENT_LABEL_UNSET);
|
|
|
tor_assert(safe_or_conn_open_ev == EVENT_LABEL_UNSET);
|
|
|
tor_assert(safe_or_conn_closed_ev == EVENT_LABEL_UNSET);
|
|
|
- tor_assert(safe_or_conn_has_buffered_data_ev == EVENT_LABEL_UNSET);
|
|
|
+ tor_assert(safe_or_conn_fixed_cell_ev == EVENT_LABEL_UNSET);
|
|
|
+ tor_assert(safe_or_conn_var_cell_ev == EVENT_LABEL_UNSET);
|
|
|
|
|
|
safe_or_conn_tcp_connecting_ev = \
|
|
|
event_registry_register_event(registry, "OR Connection Connecting");
|
|
@@ -69,17 +79,10 @@ safe_or_conn_register_events(event_registry_t *registry)
|
|
|
event_registry_register_event(registry, "OR Connection Open");
|
|
|
safe_or_conn_closed_ev = \
|
|
|
event_registry_register_event(registry, "OR Connection Closed");
|
|
|
- safe_or_conn_has_buffered_data_ev = \
|
|
|
- event_registry_register_event(registry, "OR Connection Has Data In Buffer");
|
|
|
-}
|
|
|
-
|
|
|
-void
|
|
|
-safe_or_conn_buf_data_event_update(event_label_t label,
|
|
|
- event_data_t *old_data,
|
|
|
- event_data_t *new_data)
|
|
|
-{
|
|
|
- tor_assert(label == safe_or_conn_has_buffered_data_ev);
|
|
|
- old_data->u64 += new_data->u64;
|
|
|
+ safe_or_conn_fixed_cell_ev = \
|
|
|
+ event_registry_register_event(registry, "OR Connection New Fixed-Size Cell");
|
|
|
+ safe_or_conn_var_cell_ev = \
|
|
|
+ event_registry_register_event(registry, "OR Connection New Variable-Size Cell");
|
|
|
}
|
|
|
|
|
|
/********************************************************/
|
|
@@ -448,6 +451,10 @@ safe_or_connection_new(bool requires_buffers, bool is_outgoing,
|
|
|
log_warn(LD_OR, "No remote address string was provided");
|
|
|
}
|
|
|
|
|
|
+ safe_or_conn->link_protocol = 0; // unknown protocol
|
|
|
+ safe_or_conn->wide_circ_ids = false;
|
|
|
+ safe_or_conn->allowed_to_process_cells = true;
|
|
|
+
|
|
|
// these states should be set by 'safe_or_connection_update_state()'
|
|
|
socket_rw_state_init(&safe_or_conn->tor_read_wanted, false);
|
|
|
socket_rw_state_init(&safe_or_conn->tor_write_wanted, false);
|
|
@@ -519,6 +526,23 @@ safe_or_connection_refresh_bucket_rw_states(safe_or_connection_t *safe_or_conn)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+void
|
|
|
+safe_or_connection_set_link_protocol(safe_or_connection_t *safe_or_conn,
|
|
|
+ uint16_t link_protocol)
|
|
|
+{
|
|
|
+ tor_assert(safe_or_conn != NULL);
|
|
|
+ tor_assert(link_protocol >= 3);
|
|
|
+ tor_assert(safe_or_conn->allowed_to_process_cells == false);
|
|
|
+ tor_mutex_acquire(&TO_SAFE_CONN(safe_or_conn)->lock);
|
|
|
+
|
|
|
+ safe_or_conn->link_protocol = link_protocol;
|
|
|
+ safe_or_conn->wide_circ_ids = (link_protocol >= 3);
|
|
|
+ safe_or_conn->allowed_to_process_cells = true;
|
|
|
+ event_active(TO_SAFE_CONN(safe_or_conn)->read_event, 0, 0);
|
|
|
+
|
|
|
+ tor_mutex_release(&TO_SAFE_CONN(safe_or_conn)->lock);
|
|
|
+}
|
|
|
+
|
|
|
// TODO: we should get rid of this at some point
|
|
|
void
|
|
|
safe_or_connection_get_tls_desc(safe_or_connection_t *safe_or_conn,
|
|
@@ -1033,13 +1057,6 @@ safe_or_connection_read_encrypted(safe_or_connection_t *safe_or_conn,
|
|
|
bytes_read);
|
|
|
}
|
|
|
|
|
|
- // let any listeners know that we have new data in our incoming buffer
|
|
|
- if (bytes_read > 0) {
|
|
|
- event_data_t event_data = { .u64 = bytes_read };
|
|
|
- event_source_publish(TO_SAFE_CONN(safe_or_conn)->event_source,
|
|
|
- safe_or_conn_has_buffered_data_ev, event_data, NULL);
|
|
|
- }
|
|
|
-
|
|
|
size_t tls_bytes_read = 0;
|
|
|
size_t tls_bytes_written = 0;
|
|
|
tor_tls_get_n_raw_bytes(safe_or_conn->tls, &tls_bytes_read,
|
|
@@ -1316,6 +1333,11 @@ safe_or_connection_read_cb(safe_connection_t *safe_conn)
|
|
|
tor_assert(safe_or_connection_update_state(safe_or_conn,
|
|
|
SAFE_OR_CONN_STATE_CLOSED) == E_SUCCESS);
|
|
|
}
|
|
|
+
|
|
|
+ if (safe_or_conn->allowed_to_process_cells) {
|
|
|
+ process_cells_from_inbuf(safe_or_conn);
|
|
|
+ }
|
|
|
+
|
|
|
break;
|
|
|
}
|
|
|
case SAFE_OR_CONN_STATE_CLOSED:
|
|
@@ -1416,3 +1438,96 @@ safe_or_connection_write_cb(safe_connection_t *safe_conn)
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+/********************************************************/
|
|
|
+
|
|
|
+static bool
|
|
|
+fetch_cell(safe_or_connection_t *safe_or_conn, char *cell_buf)
|
|
|
+{
|
|
|
+ safe_connection_t *safe_conn = TO_SAFE_CONN(safe_or_conn);
|
|
|
+
|
|
|
+ size_t cell_network_size = \
|
|
|
+ get_cell_network_size(safe_or_conn->wide_circ_ids?1:0);
|
|
|
+
|
|
|
+ if (buf_datalen(safe_conn->inbuf) < cell_network_size) {
|
|
|
+ // don't have a full cell
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ buf_get_bytes(safe_conn->inbuf, cell_buf, cell_network_size);
|
|
|
+ safe_connection_inbuf_modified(safe_conn);
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+static bool
|
|
|
+fetch_var_cell(safe_or_connection_t *safe_or_conn, var_cell_t **var_cell_ptr)
|
|
|
+{
|
|
|
+ safe_connection_t *safe_conn = TO_SAFE_CONN(safe_or_conn);
|
|
|
+
|
|
|
+ int link_protocol = safe_or_conn->link_protocol;
|
|
|
+ *var_cell_ptr = NULL;
|
|
|
+ int found_var_cell = fetch_var_cell_from_buf(safe_conn->inbuf, var_cell_ptr,
|
|
|
+ link_protocol);
|
|
|
+ if (*var_cell_ptr != NULL) {
|
|
|
+ // there was not a *full* cell
|
|
|
+ safe_connection_inbuf_modified(safe_conn);
|
|
|
+ }
|
|
|
+ return (found_var_cell != 0);
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+void_var_cell_free(void *void_var_cell)
|
|
|
+{
|
|
|
+ var_cell_free_((var_cell_t *)void_var_cell);
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+process_cells_from_inbuf(safe_or_connection_t *safe_or_conn)
|
|
|
+{
|
|
|
+ tor_assert(safe_or_conn != NULL);
|
|
|
+
|
|
|
+ while (true) {
|
|
|
+ var_cell_t *var_cell = NULL;
|
|
|
+ bool found_var_cell = fetch_var_cell(safe_or_conn, &var_cell);
|
|
|
+
|
|
|
+ if (found_var_cell) {
|
|
|
+ if (var_cell == NULL) {
|
|
|
+ // the next cell is a var cell, but it is not yet complete
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ event_data_t event_data = { .ptr = var_cell };
|
|
|
+ event_source_publish(TO_SAFE_CONN(safe_or_conn)->event_source,
|
|
|
+ safe_or_conn_var_cell_ev, event_data,
|
|
|
+ void_var_cell_free);
|
|
|
+
|
|
|
+ if (safe_or_conn->link_protocol == 0 &&
|
|
|
+ var_cell->command == CELL_VERSIONS) {
|
|
|
+ // this is the first VERSIONS cell we've received;
|
|
|
+ // in order to process future cells, we need to be told our
|
|
|
+ // protocol version
|
|
|
+ safe_or_conn->allowed_to_process_cells = false;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ char buf[CELL_MAX_NETWORK_SIZE];
|
|
|
+ bool found_cell = fetch_cell(safe_or_conn, buf);
|
|
|
+
|
|
|
+ if (found_cell) {
|
|
|
+ // retrieve cell info from buf (create the host-order struct from the
|
|
|
+ // network-order string)
|
|
|
+ cell_t *cell = tor_malloc(sizeof(cell_t));
|
|
|
+ cell_unpack(cell, buf, safe_or_conn->wide_circ_ids?1:0);
|
|
|
+
|
|
|
+ event_data_t event_data = { .ptr = cell };
|
|
|
+ event_source_publish(TO_SAFE_CONN(safe_or_conn)->event_source,
|
|
|
+ safe_or_conn_fixed_cell_ev, event_data,
|
|
|
+ tor_free_);
|
|
|
+ } else {
|
|
|
+ // there is not yet a complete cell
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|