/** If we aren't currently dormant, close all connections and become * dormant. */ static void hibernate_go_dormant(time_t now) { connection_t *conn; if (hibernate_state == HIBERNATE_STATE_DORMANT) return; else if (hibernate_state == HIBERNATE_STATE_LOWBANDWIDTH) hibernate_state = HIBERNATE_STATE_DORMANT; else hibernate_begin(HIBERNATE_STATE_DORMANT, now); log_notice(LD_ACCT,"Going dormant. Blowing away remaining connections."); /* Close all OR/AP/exit conns. Leave dir conns because we still want * to be able to upload server descriptors so people know we're still * running, and download directories so we can detect if we're obsolete. * Leave control conns because we still want to be controllable. */ while ((conn = connection_get_by_type(CONN_TYPE_OR)) || (conn = connection_get_by_type(CONN_TYPE_AP)) || (conn = connection_get_by_type(CONN_TYPE_EXIT))) { if (CONN_IS_EDGE(conn)) connection_edge_end(TO_EDGE_CONN(conn), END_STREAM_REASON_HIBERNATING); log_info(LD_NET,"Closing conn type %d", conn->type); if (conn->type == CONN_TYPE_AP) /* send socks failure if needed */ connection_mark_unattached_ap(TO_ENTRY_CONN(conn), END_STREAM_REASON_HIBERNATING); else if (conn->type == CONN_TYPE_OR) { if (TO_OR_CONN(conn)->chan) { channel_mark_for_close(TLS_CHAN_TO_BASE(TO_OR_CONN(conn)->chan)); } else { connection_mark_for_close(conn); } } else connection_mark_for_close(conn); } if (now < interval_wakeup_time) hibernate_end_time = interval_wakeup_time; else hibernate_end_time = interval_end_time; accounting_record_bandwidth_usage(now, get_or_state()); or_state_mark_dirty(get_or_state(), get_options()->AvoidDiskWrites ? now+600 : 0); }
/** Log, at severity <b>severity</b>, information about each circuit * that is connected to <b>conn</b>. */ void circuit_dump_by_conn(connection_t *conn, int severity) { circuit_t *circ; edge_connection_t *tmpconn; for (circ=global_circuitlist;circ;circ = circ->next) { circid_t n_circ_id = circ->n_circ_id, p_circ_id = 0; if (circ->marked_for_close) continue; if (! CIRCUIT_IS_ORIGIN(circ)) p_circ_id = TO_OR_CIRCUIT(circ)->p_circ_id; if (! CIRCUIT_IS_ORIGIN(circ) && TO_OR_CIRCUIT(circ)->p_conn && TO_CONN(TO_OR_CIRCUIT(circ)->p_conn) == conn) circuit_dump_details(severity, circ, conn->conn_array_index, "App-ward", p_circ_id, n_circ_id); if (CIRCUIT_IS_ORIGIN(circ)) { for (tmpconn=TO_ORIGIN_CIRCUIT(circ)->p_streams; tmpconn; tmpconn=tmpconn->next_stream) { if (TO_CONN(tmpconn) == conn) { circuit_dump_details(severity, circ, conn->conn_array_index, "App-ward", p_circ_id, n_circ_id); } } } if (circ->n_conn && TO_CONN(circ->n_conn) == conn) circuit_dump_details(severity, circ, conn->conn_array_index, "Exit-ward", n_circ_id, p_circ_id); if (! CIRCUIT_IS_ORIGIN(circ)) { for (tmpconn=TO_OR_CIRCUIT(circ)->n_streams; tmpconn; tmpconn=tmpconn->next_stream) { if (TO_CONN(tmpconn) == conn) { circuit_dump_details(severity, circ, conn->conn_array_index, "Exit-ward", n_circ_id, p_circ_id); } } } if (!circ->n_conn && circ->n_hop && tor_addr_eq(&circ->n_hop->addr, &conn->addr) && circ->n_hop->port == conn->port && conn->type == CONN_TYPE_OR && !memcmp(TO_OR_CONN(conn)->identity_digest, circ->n_hop->identity_digest, DIGEST_LEN)) { circuit_dump_details(severity, circ, conn->conn_array_index, (circ->state == CIRCUIT_STATE_OPEN && !CIRCUIT_IS_ORIGIN(circ)) ? "Endpoint" : "Pending", n_circ_id, p_circ_id); } } }
/** Remove all entries from the identity-to-orconn map, and clear * all identities in OR conns.*/ void connection_or_clear_identity_map(void) { smartlist_t *conns = get_connection_array(); SMARTLIST_FOREACH(conns, connection_t *, conn, { if (conn->type == CONN_TYPE_OR) { or_connection_t *or_conn = TO_OR_CONN(conn); memset(or_conn->identity_digest, 0, DIGEST_LEN); or_conn->next_with_same_id = NULL; } });
/** Called when we get data from a cpuworker. If the answer is not complete, * wait for a complete answer. If the answer is complete, * process it as appropriate. */ int connection_cpu_process_inbuf(connection_t *conn) { char success; char buf[LEN_ONION_RESPONSE]; uint64_t conn_id; circid_t circ_id; connection_t *tmp_conn; or_connection_t *p_conn = NULL; circuit_t *circ; tor_assert(conn); tor_assert(conn->type == CONN_TYPE_CPUWORKER); if (!buf_datalen(conn->inbuf)) return 0; if (conn->state == CPUWORKER_STATE_BUSY_ONION) { if (buf_datalen(conn->inbuf) < LEN_ONION_RESPONSE) /* answer available? */ return 0; /* not yet */ tor_assert(buf_datalen(conn->inbuf) == LEN_ONION_RESPONSE); connection_fetch_from_buf(&success,1,conn); connection_fetch_from_buf(buf,LEN_ONION_RESPONSE-1,conn); /* parse out the circ it was talking about */ tag_unpack(buf, &conn_id, &circ_id); circ = NULL; tmp_conn = connection_get_by_global_id(conn_id); if (tmp_conn && !tmp_conn->marked_for_close && tmp_conn->type == CONN_TYPE_OR) p_conn = TO_OR_CONN(tmp_conn); if (p_conn) circ = circuit_get_by_circid_orconn(circ_id, p_conn); if (success == 0) { log_debug(LD_OR, "decoding onionskin failed. " "(Old key or bad software.) Closing."); if (circ) circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL); goto done_processing; } if (!circ) { /* This happens because somebody sends us a destroy cell and the * circuit goes away, while the cpuworker is working. This is also * why our tag doesn't include a pointer to the circ, because we'd * never know if it's still valid. */ log_debug(LD_OR,"processed onion for a circ that's gone. Dropping."); goto done_processing; } tor_assert(! CIRCUIT_IS_ORIGIN(circ)); if (onionskin_answer(TO_OR_CIRCUIT(circ), CELL_CREATED, buf+TAG_LEN, buf+TAG_LEN+ONIONSKIN_REPLY_LEN) < 0) { log_warn(LD_OR,"onionskin_answer failed. Closing."); circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL); goto done_processing; } log_debug(LD_OR,"onionskin_answer succeeded. Yay."); } else { tor_assert(0); /* don't ask me to do handshakes yet */ } done_processing: conn->state = CPUWORKER_STATE_IDLE; num_cpuworkers_busy--; if (conn->timestamp_created < last_rotation_time) { connection_mark_for_close(conn); num_cpuworkers--; spawn_enough_cpuworkers(); } else { process_pending_task(conn); } return 0; }