Fix an annoying rep violation bug
[tor.git] / src / or / circuitlist.c
blobabe083d313f55c9062c6a442dc439d603d2a1657
1 /* Copyright 2001 Matej Pfajfar.
2 * Copyright 2001-2004 Roger Dingledine.
3 * Copyright 2004-2005 Roger Dingledine, Nick Mathewson. */
4 /* See LICENSE for licensing information */
5 /* $Id$ */
6 const char circuitlist_c_id[] = "$Id$";
8 /**
9 * \file circuitlist.c
10 * \brief Manage the global circuit list.
11 **/
13 #include "or.h"
15 /* Define RB_AUGMENT to avoid warnings about if statements with emtpy bodies.
17 #define RB_AUGMENT(x) do{}while(0)
18 #include "tree.h"
20 /********* START VARIABLES **********/
22 /** A global list of all circuits at this hop. */
23 circuit_t *global_circuitlist=NULL;
25 static void circuit_free(circuit_t *circ);
26 static void circuit_free_cpath(crypt_path_t *cpath);
27 static void circuit_free_cpath_node(crypt_path_t *victim);
29 /********* END VARIABLES ************/
31 /** A map from OR connection and circuit ID to circuit. (Lookup performance is
32 * very important here, since we need to do it every time a cell arrives.) */
33 typedef struct orconn_circid_circuit_map_t {
34 RB_ENTRY(orconn_circid_circuit_map_t) node;
35 connection_t *or_conn;
36 uint16_t circ_id;
37 circuit_t *circuit;
38 } orconn_circid_circuit_map_t;
40 /** Helper for RB tree: compare the OR connection and circuit ID for a and b,
41 * and return less than, equal to, or greater than zero appropriately.
43 static INLINE int
44 compare_orconn_circid_entries(orconn_circid_circuit_map_t *a,
45 orconn_circid_circuit_map_t *b)
47 if (a->or_conn < b->or_conn)
48 return -1;
49 else if (a->or_conn > b->or_conn)
50 return 1;
51 else
52 return ((int)b->circ_id) - ((int)a->circ_id);
55 static RB_HEAD(orconn_circid_tree, orconn_circid_circuit_map_t) orconn_circid_circuit_map = RB_INITIALIZER(orconn_circid_circuit_map);
56 RB_PROTOTYPE(orconn_circid_tree, orconn_circid_circuit_map_t, node, compare_orconn_circid_entries);
57 RB_GENERATE(orconn_circid_tree, orconn_circid_circuit_map_t, node, compare_orconn_circid_entries);
59 /** The most recently returned entry from circuit_get_by_circid_orconn;
60 * used to improve performance when many cells arrive in a row from the
61 * same circuit.
63 /* (We tried using splay trees, but round-robin turned out to make them
64 * suck.) */
65 orconn_circid_circuit_map_t *_last_circid_orconn_ent = NULL;
67 /** Set the p_conn or n_conn field of a circuit <b>circ</b>, along
68 * with the corresponding circuit ID, and add the circuit as appropriate
69 * to the (orconn,id)-\>circuit map. */
70 void
71 circuit_set_circid_orconn(circuit_t *circ, uint16_t id,
72 connection_t *conn,
73 enum which_conn_changed_t which)
75 uint16_t old_id;
76 connection_t *old_conn;
77 orconn_circid_circuit_map_t search;
78 orconn_circid_circuit_map_t *found;
80 tor_assert(!conn || conn->type == CONN_TYPE_OR);
82 if (which == P_CONN_CHANGED) {
83 old_id = circ->p_circ_id;
84 old_conn = circ->p_conn;
85 circ->p_circ_id = id;
86 circ->p_conn = conn;
87 } else {
88 old_id = circ->n_circ_id;
89 old_conn = circ->n_conn;
90 circ->n_circ_id = id;
91 circ->n_conn = conn;
94 if (_last_circid_orconn_ent &&
95 ((old_id == _last_circid_orconn_ent->circ_id &&
96 old_conn == _last_circid_orconn_ent->or_conn) ||
97 (id == _last_circid_orconn_ent->circ_id &&
98 conn == _last_circid_orconn_ent->or_conn))) {
99 _last_circid_orconn_ent = NULL;
102 if (old_conn) {
103 search.circ_id = old_id;
104 search.or_conn = old_conn;
105 found = RB_FIND(orconn_circid_tree, &orconn_circid_circuit_map, &search);
106 if (found) {
107 RB_REMOVE(orconn_circid_tree, &orconn_circid_circuit_map, found);
109 tor_free(found);
112 if (conn == NULL)
113 return;
115 search.circ_id = id;
116 search.or_conn = conn;
117 found = RB_FIND(orconn_circid_tree, &orconn_circid_circuit_map, &search);
118 if (found) {
119 found->circuit = circ;
120 } else {
121 found = tor_malloc_zero(sizeof(orconn_circid_circuit_map_t));
122 found->circ_id = id;
123 found->or_conn = conn;
124 found->circuit = circ;
125 RB_INSERT(orconn_circid_tree, &orconn_circid_circuit_map, found);
129 /** Add <b>circ</b> to the global list of circuits. This is called only from
130 * within circuit_new.
132 static void
133 circuit_add(circuit_t *circ)
135 if (!global_circuitlist) { /* first one */
136 global_circuitlist = circ;
137 circ->next = NULL;
138 } else {
139 circ->next = global_circuitlist;
140 global_circuitlist = circ;
144 /** Detach from the global circuit list, and deallocate, all
145 * circuits that have been marked for close.
147 void
148 circuit_close_all_marked(void)
150 circuit_t *tmp,*m;
152 while (global_circuitlist && global_circuitlist->marked_for_close) {
153 tmp = global_circuitlist->next;
154 circuit_free(global_circuitlist);
155 global_circuitlist = tmp;
158 tmp = global_circuitlist;
159 while (tmp && tmp->next) {
160 if (tmp->next->marked_for_close) {
161 m = tmp->next->next;
162 circuit_free(tmp->next);
163 tmp->next = m;
164 /* Need to check new tmp->next; don't advance tmp. */
165 } else {
166 /* Advance tmp. */
167 tmp = tmp->next;
172 /** Return the head of the global linked list of circuits. **/
173 circuit_t *
174 _circuit_get_global_list(void)
176 return global_circuitlist;
179 /** Function to make circ-\>state human-readable */
180 const char *
181 circuit_state_to_string(int state)
183 static char buf[64];
184 switch (state) {
185 case CIRCUIT_STATE_BUILDING: return "doing handshakes";
186 case CIRCUIT_STATE_ONIONSKIN_PENDING: return "processing the onion";
187 case CIRCUIT_STATE_OR_WAIT: return "connecting to firsthop";
188 case CIRCUIT_STATE_OPEN: return "open";
189 default:
190 warn(LD_BUG, "Bug: unknown circuit state %d", state);
191 tor_snprintf(buf, sizeof(buf), "unknown state [%d]", state);
192 return buf;
196 /** Allocate space for a new circuit, initializing with <b>p_circ_id</b>
197 * and <b>p_conn</b>. Add it to the global circuit list.
199 circuit_t *
200 circuit_new(uint16_t p_circ_id, connection_t *p_conn)
202 circuit_t *circ;
203 static uint32_t n_circuits_allocated = 1;
204 /* never zero, since a global ID of 0 is treated specially by the
205 * controller */
207 circ = tor_malloc_zero(sizeof(circuit_t));
208 circ->magic = CIRCUIT_MAGIC;
210 circ->timestamp_created = time(NULL);
212 circ->state = CIRCUIT_STATE_ONIONSKIN_PENDING;
214 /* CircIDs */
215 if (p_conn) {
216 circuit_set_circid_orconn(circ, p_circ_id, p_conn, P_CONN_CHANGED);
218 /* circ->n_circ_id remains 0 because we haven't identified the next hop yet */
220 circ->package_window = CIRCWINDOW_START;
221 circ->deliver_window = CIRCWINDOW_START;
223 circ->next_stream_id = crypto_rand_int(1<<16);
224 circ->global_identifier = n_circuits_allocated++;
226 circuit_add(circ);
228 return circ;
231 /** Deallocate space associated with circ.
233 static void
234 circuit_free(circuit_t *circ)
236 tor_assert(circ);
237 tor_assert(circ->magic == CIRCUIT_MAGIC);
238 if (circ->n_crypto)
239 crypto_free_cipher_env(circ->n_crypto);
240 if (circ->p_crypto)
241 crypto_free_cipher_env(circ->p_crypto);
242 if (circ->n_digest)
243 crypto_free_digest_env(circ->n_digest);
244 if (circ->p_digest)
245 crypto_free_digest_env(circ->p_digest);
246 if (circ->build_state) {
247 if (circ->build_state->chosen_exit)
248 extend_info_free(circ->build_state->chosen_exit);
249 if (circ->build_state->pending_final_cpath)
250 circuit_free_cpath_node(circ->build_state->pending_final_cpath);
252 tor_free(circ->build_state);
253 circuit_free_cpath(circ->cpath);
254 if (circ->rend_splice) {
255 circ->rend_splice->rend_splice = NULL;
257 /* Remove from map. */
258 circuit_set_circid_orconn(circ, 0, NULL, P_CONN_CHANGED);
259 circuit_set_circid_orconn(circ, 0, NULL, N_CONN_CHANGED);
261 memset(circ, 0xAA, sizeof(circuit_t)); /* poison memory */
262 tor_free(circ);
265 /** Deallocate space associated with the linked list <b>cpath</b>. */
266 static void
267 circuit_free_cpath(crypt_path_t *cpath)
269 crypt_path_t *victim, *head=cpath;
271 if (!cpath)
272 return;
274 /* it's a doubly linked list, so we have to notice when we've
275 * gone through it once. */
276 while (cpath->next && cpath->next != head) {
277 victim = cpath;
278 cpath = victim->next;
279 circuit_free_cpath_node(victim);
282 circuit_free_cpath_node(cpath);
285 /** Release all storage held by circuits. */
286 void
287 circuit_free_all(void)
289 circuit_t *next;
290 while (global_circuitlist) {
291 next = global_circuitlist->next;
292 while (global_circuitlist->resolving_streams) {
293 connection_t *next;
294 next = global_circuitlist->resolving_streams->next_stream;
295 connection_free(global_circuitlist->resolving_streams);
296 global_circuitlist->resolving_streams = next;
298 circuit_free(global_circuitlist);
299 global_circuitlist = next;
303 /** Deallocate space associated with the cpath node <b>victim</b>. */
304 static void
305 circuit_free_cpath_node(crypt_path_t *victim)
307 if (victim->f_crypto)
308 crypto_free_cipher_env(victim->f_crypto);
309 if (victim->b_crypto)
310 crypto_free_cipher_env(victim->b_crypto);
311 if (victim->f_digest)
312 crypto_free_digest_env(victim->f_digest);
313 if (victim->b_digest)
314 crypto_free_digest_env(victim->b_digest);
315 if (victim->dh_handshake_state)
316 crypto_dh_free(victim->dh_handshake_state);
317 if (victim->extend_info)
318 extend_info_free(victim->extend_info);
320 victim->magic = 0xDEADBEEFu;
321 tor_free(victim);
324 /** Return the circuit whose global ID is <b>id</b>, or NULL if no
325 * such circuit exists. */
326 circuit_t *
327 circuit_get_by_global_id(uint32_t id)
329 circuit_t *circ;
330 for (circ=global_circuitlist;circ;circ = circ->next) {
331 if (circ->global_identifier == id) {
332 if (circ->marked_for_close)
333 return NULL;
334 else
335 return circ;
338 return NULL;
341 /** Return a circ such that:
342 * - circ-\>n_circ_id or circ-\>p_circ_id is equal to <b>circ_id</b>, and
343 * - circ is attached to <b>conn</b>, either as p_conn or n_conn.
344 * Return NULL if no such circuit exists.
346 static INLINE circuit_t *
347 circuit_get_by_circid_orconn_impl(uint16_t circ_id, connection_t *conn)
349 orconn_circid_circuit_map_t search;
350 orconn_circid_circuit_map_t *found;
352 tor_assert(conn->type == CONN_TYPE_OR);
354 if (_last_circid_orconn_ent &&
355 circ_id == _last_circid_orconn_ent->circ_id &&
356 conn == _last_circid_orconn_ent->or_conn) {
357 found = _last_circid_orconn_ent;
358 } else {
359 search.circ_id = circ_id;
360 search.or_conn = conn;
361 found = RB_FIND(orconn_circid_tree, &orconn_circid_circuit_map, &search);
362 _last_circid_orconn_ent = found;
364 if (found && found->circuit)
365 return found->circuit;
367 /* The rest of this can be replaced with
368 "return NULL;" once we believe the code works. */
371 circuit_t *circ;
372 for (circ=global_circuitlist;circ;circ = circ->next) {
373 if (circ->p_conn == conn && circ->p_circ_id == circ_id) {
374 warn(LD_BUG, "circuit matches p_conn, but not in tree (Bug!)");
375 return circ;
377 if (circ->n_conn == conn && circ->n_circ_id == circ_id) {
378 warn(LD_BUG, "circuit matches n_conn, but not in tree (Bug!)");
379 return circ;
382 return NULL;
386 /** Return a circ such that:
387 * - circ-\>n_circ_id or circ-\>p_circ_id is equal to <b>circ_id</b>, and
388 * - circ is attached to <b>conn</b>, either as p_conn or n_conn.
389 * - circ is not marked for close.
390 * Return NULL if no such circuit exists.
392 circuit_t *
393 circuit_get_by_circid_orconn(uint16_t circ_id, connection_t *conn)
395 circuit_t *circ = circuit_get_by_circid_orconn_impl(circ_id, conn);
396 if (!circ || circ->marked_for_close)
397 return NULL;
398 else
399 return circ;
402 /** Return true iff there is a circ such that
403 * - circ-\>n_circ_id or circ-\>p_circ_id is equal to <b>circ_id</b>, and
404 * - circ is attached to <b>conn</b>, either as p_conn or n_conn.
405 * Return NULL if no such circuit exists.
408 circuit_id_used_on_conn(uint16_t circ_id, connection_t *conn)
410 circuit_t *circ = circuit_get_by_circid_orconn_impl(circ_id, conn);
411 if (circ && circ->marked_for_close)
412 log_fn(LOG_NOTICE, LD_CIRC,
413 "I was about to re-use a circuit ID that had been marked."
414 " Good thing we fixed that bug!");
415 return circ != NULL;
418 /** Return the circuit that a given edge connection is using. */
419 circuit_t *
420 circuit_get_by_edge_conn(connection_t *conn)
422 circuit_t *circ;
423 #if 0
424 connection_t *tmpconn;
425 #endif
426 tor_assert(CONN_IS_EDGE(conn));
428 if (! conn->on_circuit) {
429 /* return NULL; */
430 circ = circuit_get_by_conn(conn);
431 if (circ) {
432 warn(LD_BUG, "BUG: conn->on_circuit==NULL, but there was in fact a circuit there.");
434 return circ;
437 circ = conn->on_circuit;
438 tor_assert(circ->magic == CIRCUIT_MAGIC);
439 #if 0
440 /* All this stuff here is sanity-checking. */
441 for (tmpconn = circ->p_streams; tmpconn; tmpconn=tmpconn->next_stream)
442 if (tmpconn == conn)
443 return circ;
444 for (tmpconn = circ->n_streams; tmpconn; tmpconn=tmpconn->next_stream)
445 if (tmpconn == conn)
446 return circ;
447 for (tmpconn = circ->resolving_streams; tmpconn; tmpconn=tmpconn->next_stream)
448 if (tmpconn == conn)
449 return circ;
451 tor_assert(0);
452 #endif
453 return circ;
456 /** Return a circ such that circ is attached to <b>conn</b>, either as
457 * p_conn, n_conn, or in p_streams or n_streams or resolving_streams.
459 * Return NULL if no such circuit exists.
461 circuit_t *
462 circuit_get_by_conn(connection_t *conn)
464 circuit_t *circ;
465 connection_t *tmpconn;
467 for (circ=global_circuitlist;circ;circ = circ->next) {
468 if (circ->marked_for_close)
469 continue;
471 if (circ->p_conn == conn)
472 return circ;
473 if (circ->n_conn == conn)
474 return circ;
475 for (tmpconn = circ->p_streams; tmpconn; tmpconn=tmpconn->next_stream)
476 if (tmpconn == conn)
477 return circ;
478 for (tmpconn = circ->n_streams; tmpconn; tmpconn=tmpconn->next_stream)
479 if (tmpconn == conn)
480 return circ;
481 for (tmpconn = circ->resolving_streams; tmpconn; tmpconn=tmpconn->next_stream)
482 if (tmpconn == conn)
483 return circ;
485 return NULL;
488 /** Return a circ such that:
489 * - circ-\>rend_query is equal to <b>rend_query</b>, and
490 * - circ-\>purpose is equal to <b>purpose</b>.
492 * Return NULL if no such circuit exists.
494 circuit_t *
495 circuit_get_by_rend_query_and_purpose(const char *rend_query, uint8_t purpose)
497 circuit_t *circ;
499 for (circ = global_circuitlist; circ; circ = circ->next) {
500 if (!circ->marked_for_close &&
501 circ->purpose == purpose &&
502 !rend_cmp_service_ids(rend_query, circ->rend_query))
503 return circ;
505 return NULL;
508 /** Return the first circuit in global_circuitlist after <b>start</b>
509 * whose rend_pk_digest field is <b>digest</b> and whose purpose is
510 * <b>purpose</b>. Returns NULL if no circuit is found.
511 * If <b>start</b> is NULL, begin at the start of the list.
513 circuit_t *
514 circuit_get_next_by_pk_and_purpose(circuit_t *start,
515 const char *digest, uint8_t purpose)
517 circuit_t *circ;
518 if (start == NULL)
519 circ = global_circuitlist;
520 else
521 circ = start->next;
523 for ( ; circ; circ = circ->next) {
524 if (circ->marked_for_close)
525 continue;
526 if (circ->purpose != purpose)
527 continue;
528 if (!memcmp(circ->rend_pk_digest, digest, DIGEST_LEN))
529 return circ;
531 return NULL;
534 /** Return the circuit waiting for a rendezvous with the provided cookie.
535 * Return NULL if no such circuit is found.
537 circuit_t *
538 circuit_get_rendezvous(const char *cookie)
540 circuit_t *circ;
541 for (circ = global_circuitlist; circ; circ = circ->next) {
542 if (! circ->marked_for_close &&
543 circ->purpose == CIRCUIT_PURPOSE_REND_POINT_WAITING &&
544 ! memcmp(circ->rend_cookie, cookie, REND_COOKIE_LEN) )
545 return circ;
547 return NULL;
550 /** Return a circuit that is open, has specified <b>purpose</b>,
551 * has a timestamp_dirty value of 0, and is uptime/capacity/internal
552 * if required; or NULL if no circuit fits this description.
554 * Avoid returning need_uptime circuits if not necessary.
555 * FFFF As a more important goal, not yet implemented, avoid returning
556 * internal circuits if not necessary.
558 circuit_t *
559 circuit_get_clean_open(uint8_t purpose, int need_uptime,
560 int need_capacity, int internal)
562 circuit_t *circ;
563 circuit_t *best=NULL;
565 debug(LD_CIRC,"Hunting for a circ to cannibalize: purpose %d, uptime %d, capacity %d, internal %d", purpose, need_uptime, need_capacity, internal);
567 for (circ=global_circuitlist; circ; circ = circ->next) {
568 if (CIRCUIT_IS_ORIGIN(circ) &&
569 circ->state == CIRCUIT_STATE_OPEN &&
570 !circ->marked_for_close &&
571 circ->purpose == purpose &&
572 !circ->timestamp_dirty &&
573 (!need_uptime || circ->build_state->need_uptime) &&
574 (!need_capacity || circ->build_state->need_capacity) &&
575 (!internal || circ->build_state->is_internal)) {
576 if (!best || (best->build_state->need_uptime && !need_uptime))
577 best = circ;
580 return best;
583 /** Go through the circuitlist; mark-for-close each circuit that starts
584 * at us but has not yet been used. */
585 void
586 circuit_mark_all_unused_circs(void)
588 circuit_t *circ;
590 for (circ=global_circuitlist; circ; circ = circ->next) {
591 if (CIRCUIT_IS_ORIGIN(circ) &&
592 !circ->marked_for_close &&
593 !circ->timestamp_dirty)
594 circuit_mark_for_close(circ);
598 /** Go through the circuitlist; for each circuit that starts at us
599 * and is dirty, frob its timestamp_dirty so we won't use it for any
600 * new streams.
602 * This is useful for letting the user change pseudonyms, so new
603 * streams will not be linkable to old streams.
605 void
606 circuit_expire_all_dirty_circs(void)
608 circuit_t *circ;
609 or_options_t *options = get_options();
611 for (circ=global_circuitlist; circ; circ = circ->next) {
612 if (CIRCUIT_IS_ORIGIN(circ) &&
613 !circ->marked_for_close &&
614 circ->timestamp_dirty)
615 circ->timestamp_dirty -= options->MaxCircuitDirtiness;
619 /** Mark <b>circ</b> to be closed next time we call
620 * circuit_close_all_marked(). Do any cleanup needed:
621 * - If state is onionskin_pending, remove circ from the onion_pending
622 * list.
623 * - If circ isn't open yet: call circuit_build_failed() if we're
624 * the origin, and in either case call circuit_rep_hist_note_result()
625 * to note stats.
626 * - If purpose is C_INTRODUCE_ACK_WAIT, remove the intro point we
627 * just tried from our list of intro points for that service
628 * descriptor.
629 * - Send appropriate destroys and edge_destroys for conns and
630 * streams attached to circ.
631 * - If circ->rend_splice is set (we are the midpoint of a joined
632 * rendezvous stream), then mark the other circuit to close as well.
634 void
635 _circuit_mark_for_close(circuit_t *circ, int line, const char *file)
637 connection_t *conn;
639 assert_circuit_ok(circ);
640 tor_assert(line);
641 tor_assert(file);
643 if (circ->marked_for_close) {
644 log(LOG_WARN,LD_BUG,
645 "Duplicate call to circuit_mark_for_close at %s:%d"
646 " (first at %s:%d)", file, line,
647 circ->marked_for_close_file, circ->marked_for_close);
648 return;
651 if (circ->state == CIRCUIT_STATE_ONIONSKIN_PENDING) {
652 onion_pending_remove(circ);
654 /* If the circuit ever became OPEN, we sent it to the reputation history
655 * module then. If it isn't OPEN, we send it there now to remember which
656 * links worked and which didn't.
658 if (circ->state != CIRCUIT_STATE_OPEN) {
659 if (CIRCUIT_IS_ORIGIN(circ)) {
660 circuit_build_failed(circ); /* take actions if necessary */
662 circuit_rep_hist_note_result(circ);
664 if (CIRCUIT_IS_ORIGIN(circ)) {
665 control_event_circuit_status(circ,
666 (circ->state == CIRCUIT_STATE_OPEN)?CIRC_EVENT_CLOSED:CIRC_EVENT_FAILED);
668 if (circ->purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) {
669 tor_assert(circ->state == CIRCUIT_STATE_OPEN);
670 tor_assert(circ->build_state->chosen_exit);
671 /* treat this like getting a nack from it */
672 info(LD_REND,"Failed intro circ %s to %s (awaiting ack). Removing from descriptor.",
673 safe_str(circ->rend_query),
674 safe_str(build_state_get_exit_nickname(circ->build_state)));
675 rend_client_remove_intro_point(circ->build_state->chosen_exit,
676 circ->rend_query);
679 if (circ->n_conn)
680 connection_send_destroy(circ->n_circ_id, circ->n_conn);
681 for (conn=circ->n_streams; conn; conn=conn->next_stream)
682 connection_edge_destroy(circ->n_circ_id, conn);
683 while (circ->resolving_streams) {
684 conn = circ->resolving_streams;
685 circ->resolving_streams = conn->next_stream;
686 if (!conn->marked_for_close) {
687 /* The other side will see a DESTROY, and infer that the connections
688 * are closing because the circuit is getting torn down. No need
689 * to send an end cell*/
690 conn->has_sent_end = 1; /* we're closing the circuit, nothing to send to */
691 connection_mark_for_close(conn);
693 conn->on_circuit = NULL;
695 if (circ->p_conn)
696 connection_send_destroy(circ->p_circ_id, circ->p_conn);
697 for (conn=circ->p_streams; conn; conn=conn->next_stream)
698 connection_edge_destroy(circ->p_circ_id, conn);
700 circ->marked_for_close = line;
701 circ->marked_for_close_file = file;
703 if (circ->rend_splice && !circ->rend_splice->marked_for_close) {
704 /* do this after marking this circuit, to avoid infinite recursion. */
705 circuit_mark_for_close(circ->rend_splice);
706 circ->rend_splice = NULL;
710 /** Verify that cpath layer <b>cp</b> has all of its invariants
711 * correct. Trigger an assert if anything is invalid.
713 void
714 assert_cpath_layer_ok(const crypt_path_t *cp)
716 // tor_assert(cp->addr); /* these are zero for rendezvous extra-hops */
717 // tor_assert(cp->port);
718 tor_assert(cp);
719 tor_assert(cp->magic == CRYPT_PATH_MAGIC);
720 switch (cp->state)
722 case CPATH_STATE_OPEN:
723 tor_assert(cp->f_crypto);
724 tor_assert(cp->b_crypto);
725 /* fall through */
726 case CPATH_STATE_CLOSED:
727 tor_assert(!cp->dh_handshake_state);
728 break;
729 case CPATH_STATE_AWAITING_KEYS:
730 /* tor_assert(cp->dh_handshake_state); */
731 break;
732 default:
733 log_fn(LOG_ERR, LD_BUG, "Unexpected state %d", cp->state);
734 tor_assert(0);
736 tor_assert(cp->package_window >= 0);
737 tor_assert(cp->deliver_window >= 0);
740 /** Verify that cpath <b>cp</b> has all of its invariants
741 * correct. Trigger an assert if anything is invalid.
743 static void
744 assert_cpath_ok(const crypt_path_t *cp)
746 const crypt_path_t *start = cp;
748 do {
749 assert_cpath_layer_ok(cp);
750 /* layers must be in sequence of: "open* awaiting? closed*" */
751 if (cp != start) {
752 if (cp->state == CPATH_STATE_AWAITING_KEYS) {
753 tor_assert(cp->prev->state == CPATH_STATE_OPEN);
754 } else if (cp->state == CPATH_STATE_OPEN) {
755 tor_assert(cp->prev->state == CPATH_STATE_OPEN);
758 cp = cp->next;
759 tor_assert(cp);
760 } while (cp != start);
763 /** Verify that circuit <b>c</b> has all of its invariants
764 * correct. Trigger an assert if anything is invalid.
766 void
767 assert_circuit_ok(const circuit_t *c)
769 connection_t *conn;
771 tor_assert(c);
772 tor_assert(c->magic == CIRCUIT_MAGIC);
773 tor_assert(c->purpose >= _CIRCUIT_PURPOSE_MIN &&
774 c->purpose <= _CIRCUIT_PURPOSE_MAX);
776 if (c->n_conn) {
777 tor_assert(c->n_conn->type == CONN_TYPE_OR);
778 tor_assert(!memcmp(c->n_conn->identity_digest, c->n_conn_id_digest, DIGEST_LEN));
779 if (c->n_circ_id)
780 tor_assert(c == circuit_get_by_circid_orconn(c->n_circ_id, c->n_conn));
782 if (c->p_conn) {
783 tor_assert(c->p_conn->type == CONN_TYPE_OR);
784 if (c->p_circ_id)
785 tor_assert(c == circuit_get_by_circid_orconn(c->p_circ_id, c->p_conn));
787 for (conn = c->p_streams; conn; conn = conn->next_stream)
788 tor_assert(conn->type == CONN_TYPE_AP);
789 for (conn = c->n_streams; conn; conn = conn->next_stream)
790 tor_assert(conn->type == CONN_TYPE_EXIT);
792 tor_assert(c->deliver_window >= 0);
793 tor_assert(c->package_window >= 0);
794 if (c->state == CIRCUIT_STATE_OPEN) {
795 if (c->cpath) {
796 tor_assert(CIRCUIT_IS_ORIGIN(c));
797 tor_assert(!c->n_crypto);
798 tor_assert(!c->p_crypto);
799 tor_assert(!c->n_digest);
800 tor_assert(!c->p_digest);
801 } else {
802 tor_assert(!CIRCUIT_IS_ORIGIN(c));
803 tor_assert(c->n_crypto);
804 tor_assert(c->p_crypto);
805 tor_assert(c->n_digest);
806 tor_assert(c->p_digest);
809 if (c->cpath) {
810 assert_cpath_ok(c->cpath);
812 if (c->purpose == CIRCUIT_PURPOSE_REND_ESTABLISHED) {
813 if (!c->marked_for_close) {
814 tor_assert(c->rend_splice);
815 tor_assert(c->rend_splice->rend_splice == c);
817 tor_assert(c->rend_splice != c);
818 } else {
819 tor_assert(!c->rend_splice);