1 /* Copyright 2001,2002,2003 Roger Dingledine, Matej Pfajfar. */
2 /* See LICENSE for licensing information */
7 extern or_options_t options
; /* command-line and config-file options */
9 unsigned long stats_n_padding_cells_processed
= 0;
10 unsigned long stats_n_create_cells_processed
= 0;
11 unsigned long stats_n_created_cells_processed
= 0;
12 unsigned long stats_n_relay_cells_processed
= 0;
13 unsigned long stats_n_destroy_cells_processed
= 0;
15 static void command_process_create_cell(cell_t
*cell
, connection_t
*conn
);
16 static void command_process_created_cell(cell_t
*cell
, connection_t
*conn
);
17 static void command_process_relay_cell(cell_t
*cell
, connection_t
*conn
);
18 static void command_process_destroy_cell(cell_t
*cell
, connection_t
*conn
);
20 static void command_time_process_cell(cell_t
*cell
, connection_t
*conn
,
22 void (*func
)(cell_t
*, connection_t
*)) {
23 struct timeval start
, end
;
28 tor_gettimeofday(&start
);
32 tor_gettimeofday(&end
);
33 time_passed
= tv_udiff(&start
, &end
) ;
35 if (time_passed
> 10000) { /* more than 10ms */
36 log_fn(LOG_INFO
,"That call just took %ld ms.",time_passed
/1000);
41 void command_process_cell(cell_t
*cell
, connection_t
*conn
) {
42 static int num_create
=0, num_created
=0, num_relay
=0, num_destroy
=0;
43 static int create_time
=0, created_time
=0, relay_time
=0, destroy_time
=0;
44 static time_t current_second
= 0; /* from previous calls to time */
45 time_t now
= time(NULL
);
47 if(now
> current_second
) { /* the second has rolled over */
49 log(LOG_INFO
,"At end of second: %d creates (%d ms), %d createds (%d ms), %d relays (%d ms), %d destroys (%d ms)",
50 num_create
, create_time
/1000,
51 num_created
, created_time
/1000,
52 num_relay
, relay_time
/1000,
53 num_destroy
, destroy_time
/1000);
56 num_create
= num_created
= num_relay
= num_destroy
= 0;
57 create_time
= created_time
= relay_time
= destroy_time
= 0;
59 /* remember which second it is, for next time */
63 switch(cell
->command
) {
65 ++stats_n_padding_cells_processed
;
69 ++stats_n_create_cells_processed
;
70 command_time_process_cell(cell
, conn
, &num_create
, &create_time
,
71 command_process_create_cell
);
74 ++stats_n_created_cells_processed
;
75 command_time_process_cell(cell
, conn
, &num_created
, &created_time
,
76 command_process_created_cell
);
79 ++stats_n_relay_cells_processed
;
80 command_time_process_cell(cell
, conn
, &num_relay
, &relay_time
,
81 command_process_relay_cell
);
84 ++stats_n_destroy_cells_processed
;
85 command_time_process_cell(cell
, conn
, &num_destroy
, &destroy_time
,
86 command_process_destroy_cell
);
89 log_fn(LOG_WARN
,"Cell of unknown type (%d) received. Dropping.", cell
->command
);
94 static void command_process_create_cell(cell_t
*cell
, connection_t
*conn
) {
97 circ
= circuit_get_by_circ_id_conn(cell
->circ_id
, conn
);
100 log_fn(LOG_WARN
,"received CREATE cell (circID %d) for known circ. Dropping.", cell
->circ_id
);
104 circ
= circuit_new(cell
->circ_id
, conn
);
105 circ
->state
= CIRCUIT_STATE_ONIONSKIN_PENDING
;
106 circ
->purpose
= CIRCUIT_PURPOSE_OR
;
108 memcpy(circ
->onionskin
, cell
->payload
, ONIONSKIN_CHALLENGE_LEN
);
110 /* hand it off to the cpuworkers, and then return */
111 if(assign_to_cpuworker(NULL
, CPUWORKER_TASK_ONION
, circ
) < 0) {
112 log_fn(LOG_WARN
,"Failed to hand off onionskin. Closing.");
113 circuit_mark_for_close(circ
);
116 log_fn(LOG_DEBUG
,"success: handed off onionskin.");
119 static void command_process_created_cell(cell_t
*cell
, connection_t
*conn
) {
122 circ
= circuit_get_by_circ_id_conn(cell
->circ_id
, conn
);
125 log_fn(LOG_INFO
,"(circID %d) unknown circ (probably got a destroy earlier). Dropping.", cell
->circ_id
);
129 if(circ
->n_circ_id
!= cell
->circ_id
) {
130 log_fn(LOG_WARN
,"got created cell from OPward? Closing.");
131 circuit_mark_for_close(circ
);
135 if(CIRCUIT_IS_ORIGIN(circ
)) { /* we're the OP. Handshake this. */
136 log_fn(LOG_DEBUG
,"at OP. Finishing handshake.");
137 if(circuit_finish_handshake(circ
, cell
->payload
) < 0) {
138 log_fn(LOG_WARN
,"circuit_finish_handshake failed.");
139 circuit_mark_for_close(circ
);
142 log_fn(LOG_DEBUG
,"Moving to next skin.");
143 if(circuit_send_next_onion_skin(circ
) < 0) {
144 log_fn(LOG_INFO
,"circuit_send_next_onion_skin failed.");
145 circuit_mark_for_close(circ
); /* XXX push this circuit_close lower */
148 } else { /* pack it into an extended relay cell, and send it. */
149 log_fn(LOG_DEBUG
,"Converting created cell to extended relay cell, sending.");
150 connection_edge_send_command(NULL
, circ
, RELAY_COMMAND_EXTENDED
,
151 cell
->payload
, ONIONSKIN_REPLY_LEN
, NULL
);
155 static void command_process_relay_cell(cell_t
*cell
, connection_t
*conn
) {
158 circ
= circuit_get_by_circ_id_conn(cell
->circ_id
, conn
);
161 log_fn(LOG_INFO
,"unknown circuit %d on connection to %s:%d. Dropping.",
162 cell
->circ_id
, conn
->address
, conn
->port
);
166 if(circ
->state
== CIRCUIT_STATE_ONIONSKIN_PENDING
) {
167 log_fn(LOG_WARN
,"circuit in create_wait. Closing.");
168 circuit_mark_for_close(circ
);
172 if(cell
->circ_id
== circ
->p_circ_id
) { /* it's an outgoing cell */
173 if(circuit_receive_relay_cell(cell
, circ
, CELL_DIRECTION_OUT
) < 0) {
174 log_fn(LOG_WARN
,"circuit_receive_relay_cell (forward) failed. Closing.");
175 circuit_mark_for_close(circ
);
178 } else { /* it's an ingoing cell */
179 if(circuit_receive_relay_cell(cell
, circ
, CELL_DIRECTION_IN
) < 0) {
180 log_fn(LOG_WARN
,"circuit_receive_relay_cell (backward) failed. Closing.");
181 circuit_mark_for_close(circ
);
187 static void command_process_destroy_cell(cell_t
*cell
, connection_t
*conn
) {
190 circ
= circuit_get_by_circ_id_conn(cell
->circ_id
, conn
);
193 log_fn(LOG_INFO
,"unknown circuit %d on connection to %s:%d. Dropping.",
194 cell
->circ_id
, conn
->address
, conn
->port
);
198 log_fn(LOG_INFO
,"Received for circID %d.",cell
->circ_id
);
199 if(circ
->state
== CIRCUIT_STATE_ONIONSKIN_PENDING
) {
200 onion_pending_remove(circ
);
203 if(cell
->circ_id
== circ
->p_circ_id
|| CIRCUIT_IS_ORIGIN(circ
)) {
204 /* either the destroy came from behind, or we're the AP */
206 circuit_mark_for_close(circ
);
207 } else { /* the destroy came from ahead */
209 log_fn(LOG_DEBUG
, "Delivering 'truncated' back.");
210 connection_edge_send_command(NULL
, circ
, RELAY_COMMAND_TRUNCATED
,