9#define TOR_CONFLUX_PRIVATE
10#define CONFLUX_CELL_PRIVATE
23#include "trunnel/conflux.h"
32#include "core/or/or_circuit_st.h"
46static bool shutting_down =
false;
81 uint64_t link_sent_usec;
96 bool is_for_linked_set;
109 ERR_LINK_CIRC_OK = 0,
111 ERR_LINK_CIRC_BAD_RTT = 1,
113 ERR_LINK_CIRC_MISSING_LEG = 2,
115 ERR_LINK_CIRC_MISSING_SET = 3,
117 ERR_LINK_CIRC_INVALID_LEG = 4,
122get_unlinked_pool(
bool is_client)
128get_linked_pool(
bool is_client)
136STATIC uint8_t DEFAULT_CLIENT_UX = CONFLUX_UX_HIGH_THROUGHPUT;
137STATIC uint8_t DEFAULT_EXIT_UX = CONFLUX_UX_MIN_LATENCY;
140static inline const char *
143 return hex_str((
char *) nonce, 8);
152 switch (desired_ux) {
153 case CONFLUX_UX_NO_OPINION:
154 return CONFLUX_ALG_LOWRTT;
155 case CONFLUX_UX_MIN_LATENCY:
156 return CONFLUX_ALG_MINRTT;
157 case CONFLUX_UX_HIGH_THROUGHPUT:
158 return CONFLUX_ALG_LOWRTT;
162 case CONFLUX_UX_LOW_MEM_THROUGHPUT:
163 case CONFLUX_UX_LOW_MEM_LATENCY:
164 return CONFLUX_ALG_MINRTT;
168 return CONFLUX_ALG_LOWRTT;
176 conflux_t *cfx = tor_malloc_zero(
sizeof(*cfx));
196 } SMARTLIST_FOREACH_END(leg);
197 smartlist_free(cfx->
legs);
200 smartlist_free(cfx->
ooo_q);
207#define conflux_free(cfx) \
208 FREE_AND_NULL(conflux_t, conflux_free_, cfx)
223 leg_t *leg = tor_malloc_zero(
sizeof(*leg));
252 unlinked->is_client = is_client;
253 memcpy(unlinked->cfx->
nonce, nonce,
sizeof(unlinked->cfx->
nonce));
268 if (!unlinked->is_for_linked_set) {
272 smartlist_free(unlinked->legs);
374 if (leg->circ == circ) {
377 } SMARTLIST_FOREACH_END(leg);
401 if (leg->circ == circ) {
406 } SMARTLIST_FOREACH_END(leg);
422 "Unlinked Conflux circuit %u has attached streams.",
428 "Unlinked conflux circ %u has half streams.",
436 "Unlinked conflux circuit has attached streams.");
441 "Unlinked conflux circuit has resolving streams.");
454 uint8_t *nonce = NULL;
460 nonce = leg->link->nonce;
461 version = leg->link->version;
464 valid &= (leg->link->version == version &&
465 tor_memeq(leg->link->nonce, nonce,
sizeof(leg->link->nonce)));
472 "Data loss detected while trying to add a conflux leg.");
482 } SMARTLIST_FOREACH_END(leg);
501 cleg->
circ = leg->circ;
559 bool full_teardown =
false;
574 full_teardown =
true;
575 log_info(
LD_CIRC,
"Conflux current circuit has closed with "
576 "data in flight, tearing down entire set.");
589 full_teardown =
true;
590 log_info(
LD_CIRC,
"Conflux sequence number check failed, "
591 "tearing down entire set.");
598 full_teardown =
true;
599 log_info(
LD_CIRC,
"Conflux current circuit has closed, "
600 "tearing down entire set.");
609 return full_teardown;
621 if (smartlist_len(unlinked->legs) == 0) {
641 circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL);
643 } SMARTLIST_FOREACH_END(circ);
646 smartlist_free(circ_to_close);
665 if (smartlist_len(unlinked->legs) > 0) {
688 memcpy(nonce_localcopy, nonce,
sizeof(nonce_localcopy));
714 circuit_mark_for_close(circ, reason));
717 smartlist_free(circ_to_close);
745 if (BUG(smartlist_len(unlinked->legs) == 0)) {
746 err = ERR_LINK_CIRC_MISSING_LEG;
751 if (smartlist_len(unlinked->legs) +
752 smartlist_len(unlinked->cfx->
legs) > conflux_params_get_max_legs_set()) {
754 "Conflux set has too many legs to link. "
755 "Rejecting this circuit.");
756 conflux_log_set(LOG_PROTOCOL_WARN, unlinked->cfx, unlinked->is_client);
757 err = ERR_LINK_CIRC_INVALID_LEG;
766 "Conflux unlinked set legs are not validating. Tearing it down.");
768 END_CIRC_REASON_TORPROTOCOL);
769 err = ERR_LINK_CIRC_INVALID_LEG;
778 log_info(
LD_CIRC,
"Can't finalize conflux set, still waiting on at "
779 "least one leg to link up.");
783 } SMARTLIST_FOREACH_END(leg);
795 leg->circ->conflux = unlinked->cfx;
799 } SMARTLIST_FOREACH_END(leg);
801 is_client = unlinked->is_client;
817 unlinked->cfx = NULL;
821 "Successfully linked a conflux %s set which is now usable.",
822 is_client ?
"client" :
"relay");
841 if (BUG(!leg || leg->link_sent_usec == 0)) {
843 "Conflux: Trying to record client RTT without a timestamp");
848 tor_assert_nonfatal(now >= leg->link_sent_usec);
849 leg->rtt_usec = now - leg->link_sent_usec;
850 if (leg->rtt_usec == 0) {
851 log_warn(
LD_CIRC,
"Clock appears stalled for conflux.");
857 return leg->rtt_usec;
862 leg->rtt_usec = UINT64_MAX;
882 "Conflux: Trying to record exit RTT without a timestamp");
891 log_warn(
LD_CIRC,
"Clock appears stalled for conflux.");
916 if (rtt_usec == UINT64_MAX)
920 log_info(
LD_CIRC,
"Conflux leg RTT is above circuit build time out "
921 "currently at %f msec. Relaunching.",
943 bool is_client =
false;
952 if (BUG(!unlinked)) {
953 log_warn(
LD_BUG,
"Failed to find the unlinked set %s when linking. "
956 err = ERR_LINK_CIRC_MISSING_SET;
964 log_warn(
LD_BUG,
"Failed to find leg for the unlinked set %s when "
965 "linking. Closing circuit.",
967 err = ERR_LINK_CIRC_MISSING_LEG;
992 for (
int i = 0; i < num_legs; i++) {
1007unlinked_get_or_create(
const uint8_t *nonce,
bool is_client)
1023 unlinked->cfx = cfx;
1024 unlinked->is_for_linked_set =
true;
1064 if (smartlist_len(unlinked->legs) > 0) {
1066 leg_t *leg = smartlist_get(unlinked->legs, 0);
1085#ifdef TOR_UNIT_TESTS
1086 return DEFAULT_CLIENT_UX;
1090 (void)DEFAULT_CLIENT_UX;
1093 return opt->ConfluxClientUX;
1108 unsigned int max_num_launch =
1109 conflux_params_get_num_legs_set() +
1110 conflux_params_get_max_unlinked_leg_retry();
1114 log_info(
LD_CIRC,
"Maximum number of leg launch reached for nonce %s",
1145 unlinked = unlinked_get_or_create(nonce,
true);
1157 log_info(
LD_CIRC,
"Launching conflux leg for nonce %s.",
fmt_nonce(nonce));
1159 log_info(
LD_CIRC,
"Launching new conflux set for nonce %s.",
1180 if (!circ ||
TO_CIRCUIT(circ)->marked_for_close) {
1184 if (BUG(!
TO_CIRCUIT(circ)->conflux_pending_nonce || !unlinked->cfx)) {
1205 conflux_cell_new_link(nonce,
1206 last_seq_sent, last_seq_recv,
1233 if (!CIRCUIT_IS_CONFLUX(circ)) {
1262 } CONFLUX_FOR_EACH_LEG_END(leg);
1277 } SMARTLIST_FOREACH_END(leg);
1301 if (!CIRCUIT_IS_CONFLUX(circ)) {
1324 } CONFLUX_FOR_EACH_LEG_END(leg);
1341 } SMARTLIST_FOREACH_END(leg);
1353 if (BUG(!leg->
circ)) {
1354 log_warn(
LD_BUG,
"Client conflux linked set leg without a circuit");
1360 if (!CONST_TO_ORIGIN_CIRCUIT(leg->
circ)->unusable_for_new_conns &&
1365 } DIGEST256MAP_FOREACH_END;
1382 if (!conflux_is_enabled(NULL) ||
1390 conflux_params_get_max_linked_set()) {
1398 int num_set = num_unlinked + num_linked;
1399 int max_prebuilt = conflux_params_get_max_prebuilt();
1401 if (num_set >= max_prebuilt) {
1405 log_info(
LD_CIRC,
"Preemptively launching new conflux circuit set(s). "
1406 "We have %d linked and %d unlinked.",
1407 num_linked, num_unlinked);
1409 for (
int i = 0; i < (max_prebuilt - num_set); i++) {
1441 if (BUG(leg->
circ->
purpose != CIRCUIT_PURPOSE_CONFLUX_LINKED)) {
1456 CIRCUIT_PURPOSE_CONFLUX_LINKED,
1458 need_internal, now)) {
1464 } DIGEST256MAP_FOREACH_END;
1477 bool is_client =
false;
1499 log_info(
LD_CIRC,
"Conflux unlinked circuit with nonce %s has closed",
1503 unlinked_leg_del_and_free(unlinked, circ);
1507 if (smartlist_len(unlinked->legs) == 0) {
1534 tor_assert_nonfatal(circ->
conflux);
1538 tor_assert_nonfatal(circ->
purpose == CIRCUIT_PURPOSE_CONFLUX_LINKED);
1543 stream->on_circuit = circ;
1544 stream->cpath_layer = ocirc->
cpath->
prev;
1552 stream->on_circuit = circ;
1558 stream->on_circuit = circ;
1585 bool is_client =
false;
1586 bool full_teardown =
false;
1593 tor_assert_nonfatal(circ->
purpose == CIRCUIT_PURPOSE_CONFLUX_LINKED);
1636 if (full_teardown) {
1665 if (BUG(!shutting_down)) {
1667 "Conflux circuit %p being freed without being marked for "
1668 "full teardown via close, with shutdown state %d. "
1669 "Please report this.", circ, shutting_down);
1698 unlinked->is_for_linked_set =
false;
1758 if (!conflux_is_enabled(circ)) {
1759 circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL);
1760 static ratelim_t conflux_ratelim = RATELIM_INIT(600);
1762 "Conflux circuit opened without negotiating "
1763 "congestion control");
1772 log_info(
LD_CIRC,
"Conflux circuit has opened with nonce %s",
1777 log_warn(
LD_CIRC,
"Unable to find conflux leg in unlinked set.");
1783 if (!conflux_cell_send_link(leg->link, orig_circ)) {
1806 if (!conflux_is_enabled(circ)) {
1807 circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL);
1815 "Got a CONFLUX_LINK cell on an origin circuit. Closing circuit.");
1816 circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL);
1822 "Got a CONFLUX_LINK with further hops. Closing circuit.");
1823 circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL);
1829 "Got a CONFLUX_LINK on a circuit with a pending nonce. "
1830 "Closing circuit.");
1831 circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL);
1837 "Got a CONFLUX_LINK on an already linked circuit "
1838 "Closing circuit.");
1839 circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL);
1844 link = conflux_cell_parse_link(msg);
1847 "CONFLUX_LINK cell. Closing circuit.");
1848 circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL);
1852 log_info(
LD_CIRC,
"Processing a CONFLUX_LINK for set %s",
1858 unlinked = unlinked_get_or_create(link->nonce,
false);
1866 sizeof(leg->link->nonce));
1890 circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL);
1933 if (!conflux_is_enabled(circ)) {
1934 circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL);
1942 "Received CONFLUX_LINKED cell on a non origin circuit.");
1948 "Received a CONFLUX_LINKED cell without having sent a "
1949 "CONFLUX_LINK cell. Closing circuit.");
1955 "Received a CONFLUX_LINKED cell on a circuit that is already "
1956 "linked. Closing circuit.");
1962 "Got a CONFLUX_LINKED from wrong hop on circuit. Closing circuit.");
1969 link = conflux_cell_parse_link(msg);
1974 log_info(
LD_CIRC,
"Processing a CONFLUX_LINKED for set %s",
1980 sizeof(link->nonce))) {
1982 "Received CONFLUX_LINKED but circuit nonce doesn't match "
1983 "cell nonce. Closing circuit.");
1990 log_warn(
LD_CIRC,
"Received CONFLUX_LINKED but can't find "
1991 "associated leg. Closing circuit.");
1995 log_info(
LD_CIRC,
"Successfully processed a CONFLUX_LINKED cell.");
2013 case ERR_LINK_CIRC_OK:
2016 case ERR_LINK_CIRC_INVALID_LEG:
2017 case ERR_LINK_CIRC_MISSING_SET:
2021 case ERR_LINK_CIRC_BAD_RTT:
2022 case ERR_LINK_CIRC_MISSING_LEG:
2046 circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL);
2058 if (!conflux_is_enabled(circ)) {
2064 "Received CONFLUX_LINKED_ACK cell on an origin circuit. Closing.");
2070 "Got a CONFLUX_LINKED_ACK with further hops. Closing circuit.");
2076 "Received a CONFLUX_LINKED_ACK cell on a circuit that is not"
2077 "linked. Closing circuit.");
2081 log_info(
LD_CIRC,
"Processing a CONFLUX_LINKED_ACK for set %s",
2092 circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL);
2153 "Conflux %s: %d linked, %d launched. Delivered: %"PRIu64
"; "
2154 "teardown: %d; Current: %p, Previous: %p",
2165 " - Linked Leg %d purpose=%d; RTT %"PRIu64
", sent: %"PRIu64
2166 "; sent: %"PRIu64
", recv: %"PRIu64
", infl: %"PRIu64
", "
2167 "ptr: %p, idx: %d, marked: %d",
2168 legs, leg->circ->purpose, leg->circ_rtts_usec,
2169 leg->linked_sent_usec, leg->last_seq_recv,
2170 leg->last_seq_sent, cc->
inflight, leg->circ,
2171 leg->circ->global_circuitlist_idx,
2172 leg->circ->marked_for_close);
2174 } CONFLUX_FOR_EACH_LEG_END(leg);
2180 log_fn(loglevel,
LD_BUG,
" - Unlinked set: %d legs, for link: %d",
2181 smartlist_len(unlinked->legs), unlinked->is_for_linked_set);
2185 " Unlinked Leg: %d purpose=%d; linked: %d, RTT %"PRIu64
", "
2186 "sent: %"PRIu64
" link ptr %p, circ ptr: %p, idx: %d, marked: %d",
2187 legs, leg->circ->purpose, leg->linked,
2188 leg->rtt_usec, leg->link_sent_usec,
2189 leg->link, leg->circ,
2190 leg->circ->global_circuitlist_idx,
2191 leg->circ->marked_for_close);
2193 } SMARTLIST_FOREACH_END(leg);
2207 shutting_down =
true;
2210#ifdef TOR_UNIT_TESTS
2215conflux_clear_shutdown(
void)
2217 shutting_down =
false;
const char * hex_str(const char *from, size_t fromlen)
bool conflux_can_exclude_used_bridges(void)
Header file for circuitbuild.c.
origin_circuit_t * circuit_establish_circuit_conflux(const uint8_t *conflux_nonce, uint8_t purpose, extend_info_t *exit_ei, int flags)
Header file for circuitbuild.c.
origin_circuit_t * TO_ORIGIN_CIRCUIT(circuit_t *x)
or_circuit_t * TO_OR_CIRCUIT(circuit_t *x)
Header file for circuitlist.c.
#define CIRCUIT_IS_ORCIRC(c)
#define CIRCUIT_IS_ORIGIN(c)
#define CIRCUIT_PURPOSE_CONFLUX_UNLINKED
double get_circuit_build_timeout_ms(void)
Header file for circuitstats.c.
void circuit_read_valid_data(origin_circuit_t *circ, uint16_t relay_body_len)
void circuit_change_purpose(circuit_t *circ, uint8_t new_purpose)
int circuit_is_acceptable(const origin_circuit_t *origin_circ, const entry_connection_t *conn, int must_be_open, uint8_t purpose, int need_uptime, int need_internal, time_t now)
Header file for circuituse.c.
#define CIRCLAUNCH_NEED_CAPACITY
#define CIRCLAUNCH_NEED_UPTIME
#define CIRCLAUNCH_NEED_CONFLUX
uint64_t monotime_absolute_usec(void)
const or_options_t * get_options(void)
Header file for config.c.
const congestion_control_t * circuit_ccontrol(const circuit_t *circ)
uint64_t conflux_get_max_seq_recv(const conflux_t *cfx)
uint64_t conflux_get_max_seq_sent(const conflux_t *cfx)
void conflux_clear_ooo_q(conflux_t *cfx)
conflux_leg_t * conflux_get_leg(conflux_t *cfx, const circuit_t *circ)
Public APIs for conflux multipath support.
#define CONFLUX_FOR_EACH_LEG_BEGIN(cfx, var)
#define CONFLUX_NUM_LEGS(cfx)
Header file for conflux_cell.c.
Header file for conflux_params.c.
static void unlinked_pool_del(unlinked_circuits_t *unlinked, bool is_client)
static const char * fmt_nonce(const uint8_t *nonce)
static link_circ_err_t link_circuit(circuit_t *circ)
static unlinked_circuits_t * unlinked_pool_get(const uint8_t *nonce, bool is_client)
static leg_t * leg_find(const unlinked_circuits_t *unlinked, const circuit_t *circ)
static void linked_circuit_closed(circuit_t *circ)
void conflux_circuit_has_opened(origin_circuit_t *orig_circ)
void conflux_process_linked_ack(circuit_t *circ)
static void unlinked_close_all_legs(unlinked_circuits_t *unlinked)
static void leg_free(leg_t *leg)
#define conflux_free(cfx)
static bool cfx_del_leg(conflux_t *cfx, const circuit_t *circ)
void conflux_log_set(int loglevel, const conflux_t *cfx, bool is_client)
void conflux_circuit_has_closed(circuit_t *circ)
static void linked_circuit_free(circuit_t *circ, bool is_client)
static void free_conflux_void_(void *ptr)
static void cfx_add_leg(conflux_t *cfx, leg_t *leg)
static extend_info_t * get_exit_for_nonce(const uint8_t *nonce)
static uint64_t record_rtt_client(const circuit_t *circ)
STATIC bool launch_new_set(int num_legs)
static bool validate_unlinked_legs(unlinked_circuits_t *unlinked)
static bool record_rtt(const circuit_t *circ, bool is_client)
static leg_t * leg_new(circuit_t *circ, conflux_cell_link_t *link)
void conflux_predict_new(time_t now)
static void linked_nullify_streams(circuit_t *circ)
static bool launch_leg_is_allowed(const conflux_t *cfx)
static digest256map_t * server_unlinked_pool
void conflux_notify_shutdown(void)
static uint8_t conflux_choose_algorithm(uint8_t desired_ux)
static void linked_pool_del(const uint8_t *nonce, bool is_client)
static link_circ_err_t try_finalize_set(unlinked_circuits_t *unlinked)
static void unlinked_pool_add(unlinked_circuits_t *unlinked, bool is_client)
static digest256map_t * client_linked_pool
static void linked_update_stream_backpointers(circuit_t *circ)
static void unlinked_pool_del_and_free(unlinked_circuits_t *unlinked, bool is_client)
void conflux_pool_init(void)
static void unlinked_circuit_free(circuit_t *circ, bool is_client)
static conflux_t * linked_pool_get(const uint8_t *nonce, bool is_client)
void conflux_add_middles_to_exclude_list(const origin_circuit_t *orig_circ, smartlist_t *excluded)
static void unlinked_close_or_free(unlinked_circuits_t *unlinked)
void conflux_circuit_about_to_free(circuit_t *circ)
static unlinked_circuits_t * unlinked_new(const uint8_t *nonce, bool is_client)
static uint64_t record_rtt_exit(const circuit_t *circ)
static void free_unlinked_void_(void *ptr)
static digest256map_t * client_unlinked_pool
static digest256map_t * server_linked_pool
static void linked_pool_add(conflux_t *cfx, bool is_client)
bool conflux_launch_leg(const uint8_t *nonce)
static void unlinked_leg_add(unlinked_circuits_t *unlinked, leg_t *leg)
static int count_client_usable_sets(void)
void conflux_mark_all_for_close(const uint8_t *nonce, bool is_client, int reason)
static void unlinked_free(unlinked_circuits_t *unlinked)
void conflux_pool_free_all(void)
void conflux_add_guards_to_exclude_list(const origin_circuit_t *orig_circ, smartlist_t *excluded)
static conflux_t * conflux_new(void)
static void validate_circ_has_no_streams(circuit_t *circ)
static uint8_t get_client_ux(void)
void conflux_process_link(circuit_t *circ, const relay_msg_t *msg)
void conflux_process_linked(circuit_t *circ, crypt_path_t *layer_hint, const relay_msg_t *msg)
static void unlinked_circuit_closed(circuit_t *circ)
origin_circuit_t * conflux_get_circ_for_conn(const entry_connection_t *conn, time_t now, int need_internal)
static leg_t * unlinked_leg_find(const circuit_t *circ, bool is_client)
Header file for conflux_pool.c.
Structure definitions for conflux multipath.
void conflux_validate_stream_lists(const conflux_t *cfx)
bool conflux_validate_source_hop(circuit_t *in_circ, crypt_path_t *layer_hint)
void conflux_sync_circ_fields(conflux_t *cfx, origin_circuit_t *ref_circ)
Header file for conflux_util.c.
Structure definitions for congestion control.
void connection_ap_attach_pending(int retry)
Header file for connection_edge.c.
Path structures for origin circuits.
void crypto_rand(char *to, size_t n)
Common functions for using (pseudo-)random number generators.
void memwipe(void *mem, uint8_t byte, size_t sz)
Common functions for cryptographic routines.
int tor_memeq(const void *a, const void *b, size_t sz)
#define tor_memneq(a, b, sz)
Edge-connection structure.
#define log_fn(severity, domain, args,...)
#define log_fn_ratelim(ratelim, severity, domain, args,...)
consensus_path_type_t router_have_consensus_path(void)
node_t * node_get_mutable_by_id(const char *identity_digest)
Header file for nodelist.c.
Master header file for Tor-specific functionality.
Origin circuit structure.
bool have_been_under_memory_pressure(void)
smartlist_t * smartlist_new(void)
void smartlist_add(smartlist_t *sl, void *element)
void smartlist_remove(smartlist_t *sl, const void *element)
#define SMARTLIST_FOREACH_BEGIN(sl, type, var)
#define SMARTLIST_FOREACH(sl, type, var, cmd)
#define SMARTLIST_DEL_CURRENT(sl, var)
uint16_t marked_for_close
struct conflux_t * conflux
uint8_t * conflux_pending_nonce
uint64_t linked_sent_usec
struct conflux_leg_t * curr_leg
struct conflux_params_t params
struct conflux_leg_t * prev_leg
uint8_t nonce[DIGEST256_LEN]
uint64_t last_seq_delivered
unsigned int num_leg_launch
struct crypt_path_t * prev
struct crypt_path_t * next
extend_info_t * extend_info
struct edge_connection_t * next_stream
char identity_digest[DIGEST_LEN]
edge_connection_t * resolving_streams
edge_connection_t * n_streams
uint32_t global_identifier
edge_connection_t * p_streams
unsigned int isolation_values_set
smartlist_t * half_streams
#define tor_assert_nonfatal_unreached()