Loading src/or/onion.c +37 −16 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ typedef struct onion_queue_t { TOR_TAILQ_ENTRY(onion_queue_t) next; or_circuit_t *circ; uint16_t handshake_type; create_cell_t *onionskin; time_t when_added; } onion_queue_t; Loading @@ -35,11 +36,16 @@ typedef struct onion_queue_t { /** 5 seconds on the onion queue til we just send back a destroy */ #define ONIONQUEUE_WAIT_CUTOFF 5 /** Queue of circuits waiting for CPU workers, or NULL if the list is empty.*/ TOR_TAILQ_HEAD(onion_queue_head_t, onion_queue_t) ol_list = TOR_TAILQ_HEAD_INITIALIZER(ol_list); /** Array of queues of circuits waiting for CPU workers. An element is NULL * if that queue is empty.*/ TOR_TAILQ_HEAD(onion_queue_head_t, onion_queue_t) ol_list[MAX_ONION_HANDSHAKE_TYPE+1] = { TOR_TAILQ_HEAD_INITIALIZER(ol_list[0]), /* tap */ TOR_TAILQ_HEAD_INITIALIZER(ol_list[1]), /* fast */ TOR_TAILQ_HEAD_INITIALIZER(ol_list[2]), /* ntor */ }; /** Number of entries of each type currently in ol_list. */ /** Number of entries of each type currently in each element of ol_list[]. */ static int ol_entries[MAX_ONION_HANDSHAKE_TYPE+1]; static void onion_queue_entry_remove(onion_queue_t *victim); Loading @@ -60,8 +66,7 @@ have_room_for_onionskin(uint16_t type) int num_cpus; uint64_t tap_usec, ntor_usec; /* If we've got fewer than 50 entries, we always have room for one more. */ if (ol_entries[ONION_HANDSHAKE_TYPE_TAP] + ol_entries[ONION_HANDSHAKE_TYPE_NTOR] < 50) if (ol_entries[type] < 50) return 1; num_cpus = get_num_cpus(options); /* Compute how many microseconds we'd expect to need to clear all Loading @@ -72,10 +77,17 @@ have_room_for_onionskin(uint16_t type) ntor_usec = estimated_usec_for_onionskins( ol_entries[ONION_HANDSHAKE_TYPE_NTOR], ONION_HANDSHAKE_TYPE_NTOR) / num_cpus; /* See whether that exceeds MaxOnionQueueDelay. If so, we can't queue * this. */ if ((tap_usec + ntor_usec) / 1000 > (uint64_t)options->MaxOnionQueueDelay) if (type == ONION_HANDSHAKE_TYPE_NTOR && ntor_usec / 1000 > (uint64_t)options->MaxOnionQueueDelay) return 0; if (type == ONION_HANDSHAKE_TYPE_TAP && (tap_usec + ntor_usec) / 1000 > (uint64_t)options->MaxOnionQueueDelay) return 0; #ifdef CURVE25519_ENABLED /* If we support the ntor handshake, then don't let TAP handshakes use * more than 2/3 of the space on the queue. */ Loading @@ -100,6 +112,7 @@ onion_pending_add(or_circuit_t *circ, create_cell_t *onionskin) tmp = tor_malloc_zero(sizeof(onion_queue_t)); tmp->circ = circ; tmp->handshake_type = onionskin->handshake_type; tmp->onionskin = onionskin; tmp->when_added = now; Loading @@ -108,7 +121,8 @@ onion_pending_add(or_circuit_t *circ, create_cell_t *onionskin) static ratelim_t last_warned = RATELIM_INIT(WARN_TOO_MANY_CIRC_CREATIONS_INTERVAL); char *m; if ((m = rate_limit_log(&last_warned, approx_time()))) { if (onionskin->handshake_type == ONION_HANDSHAKE_TYPE_NTOR && (m = rate_limit_log(&last_warned, approx_time()))) { log_warn(LD_GENERAL, "Your computer is too slow to handle this many circuit " "creation requests! Please consider using the " Loading @@ -122,11 +136,11 @@ onion_pending_add(or_circuit_t *circ, create_cell_t *onionskin) ++ol_entries[onionskin->handshake_type]; circ->onionqueue_entry = tmp; TOR_TAILQ_INSERT_TAIL(&ol_list, tmp, next); TOR_TAILQ_INSERT_TAIL(&ol_list[onionskin->handshake_type], tmp, next); /* cull elderly requests. */ while (1) { onion_queue_t *head = TOR_TAILQ_FIRST(&ol_list); onion_queue_t *head = TOR_TAILQ_FIRST(&ol_list[onionskin->handshake_type]); if (now - head->when_added < (time_t)ONIONQUEUE_WAIT_CUTOFF) break; Loading @@ -140,14 +154,18 @@ onion_pending_add(or_circuit_t *circ, create_cell_t *onionskin) return 0; } /** Remove the first item from ol_list and return it, or return * NULL if the list is empty. /** Remove the highest priority item from ol_list[] and return it, or * return NULL if the lists are empty. */ or_circuit_t * onion_next_task(create_cell_t **onionskin_out) { or_circuit_t *circ; onion_queue_t *head = TOR_TAILQ_FIRST(&ol_list); /* skip ol_list[ONION_HANDSHAKE_TYPE_FAST] since we know it'll be empty */ onion_queue_t *head = TOR_TAILQ_FIRST(&ol_list[ONION_HANDSHAKE_TYPE_NTOR]); if (!head) head = TOR_TAILQ_FIRST(&ol_list[ONION_HANDSHAKE_TYPE_TAP]); if (!head) return NULL; /* no onions pending, we're done */ Loading Loading @@ -186,7 +204,7 @@ onion_pending_remove(or_circuit_t *circ) static void onion_queue_entry_remove(onion_queue_t *victim) { TOR_TAILQ_REMOVE(&ol_list, victim, next); TOR_TAILQ_REMOVE(&ol_list[victim->handshake_type], victim, next); if (victim->circ) victim->circ->onionqueue_entry = NULL; Loading @@ -204,9 +222,12 @@ void clear_pending_onions(void) { onion_queue_t *victim; while ((victim = TOR_TAILQ_FIRST(&ol_list))) { int i; for (i=0; i<=MAX_ONION_HANDSHAKE_TYPE; i++) { while ((victim = TOR_TAILQ_FIRST(&ol_list[i]))) { onion_queue_entry_remove(victim); } } memset(ol_entries, 0, sizeof(ol_entries)); } Loading Loading
src/or/onion.c +37 −16 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ typedef struct onion_queue_t { TOR_TAILQ_ENTRY(onion_queue_t) next; or_circuit_t *circ; uint16_t handshake_type; create_cell_t *onionskin; time_t when_added; } onion_queue_t; Loading @@ -35,11 +36,16 @@ typedef struct onion_queue_t { /** 5 seconds on the onion queue til we just send back a destroy */ #define ONIONQUEUE_WAIT_CUTOFF 5 /** Queue of circuits waiting for CPU workers, or NULL if the list is empty.*/ TOR_TAILQ_HEAD(onion_queue_head_t, onion_queue_t) ol_list = TOR_TAILQ_HEAD_INITIALIZER(ol_list); /** Array of queues of circuits waiting for CPU workers. An element is NULL * if that queue is empty.*/ TOR_TAILQ_HEAD(onion_queue_head_t, onion_queue_t) ol_list[MAX_ONION_HANDSHAKE_TYPE+1] = { TOR_TAILQ_HEAD_INITIALIZER(ol_list[0]), /* tap */ TOR_TAILQ_HEAD_INITIALIZER(ol_list[1]), /* fast */ TOR_TAILQ_HEAD_INITIALIZER(ol_list[2]), /* ntor */ }; /** Number of entries of each type currently in ol_list. */ /** Number of entries of each type currently in each element of ol_list[]. */ static int ol_entries[MAX_ONION_HANDSHAKE_TYPE+1]; static void onion_queue_entry_remove(onion_queue_t *victim); Loading @@ -60,8 +66,7 @@ have_room_for_onionskin(uint16_t type) int num_cpus; uint64_t tap_usec, ntor_usec; /* If we've got fewer than 50 entries, we always have room for one more. */ if (ol_entries[ONION_HANDSHAKE_TYPE_TAP] + ol_entries[ONION_HANDSHAKE_TYPE_NTOR] < 50) if (ol_entries[type] < 50) return 1; num_cpus = get_num_cpus(options); /* Compute how many microseconds we'd expect to need to clear all Loading @@ -72,10 +77,17 @@ have_room_for_onionskin(uint16_t type) ntor_usec = estimated_usec_for_onionskins( ol_entries[ONION_HANDSHAKE_TYPE_NTOR], ONION_HANDSHAKE_TYPE_NTOR) / num_cpus; /* See whether that exceeds MaxOnionQueueDelay. If so, we can't queue * this. */ if ((tap_usec + ntor_usec) / 1000 > (uint64_t)options->MaxOnionQueueDelay) if (type == ONION_HANDSHAKE_TYPE_NTOR && ntor_usec / 1000 > (uint64_t)options->MaxOnionQueueDelay) return 0; if (type == ONION_HANDSHAKE_TYPE_TAP && (tap_usec + ntor_usec) / 1000 > (uint64_t)options->MaxOnionQueueDelay) return 0; #ifdef CURVE25519_ENABLED /* If we support the ntor handshake, then don't let TAP handshakes use * more than 2/3 of the space on the queue. */ Loading @@ -100,6 +112,7 @@ onion_pending_add(or_circuit_t *circ, create_cell_t *onionskin) tmp = tor_malloc_zero(sizeof(onion_queue_t)); tmp->circ = circ; tmp->handshake_type = onionskin->handshake_type; tmp->onionskin = onionskin; tmp->when_added = now; Loading @@ -108,7 +121,8 @@ onion_pending_add(or_circuit_t *circ, create_cell_t *onionskin) static ratelim_t last_warned = RATELIM_INIT(WARN_TOO_MANY_CIRC_CREATIONS_INTERVAL); char *m; if ((m = rate_limit_log(&last_warned, approx_time()))) { if (onionskin->handshake_type == ONION_HANDSHAKE_TYPE_NTOR && (m = rate_limit_log(&last_warned, approx_time()))) { log_warn(LD_GENERAL, "Your computer is too slow to handle this many circuit " "creation requests! Please consider using the " Loading @@ -122,11 +136,11 @@ onion_pending_add(or_circuit_t *circ, create_cell_t *onionskin) ++ol_entries[onionskin->handshake_type]; circ->onionqueue_entry = tmp; TOR_TAILQ_INSERT_TAIL(&ol_list, tmp, next); TOR_TAILQ_INSERT_TAIL(&ol_list[onionskin->handshake_type], tmp, next); /* cull elderly requests. */ while (1) { onion_queue_t *head = TOR_TAILQ_FIRST(&ol_list); onion_queue_t *head = TOR_TAILQ_FIRST(&ol_list[onionskin->handshake_type]); if (now - head->when_added < (time_t)ONIONQUEUE_WAIT_CUTOFF) break; Loading @@ -140,14 +154,18 @@ onion_pending_add(or_circuit_t *circ, create_cell_t *onionskin) return 0; } /** Remove the first item from ol_list and return it, or return * NULL if the list is empty. /** Remove the highest priority item from ol_list[] and return it, or * return NULL if the lists are empty. */ or_circuit_t * onion_next_task(create_cell_t **onionskin_out) { or_circuit_t *circ; onion_queue_t *head = TOR_TAILQ_FIRST(&ol_list); /* skip ol_list[ONION_HANDSHAKE_TYPE_FAST] since we know it'll be empty */ onion_queue_t *head = TOR_TAILQ_FIRST(&ol_list[ONION_HANDSHAKE_TYPE_NTOR]); if (!head) head = TOR_TAILQ_FIRST(&ol_list[ONION_HANDSHAKE_TYPE_TAP]); if (!head) return NULL; /* no onions pending, we're done */ Loading Loading @@ -186,7 +204,7 @@ onion_pending_remove(or_circuit_t *circ) static void onion_queue_entry_remove(onion_queue_t *victim) { TOR_TAILQ_REMOVE(&ol_list, victim, next); TOR_TAILQ_REMOVE(&ol_list[victim->handshake_type], victim, next); if (victim->circ) victim->circ->onionqueue_entry = NULL; Loading @@ -204,9 +222,12 @@ void clear_pending_onions(void) { onion_queue_t *victim; while ((victim = TOR_TAILQ_FIRST(&ol_list))) { int i; for (i=0; i<=MAX_ONION_HANDSHAKE_TYPE; i++) { while ((victim = TOR_TAILQ_FIRST(&ol_list[i]))) { onion_queue_entry_remove(victim); } } memset(ol_entries, 0, sizeof(ol_entries)); } Loading