/** Try to tell a cpuworker to perform the public key operations necessary to * respond to <b>onionskin</b> for the circuit <b>circ</b>. * * If <b>cpuworker</b> is defined, assert that he's idle, and use him. Else, * look for an idle cpuworker and use him. If none idle, queue task onto the * pending onion list and return. Return 0 if we successfully assign the * task, or -1 on failure. */ int assign_onionskin_to_cpuworker(connection_t *cpuworker, or_circuit_t *circ, char *onionskin) { char qbuf[1]; char tag[TAG_LEN]; time_t now = approx_time(); static time_t last_culled_cpuworkers = 0; /* Checking for wedged cpuworkers requires a linear search over all * connections, so let's do it only once a minute. */ #define CULL_CPUWORKERS_INTERVAL 60 if (last_culled_cpuworkers + CULL_CPUWORKERS_INTERVAL <= now) { cull_wedged_cpuworkers(); spawn_enough_cpuworkers(); last_culled_cpuworkers = now; } if (1) { if (num_cpuworkers_busy == num_cpuworkers) { log_debug(LD_OR,"No idle cpuworkers. Queuing."); if (onion_pending_add(circ, onionskin) < 0) { tor_free(onionskin); return -1; } return 0; } if (!cpuworker) cpuworker = connection_get_by_type_state(CONN_TYPE_CPUWORKER, CPUWORKER_STATE_IDLE); tor_assert(cpuworker); if (!circ->p_conn) { log_info(LD_OR,"circ->p_conn gone. Failing circ."); tor_free(onionskin); return -1; } tag_pack(tag, circ->p_conn->_base.global_identifier, circ->p_circ_id); cpuworker->state = CPUWORKER_STATE_BUSY_ONION; /* touch the lastwritten timestamp, since that's how we check to * see how long it's been since we asked the question, and sometimes * we check before the first call to connection_handle_write(). */ cpuworker->timestamp_lastwritten = time(NULL); num_cpuworkers_busy++; qbuf[0] = CPUWORKER_TASK_ONION; connection_write_to_buf(qbuf, 1, cpuworker); connection_write_to_buf(tag, sizeof(tag), cpuworker); connection_write_to_buf(onionskin, ONIONSKIN_CHALLENGE_LEN, cpuworker); tor_free(onionskin); } return 0; }
/** Called when the onion key has changed and we need to spawn new * cpuworkers. Close all currently idle cpuworkers, and mark the last * rotation time as now. */ void cpuworkers_rotate(void) { connection_t *cpuworker; while ((cpuworker = connection_get_by_type_state(CONN_TYPE_CPUWORKER, CPUWORKER_STATE_IDLE))) { connection_mark_for_close(cpuworker); --num_cpuworkers; } last_rotation_time = time(NULL); if (server_mode(get_options())) spawn_enough_cpuworkers(); }
/** Try to tell a cpuworker to perform the public key operations necessary to * respond to <b>onionskin</b> for the circuit <b>circ</b>. * * If <b>cpuworker</b> is defined, assert that he's idle, and use him. Else, * look for an idle cpuworker and use him. If none idle, queue task onto the * pending onion list and return. Return 0 if we successfully assign the * task, or -1 on failure. */ int assign_onionskin_to_cpuworker(connection_t *cpuworker, or_circuit_t *circ, create_cell_t *onionskin) { cpuworker_request_t req; time_t now = approx_time(); static time_t last_culled_cpuworkers = 0; int should_time; /* Checking for wedged cpuworkers requires a linear search over all * connections, so let's do it only once a minute. */ #define CULL_CPUWORKERS_INTERVAL 60 if (last_culled_cpuworkers + CULL_CPUWORKERS_INTERVAL <= now) { cull_wedged_cpuworkers(); spawn_enough_cpuworkers(); last_culled_cpuworkers = now; } if (1) { if (num_cpuworkers_busy == num_cpuworkers) { log_debug(LD_OR,"No idle cpuworkers. Queuing."); if (onion_pending_add(circ, onionskin) < 0) { tor_free(onionskin); return -1; } return 0; } if (!cpuworker) cpuworker = connection_get_by_type_state(CONN_TYPE_CPUWORKER, CPUWORKER_STATE_IDLE); tor_assert(cpuworker); if (!circ->p_chan) { log_info(LD_OR,"circ->p_chan gone. Failing circ."); tor_free(onionskin); return -1; } if (connection_or_digest_is_known_relay(circ->p_chan->identity_digest)) rep_hist_note_circuit_handshake_assigned(onionskin->handshake_type); should_time = should_time_request(onionskin->handshake_type); memset(&req, 0, sizeof(req)); req.magic = CPUWORKER_REQUEST_MAGIC; tag_pack(req.tag, circ->p_chan->global_identifier, circ->p_circ_id); req.timed = should_time; cpuworker->state = CPUWORKER_STATE_BUSY_ONION; /* touch the lastwritten timestamp, since that's how we check to * see how long it's been since we asked the question, and sometimes * we check before the first call to connection_handle_write(). */ cpuworker->timestamp_lastwritten = now; num_cpuworkers_busy++; req.task = CPUWORKER_TASK_ONION; memcpy(&req.create_cell, onionskin, sizeof(create_cell_t)); tor_free(onionskin); if (should_time) tor_gettimeofday(&req.started_at); connection_write_to_buf((void*)&req, sizeof(req), cpuworker); memwipe(&req, 0, sizeof(req)); } return 0; }
static void test_conn_get_basic(void *arg) { connection_t *conn = (connection_t*)arg; tor_addr_t addr, addr2; tt_assert(conn); assert_connection_ok(conn, time(NULL)); test_conn_lookup_addr_helper(TEST_CONN_ADDRESS, TEST_CONN_FAMILY, &addr); tt_assert(!tor_addr_is_null(&addr)); test_conn_lookup_addr_helper(TEST_CONN_ADDRESS_2, TEST_CONN_FAMILY, &addr2); tt_assert(!tor_addr_is_null(&addr2)); /* Check that we get this connection back when we search for it by * its attributes, but get NULL when we supply a different value. */ tt_assert(connection_get_by_global_id(conn->global_identifier) == conn); tt_assert(connection_get_by_global_id(!conn->global_identifier) == NULL); tt_assert(connection_get_by_type(conn->type) == conn); tt_assert(connection_get_by_type(TEST_CONN_TYPE) == conn); tt_assert(connection_get_by_type(!conn->type) == NULL); tt_assert(connection_get_by_type(!TEST_CONN_TYPE) == NULL); tt_assert(connection_get_by_type_state(conn->type, conn->state) == conn); tt_assert(connection_get_by_type_state(TEST_CONN_TYPE, TEST_CONN_STATE) == conn); tt_assert(connection_get_by_type_state(!conn->type, !conn->state) == NULL); tt_assert(connection_get_by_type_state(!TEST_CONN_TYPE, !TEST_CONN_STATE) == NULL); /* Match on the connection fields themselves */ tt_assert(connection_get_by_type_addr_port_purpose(conn->type, &conn->addr, conn->port, conn->purpose) == conn); /* Match on the original inputs to the connection */ tt_assert(connection_get_by_type_addr_port_purpose(TEST_CONN_TYPE, &conn->addr, conn->port, conn->purpose) == conn); tt_assert(connection_get_by_type_addr_port_purpose(conn->type, &addr, conn->port, conn->purpose) == conn); tt_assert(connection_get_by_type_addr_port_purpose(conn->type, &conn->addr, TEST_CONN_PORT, conn->purpose) == conn); tt_assert(connection_get_by_type_addr_port_purpose(conn->type, &conn->addr, conn->port, TEST_CONN_BASIC_PURPOSE) == conn); tt_assert(connection_get_by_type_addr_port_purpose(TEST_CONN_TYPE, &addr, TEST_CONN_PORT, TEST_CONN_BASIC_PURPOSE) == conn); /* Then try each of the not-matching combinations */ tt_assert(connection_get_by_type_addr_port_purpose(!conn->type, &conn->addr, conn->port, conn->purpose) == NULL); tt_assert(connection_get_by_type_addr_port_purpose(conn->type, &addr2, conn->port, conn->purpose) == NULL); tt_assert(connection_get_by_type_addr_port_purpose(conn->type, &conn->addr, !conn->port, conn->purpose) == NULL); tt_assert(connection_get_by_type_addr_port_purpose(conn->type, &conn->addr, conn->port, !conn->purpose) == NULL); /* Then try everything not-matching */ tt_assert(connection_get_by_type_addr_port_purpose(!conn->type, &addr2, !conn->port, !conn->purpose) == NULL); tt_assert(connection_get_by_type_addr_port_purpose(!TEST_CONN_TYPE, &addr2, !TEST_CONN_PORT, !TEST_CONN_BASIC_PURPOSE) == NULL); done: ; }