| 
					
				 | 
			
			
				@@ -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; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -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); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -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 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -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. */ 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -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; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -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 " 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -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; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -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 */ 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -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; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -204,8 +222,11 @@ void 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 clear_pending_onions(void) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   onion_queue_t *victim; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  while ((victim = TOR_TAILQ_FIRST(&ol_list))) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    onion_queue_entry_remove(victim); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  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)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 |