/** 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; }
/** 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; }