|
@@ -1022,8 +1022,95 @@ circuit_stream_is_being_handled(entry_connection_t *conn,
|
|
|
/** Don't keep more than this many unused open circuits around. */
|
|
|
#define MAX_UNUSED_OPEN_CIRCUITS 14
|
|
|
|
|
|
-/** Figure out how many circuits we have open that are clean. Make
|
|
|
- * sure it's enough for all the upcoming behaviors we predict we'll have.
|
|
|
+/* Return true if a circuit is available for use, meaning that it is open,
|
|
|
+ * clean, usable for new multi-hop connections, and a general purpose origin
|
|
|
+ * circuit.
|
|
|
+ * Accept any kind of circuit, return false if the above conditions are not
|
|
|
+ * met. */
|
|
|
+STATIC int
|
|
|
+circuit_is_available_for_use(const circuit_t *circ)
|
|
|
+{
|
|
|
+ const origin_circuit_t *origin_circ;
|
|
|
+ cpath_build_state_t *build_state;
|
|
|
+
|
|
|
+ if (!CIRCUIT_IS_ORIGIN(circ))
|
|
|
+ return 0;
|
|
|
+ if (circ->marked_for_close)
|
|
|
+ return 0; /* Don't mess with marked circs */
|
|
|
+ if (circ->timestamp_dirty)
|
|
|
+ return 0; /* Only count clean circs */
|
|
|
+ if (circ->purpose != CIRCUIT_PURPOSE_C_GENERAL)
|
|
|
+ return 0;/* Only pay attention to general
|
|
|
+ purpose circs */
|
|
|
+
|
|
|
+ origin_circ = CONST_TO_ORIGIN_CIRCUIT(circ);
|
|
|
+ if (origin_circ->unusable_for_new_conns)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ build_state = origin_circ->build_state;
|
|
|
+ if (build_state->onehop_tunnel)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+
|
|
|
+/* Return true if we need any more exit circuits.
|
|
|
+ * needs_uptime and needs_capacity are set only if we need more exit circuits.
|
|
|
+ * Check if we know of a port that's been requested recently and no circuit
|
|
|
+ * is currently available that can handle it. */
|
|
|
+STATIC int
|
|
|
+needs_exit_circuits(time_t now, int *needs_uptime, int *needs_capacity)
|
|
|
+{
|
|
|
+ return (!circuit_all_predicted_ports_handled(now, needs_uptime,
|
|
|
+ needs_capacity) &&
|
|
|
+ router_have_consensus_path() == CONSENSUS_PATH_EXIT);
|
|
|
+}
|
|
|
+
|
|
|
+/* Return true if we need any more hidden service server circuits.
|
|
|
+ * HS servers only need an internal circuit. */
|
|
|
+STATIC int
|
|
|
+needs_hs_server_circuits(int num_uptime_internal)
|
|
|
+{
|
|
|
+ return (num_rend_services() && num_uptime_internal < 3 &&
|
|
|
+ router_have_consensus_path() != CONSENSUS_PATH_UNKNOWN);
|
|
|
+}
|
|
|
+
|
|
|
+/* Return true if we need any more hidden service client circuits.
|
|
|
+ * HS clients only need an internal circuit. */
|
|
|
+STATIC int
|
|
|
+needs_hs_client_circuits(time_t now, int *needs_uptime, int *needs_capacity,
|
|
|
+ int num_internal, int num_uptime_internal)
|
|
|
+{
|
|
|
+ int used_internal_recently = rep_hist_get_predicted_internal(now,
|
|
|
+ needs_uptime,
|
|
|
+ needs_capacity);
|
|
|
+ return (used_internal_recently &&
|
|
|
+ ((num_uptime_internal<2 && needs_uptime) || num_internal<3) &&
|
|
|
+ router_have_consensus_path() != CONSENSUS_PATH_UNKNOWN);
|
|
|
+}
|
|
|
+
|
|
|
+/* Check to see if we still need more circuits to learn
|
|
|
+ * a good build timeout. But if we're close to our max number we
|
|
|
+ * want, don't do another -- we want to leave a few slots open so
|
|
|
+ * we can still build circuits preemptively as needed.
|
|
|
+ * XXXX make the assumption that build timeout streams should be
|
|
|
+ * created whenever we can build internal circuits. */
|
|
|
+STATIC int
|
|
|
+needs_circuits_for_build(int num)
|
|
|
+{
|
|
|
+ if (router_have_consensus_path() != CONSENSUS_PATH_UNKNOWN) {
|
|
|
+ if (num < MAX_UNUSED_OPEN_CIRCUITS-2 &&
|
|
|
+ ! circuit_build_times_disabled() &&
|
|
|
+ circuit_build_times_needs_circuits_now(get_circuit_build_times()))
|
|
|
+ {
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/** Determine how many circuits we have open that are clean,
|
|
|
+ * Make sure it's enough for all the upcoming behaviors we predict we'll have.
|
|
|
* But put an upper bound on the total number of circuits.
|
|
|
*/
|
|
|
static void
|
|
@@ -1035,25 +1122,14 @@ circuit_predict_and_launch_new(void)
|
|
|
time_t now = time(NULL);
|
|
|
int flags = 0;
|
|
|
|
|
|
- /* First, count how many of each type of circuit we have already. */
|
|
|
+ /* Count how many of each type of circuit we currently have. */
|
|
|
SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
|
|
|
- cpath_build_state_t *build_state;
|
|
|
- origin_circuit_t *origin_circ;
|
|
|
- if (!CIRCUIT_IS_ORIGIN(circ))
|
|
|
- continue;
|
|
|
- if (circ->marked_for_close)
|
|
|
- continue; /* don't mess with marked circs */
|
|
|
- if (circ->timestamp_dirty)
|
|
|
- continue; /* only count clean circs */
|
|
|
- if (circ->purpose != CIRCUIT_PURPOSE_C_GENERAL)
|
|
|
- continue; /* only pay attention to general-purpose circs */
|
|
|
- origin_circ = TO_ORIGIN_CIRCUIT(circ);
|
|
|
- if (origin_circ->unusable_for_new_conns)
|
|
|
- continue;
|
|
|
- build_state = origin_circ->build_state;
|
|
|
- if (build_state->onehop_tunnel)
|
|
|
+ if (!circuit_is_available_for_use(circ))
|
|
|
continue;
|
|
|
+
|
|
|
num++;
|
|
|
+
|
|
|
+ cpath_build_state_t *build_state = TO_ORIGIN_CIRCUIT(circ)->build_state;
|
|
|
if (build_state->is_internal)
|
|
|
num_internal++;
|
|
|
if (build_state->need_uptime && build_state->is_internal)
|
|
@@ -1063,19 +1139,14 @@ circuit_predict_and_launch_new(void)
|
|
|
|
|
|
/* If that's enough, then stop now. */
|
|
|
if (num >= MAX_UNUSED_OPEN_CIRCUITS)
|
|
|
- return; /* we already have many, making more probably will hurt */
|
|
|
-
|
|
|
- /* Second, see if we need any more exit circuits. */
|
|
|
- /* check if we know of a port that's been requested recently
|
|
|
- * and no circuit is currently available that can handle it.
|
|
|
- * Exits (obviously) require an exit circuit. */
|
|
|
- if (!circuit_all_predicted_ports_handled(now, &port_needs_uptime,
|
|
|
- &port_needs_capacity)
|
|
|
- && router_have_consensus_path() == CONSENSUS_PATH_EXIT) {
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (needs_exit_circuits(now, &port_needs_uptime, &port_needs_capacity)) {
|
|
|
if (port_needs_uptime)
|
|
|
flags |= CIRCLAUNCH_NEED_UPTIME;
|
|
|
if (port_needs_capacity)
|
|
|
flags |= CIRCLAUNCH_NEED_CAPACITY;
|
|
|
+
|
|
|
log_info(LD_CIRC,
|
|
|
"Have %d clean circs (%d internal), need another exit circ.",
|
|
|
num, num_internal);
|
|
@@ -1083,12 +1154,10 @@ circuit_predict_and_launch_new(void)
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- /* Third, see if we need any more hidden service (server) circuits.
|
|
|
- * HS servers only need an internal circuit. */
|
|
|
- if (num_rend_services() && num_uptime_internal < 3
|
|
|
- && router_have_consensus_path() != CONSENSUS_PATH_UNKNOWN) {
|
|
|
+ if (needs_hs_server_circuits(num_uptime_internal)) {
|
|
|
flags = (CIRCLAUNCH_NEED_CAPACITY | CIRCLAUNCH_NEED_UPTIME |
|
|
|
CIRCLAUNCH_IS_INTERNAL);
|
|
|
+
|
|
|
log_info(LD_CIRC,
|
|
|
"Have %d clean circs (%d internal), need another internal "
|
|
|
"circ for my hidden service.",
|
|
@@ -1097,18 +1166,16 @@ circuit_predict_and_launch_new(void)
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- /* Fourth, see if we need any more hidden service (client) circuits.
|
|
|
- * HS clients only need an internal circuit. */
|
|
|
- if (rep_hist_get_predicted_internal(now, &hidserv_needs_uptime,
|
|
|
- &hidserv_needs_capacity) &&
|
|
|
- ((num_uptime_internal<2 && hidserv_needs_uptime) ||
|
|
|
- num_internal<3)
|
|
|
- && router_have_consensus_path() != CONSENSUS_PATH_UNKNOWN) {
|
|
|
+ if (needs_hs_client_circuits(now, &hidserv_needs_uptime,
|
|
|
+ &hidserv_needs_capacity,
|
|
|
+ num_internal, num_uptime_internal))
|
|
|
+ {
|
|
|
if (hidserv_needs_uptime)
|
|
|
flags |= CIRCLAUNCH_NEED_UPTIME;
|
|
|
if (hidserv_needs_capacity)
|
|
|
flags |= CIRCLAUNCH_NEED_CAPACITY;
|
|
|
flags |= CIRCLAUNCH_IS_INTERNAL;
|
|
|
+
|
|
|
log_info(LD_CIRC,
|
|
|
"Have %d clean circs (%d uptime-internal, %d internal), need"
|
|
|
" another hidden service circ.",
|
|
@@ -1117,26 +1184,17 @@ circuit_predict_and_launch_new(void)
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- /* Finally, check to see if we still need more circuits to learn
|
|
|
- * a good build timeout. But if we're close to our max number we
|
|
|
- * want, don't do another -- we want to leave a few slots open so
|
|
|
- * we can still build circuits preemptively as needed.
|
|
|
- * XXXX make the assumption that build timeout streams should be
|
|
|
- * created whenever we can build internal circuits. */
|
|
|
- if (router_have_consensus_path() != CONSENSUS_PATH_UNKNOWN) {
|
|
|
- if (num < MAX_UNUSED_OPEN_CIRCUITS-2 &&
|
|
|
- ! circuit_build_times_disabled() &&
|
|
|
- circuit_build_times_needs_circuits_now(get_circuit_build_times())) {
|
|
|
- flags = CIRCLAUNCH_NEED_CAPACITY;
|
|
|
- /* if there are no exits in the consensus, make timeout
|
|
|
- * circuits internal */
|
|
|
- if (router_have_consensus_path() == CONSENSUS_PATH_INTERNAL)
|
|
|
- flags |= CIRCLAUNCH_IS_INTERNAL;
|
|
|
+ if (needs_circuits_for_build(num)) {
|
|
|
+ flags = CIRCLAUNCH_NEED_CAPACITY;
|
|
|
+ /* if there are no exits in the consensus, make timeout
|
|
|
+ * circuits internal */
|
|
|
+ if (router_have_consensus_path() == CONSENSUS_PATH_INTERNAL)
|
|
|
+ flags |= CIRCLAUNCH_IS_INTERNAL;
|
|
|
+
|
|
|
log_info(LD_CIRC,
|
|
|
"Have %d clean circs need another buildtime test circ.", num);
|
|
|
circuit_launch(CIRCUIT_PURPOSE_C_GENERAL, flags);
|
|
|
return;
|
|
|
- }
|
|
|
}
|
|
|
}
|
|
|
|