|
@@ -250,7 +250,106 @@ circuit_t *circuit_get_by_conn(connection_t *conn) {
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
+
|
|
|
+ */
|
|
|
+static int circuit_is_acceptable(circuit_t *circ,
|
|
|
+ connection_t *conn,
|
|
|
+ int must_be_open,
|
|
|
+ uint8_t purpose,
|
|
|
+ time_t now)
|
|
|
+{
|
|
|
+ routerinfo_t *exitrouter;
|
|
|
+
|
|
|
+ if (!circ->cpath)
|
|
|
+ return 0;
|
|
|
+ if (must_be_open && (circ->state != CIRCUIT_STATE_OPEN || !circ->n_conn))
|
|
|
+ return 0;
|
|
|
+ if (circ->marked_for_close)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+
|
|
|
+ if(purpose == CIRCUIT_PURPOSE_C_REND_JOINED && !must_be_open) {
|
|
|
+ if(circ->purpose != CIRCUIT_PURPOSE_C_ESTABLISH_REND &&
|
|
|
+ circ->purpose != CIRCUIT_PURPOSE_C_REND_READY &&
|
|
|
+ circ->purpose != CIRCUIT_PURPOSE_C_REND_JOINED)
|
|
|
+ return 0;
|
|
|
+ } else {
|
|
|
+ if(purpose != circ->purpose)
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(purpose == CIRCUIT_PURPOSE_C_GENERAL)
|
|
|
+ if(circ->timestamp_dirty &&
|
|
|
+ circ->timestamp_dirty+options.NewCircuitPeriod < now)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ if(conn) {
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ * circuit, it's the magical extra bob hop. so just check the nickname
|
|
|
+ * of the one we meant to finish at.
|
|
|
+ */
|
|
|
+ exitrouter = router_get_by_nickname(circ->build_state->chosen_exit);
|
|
|
+
|
|
|
+ if(!exitrouter) {
|
|
|
+ log_fn(LOG_INFO,"Skipping broken circ (exit router vanished)");
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(purpose == CIRCUIT_PURPOSE_C_GENERAL) {
|
|
|
+ if(connection_ap_can_use_exit(conn, exitrouter) == ADDR_POLICY_REJECTED) {
|
|
|
+
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if(rend_cmp_service_ids(conn->rend_query, circ->rend_query)) {
|
|
|
+
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+ * circuit_get_best
|
|
|
+ */
|
|
|
+static int circuit_is_better(circuit_t *a, circuit_t *b, uint8_t purpose)
|
|
|
+{
|
|
|
+ switch(purpose) {
|
|
|
+ case CIRCUIT_PURPOSE_C_GENERAL:
|
|
|
+
|
|
|
+ * else if it's more recently created it's best
|
|
|
+ */
|
|
|
+ if(b->timestamp_dirty) {
|
|
|
+ if(a->timestamp_dirty &&
|
|
|
+ a->timestamp_dirty > b->timestamp_dirty)
|
|
|
+ return 1;
|
|
|
+ } else {
|
|
|
+ if(a->timestamp_dirty ||
|
|
|
+ a->timestamp_created > b->timestamp_created)
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case CIRCUIT_PURPOSE_C_INTRODUCING:
|
|
|
+
|
|
|
+ if(a->timestamp_created > b->timestamp_created)
|
|
|
+ return 1;
|
|
|
+ break;
|
|
|
+ case CIRCUIT_PURPOSE_C_REND_JOINED:
|
|
|
+
|
|
|
+ if(a->purpose > b->purpose)
|
|
|
+ return 1;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
|
|
|
* dirty. Circ must not be too old.
|
|
|
* If !conn, return newest.
|
|
@@ -268,7 +367,6 @@ circuit_t *circuit_get_by_conn(connection_t *conn) {
|
|
|
circuit_t *circuit_get_best(connection_t *conn,
|
|
|
int must_be_open, uint8_t purpose) {
|
|
|
circuit_t *circ, *best=NULL;
|
|
|
- routerinfo_t *exitrouter;
|
|
|
time_t now = time(NULL);
|
|
|
|
|
|
assert(purpose == CIRCUIT_PURPOSE_C_GENERAL ||
|
|
@@ -276,93 +374,14 @@ circuit_t *circuit_get_best(connection_t *conn,
|
|
|
purpose == CIRCUIT_PURPOSE_C_REND_JOINED);
|
|
|
|
|
|
for (circ=global_circuitlist;circ;circ = circ->next) {
|
|
|
- if (!circ->cpath)
|
|
|
- continue;
|
|
|
- if (must_be_open && (circ->state != CIRCUIT_STATE_OPEN || !circ->n_conn))
|
|
|
- continue;
|
|
|
- if (circ->marked_for_close)
|
|
|
+ if (!circuit_is_acceptable(circ,conn,must_be_open,purpose,now))
|
|
|
continue;
|
|
|
|
|
|
-
|
|
|
- if(purpose == CIRCUIT_PURPOSE_C_REND_JOINED) {
|
|
|
- if(must_be_open && purpose != circ->purpose)
|
|
|
- continue;
|
|
|
- if(circ->purpose != CIRCUIT_PURPOSE_C_ESTABLISH_REND &&
|
|
|
- circ->purpose != CIRCUIT_PURPOSE_C_REND_READY &&
|
|
|
- circ->purpose != CIRCUIT_PURPOSE_C_REND_JOINED)
|
|
|
- continue;
|
|
|
- } else {
|
|
|
- if(purpose != circ->purpose)
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- if(purpose == CIRCUIT_PURPOSE_C_GENERAL)
|
|
|
- if(circ->timestamp_dirty &&
|
|
|
- circ->timestamp_dirty+options.NewCircuitPeriod < now)
|
|
|
- continue;
|
|
|
-
|
|
|
- if(conn) {
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- * circuit, it's the magical extra bob hop. so just check the nickname
|
|
|
- * of the one we meant to finish at.
|
|
|
- */
|
|
|
- exitrouter = router_get_by_nickname(circ->build_state->chosen_exit);
|
|
|
-
|
|
|
- if(!exitrouter) {
|
|
|
- log_fn(LOG_INFO,"Skipping broken circ (exit router vanished)");
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- if(purpose == CIRCUIT_PURPOSE_C_GENERAL) {
|
|
|
- if(connection_ap_can_use_exit(conn, exitrouter) == ADDR_POLICY_REJECTED) {
|
|
|
-
|
|
|
- continue;
|
|
|
- }
|
|
|
- } else {
|
|
|
- if(rend_cmp_service_ids(conn->rend_query, circ->rend_query)) {
|
|
|
-
|
|
|
- continue;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
|
|
|
* mean it's the *best* circ to hand back. try to decide.
|
|
|
*/
|
|
|
- if(!best)
|
|
|
+ if(!best || circuit_is_better(circ,best,purpose))
|
|
|
best = circ;
|
|
|
- switch(purpose) {
|
|
|
- case CIRCUIT_PURPOSE_C_GENERAL:
|
|
|
-
|
|
|
- * else if it's more recently created it's best
|
|
|
- */
|
|
|
- if(best->timestamp_dirty) {
|
|
|
- if(circ->timestamp_dirty &&
|
|
|
- circ->timestamp_dirty > best->timestamp_dirty)
|
|
|
- best = circ;
|
|
|
- } else {
|
|
|
- if(circ->timestamp_dirty ||
|
|
|
- circ->timestamp_created > best->timestamp_created)
|
|
|
- best = circ;
|
|
|
- }
|
|
|
- break;
|
|
|
- case CIRCUIT_PURPOSE_C_INTRODUCING:
|
|
|
-
|
|
|
- if(circ->timestamp_created > best->timestamp_created)
|
|
|
- best = circ;
|
|
|
- break;
|
|
|
- case CIRCUIT_PURPOSE_C_REND_JOINED:
|
|
|
-
|
|
|
- if(circ->purpose > best->purpose)
|
|
|
- best = circ;
|
|
|
- break;
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
return best;
|