static void cv_test_thr_fn_(void *arg) { cv_testinfo_t *i = arg; int tid, r; tor_mutex_acquire(i->mutex); tid = i->n_threads++; tor_mutex_release(i->mutex); (void) tid; tor_mutex_acquire(i->mutex); while (1) { if (i->addend) { i->value += i->addend; i->addend = 0; } if (i->shutdown) { ++i->n_shutdown; i->shutdown = 0; tor_mutex_release(i->mutex); spawn_exit(); } r = tor_cond_wait(i->cond, i->mutex, i->tv); ++i->n_wakeups; if (r == 1) { ++i->n_timeouts; tor_mutex_release(i->mutex); spawn_exit(); } } }
/** Helper function for threading unit tests: This function runs in a * subthread. It grabs its own mutex (start1 or start2) to make sure that it * should start, then it repeatedly alters _test_thread_strmap protected by * thread_test_mutex_. */ static void thread_test_func_(void* _s) { char *s = _s; int i, *count; tor_mutex_t *m; char buf[64]; char **cp; if (!strcmp(s, "thread 1")) { m = thread_test_start1_; cp = &thread1_name_; count = &t1_count; thread_fn_tid1 = tor_get_thread_id(); } else { m = thread_test_start2_; cp = &thread2_name_; count = &t2_count; thread_fn_tid2 = tor_get_thread_id(); } tor_snprintf(buf, sizeof(buf), "%lu", tor_get_thread_id()); *cp = tor_strdup(buf); tor_mutex_acquire(m); for (i=0; i<10000; ++i) { tor_mutex_acquire(thread_test_mutex_); strmap_set(thread_test_strmap_, "last to run", *cp); ++*count; tor_mutex_release(thread_test_mutex_); } tor_mutex_acquire(thread_test_mutex_); strmap_set(thread_test_strmap_, s, *cp); if (in_main_thread()) ++thread_fns_failed; tor_mutex_release(thread_test_mutex_); tor_mutex_release(m); spawn_exit(); }
/** Implement a cpuworker. 'data' is an fdarray as returned by socketpair. * Read and writes from fdarray[1]. Reads requests, writes answers. * * Request format: * cpuworker_request_t. * Response format: * cpuworker_reply_t */ static void cpuworker_main(void *data) { /* For talking to the parent thread/process */ tor_socket_t *fdarray = data; tor_socket_t fd; /* variables for onion processing */ server_onion_keys_t onion_keys; cpuworker_request_t req; cpuworker_reply_t rpl; fd = fdarray[1]; /* this side is ours */ #ifndef TOR_IS_MULTITHREADED tor_close_socket(fdarray[0]); /* this is the side of the socketpair the * parent uses */ tor_free_all(1); /* so the child doesn't hold the parent's fd's open */ handle_signals(0); /* ignore interrupts from the keyboard, etc */ #endif tor_free(data); setup_server_onion_keys(&onion_keys); for (;;) { if (read_all(fd, (void *)&req, sizeof(req), 1) != sizeof(req)) { log_info(LD_OR, "read request failed. Exiting."); goto end; } tor_assert(req.magic == CPUWORKER_REQUEST_MAGIC); memset(&rpl, 0, sizeof(rpl)); if (req.task == CPUWORKER_TASK_ONION) { const create_cell_t *cc = &req.create_cell; created_cell_t *cell_out = &rpl.created_cell; struct timeval tv_start = {0,0}, tv_end; int n; rpl.timed = req.timed; rpl.started_at = req.started_at; rpl.handshake_type = cc->handshake_type; if (req.timed) tor_gettimeofday(&tv_start); n = onion_skin_server_handshake(cc->handshake_type, cc->onionskin, cc->handshake_len, &onion_keys, cell_out->reply, rpl.keys, CPATH_KEY_MATERIAL_LEN, rpl.rend_auth_material); if (n < 0) { /* failure */ log_debug(LD_OR,"onion_skin_server_handshake failed."); memset(&rpl, 0, sizeof(rpl)); memcpy(rpl.tag, req.tag, TAG_LEN); rpl.success = 0; } else { /* success */ log_debug(LD_OR,"onion_skin_server_handshake succeeded."); memcpy(rpl.tag, req.tag, TAG_LEN); cell_out->handshake_len = n; switch (cc->cell_type) { case CELL_CREATE: cell_out->cell_type = CELL_CREATED; break; case CELL_CREATE2: cell_out->cell_type = CELL_CREATED2; break; case CELL_CREATE_FAST: cell_out->cell_type = CELL_CREATED_FAST; break; default: tor_assert(0); goto end; } rpl.success = 1; } rpl.magic = CPUWORKER_REPLY_MAGIC; if (req.timed) { struct timeval tv_diff; int64_t usec; tor_gettimeofday(&tv_end); timersub(&tv_end, &tv_start, &tv_diff); usec = ((int64_t)tv_diff.tv_sec)*1000000 + tv_diff.tv_usec; if (usec < 0 || usec > MAX_BELIEVABLE_ONIONSKIN_DELAY) rpl.n_usec = MAX_BELIEVABLE_ONIONSKIN_DELAY; else rpl.n_usec = (uint32_t) usec; } if (write_all(fd, (void*)&rpl, sizeof(rpl), 1) != sizeof(rpl)) { log_err(LD_BUG,"writing response buf failed. Exiting."); goto end; } log_debug(LD_OR,"finished writing response."); } else if (req.task == CPUWORKER_TASK_SHUTDOWN) { log_info(LD_OR,"Clean shutdown: exiting"); goto end; } memwipe(&req, 0, sizeof(req)); memwipe(&rpl, 0, sizeof(req)); } end: memwipe(&req, 0, sizeof(req)); memwipe(&rpl, 0, sizeof(req)); release_server_onion_keys(&onion_keys); tor_close_socket(fd); crypto_thread_cleanup(); spawn_exit(); }
/** Implement a cpuworker. 'data' is an fdarray as returned by socketpair. * Read and writes from fdarray[1]. Reads requests, writes answers. * * Request format: * Task type [1 byte, always CPUWORKER_TASK_ONION] * Opaque tag TAG_LEN * Onionskin challenge ONIONSKIN_CHALLENGE_LEN * Response format: * Success/failure [1 byte, boolean.] * Opaque tag TAG_LEN * Onionskin challenge ONIONSKIN_REPLY_LEN * Negotiated keys KEY_LEN*2+DIGEST_LEN*2 * * (Note: this _should_ be by addr/port, since we're concerned with specific * connections, not with routers (where we'd use identity).) */ static void cpuworker_main(void *data) { char question[ONIONSKIN_CHALLENGE_LEN]; uint8_t question_type; int *fdarray = data; int fd; /* variables for onion processing */ char keys[CPATH_KEY_MATERIAL_LEN]; char reply_to_proxy[ONIONSKIN_REPLY_LEN]; char buf[LEN_ONION_RESPONSE]; char tag[TAG_LEN]; crypto_pk_env_t *onion_key = NULL, *last_onion_key = NULL; fd = fdarray[1]; /* this side is ours */ #ifndef TOR_IS_MULTITHREADED tor_close_socket(fdarray[0]); /* this is the side of the socketpair the * parent uses */ tor_free_all(1); /* so the child doesn't hold the parent's fd's open */ handle_signals(0); /* ignore interrupts from the keyboard, etc */ #endif tor_free(data); dup_onion_keys(&onion_key, &last_onion_key); for (;;) { ssize_t r; if ((r = recv(fd, &question_type, 1, 0)) != 1) { // log_fn(LOG_ERR,"read type failed. Exiting."); if (r == 0) { log_info(LD_OR, "CPU worker exiting because Tor process closed connection " "(either rotated keys or died)."); } else { log_info(LD_OR, "CPU worker exiting because of error on connection to Tor " "process."); log_info(LD_OR,"(Error on %d was %s)", fd, tor_socket_strerror(tor_socket_errno(fd))); } goto end; } tor_assert(question_type == CPUWORKER_TASK_ONION); if (read_all(fd, tag, TAG_LEN, 1) != TAG_LEN) { log_err(LD_BUG,"read tag failed. Exiting."); goto end; } if (read_all(fd, question, ONIONSKIN_CHALLENGE_LEN, 1) != ONIONSKIN_CHALLENGE_LEN) { log_err(LD_BUG,"read question failed. Exiting."); goto end; } if (question_type == CPUWORKER_TASK_ONION) { if (onion_skin_server_handshake(question, onion_key, last_onion_key, reply_to_proxy, keys, CPATH_KEY_MATERIAL_LEN) < 0) { /* failure */ log_debug(LD_OR,"onion_skin_server_handshake failed."); *buf = 0; /* indicate failure in first byte */ memcpy(buf+1,tag,TAG_LEN); /* send all zeros as answer */ memset(buf+1+TAG_LEN, 0, LEN_ONION_RESPONSE-(1+TAG_LEN)); } else { /* success */ log_debug(LD_OR,"onion_skin_server_handshake succeeded."); buf[0] = 1; /* 1 means success */ memcpy(buf+1,tag,TAG_LEN); memcpy(buf+1+TAG_LEN,reply_to_proxy,ONIONSKIN_REPLY_LEN); memcpy(buf+1+TAG_LEN+ONIONSKIN_REPLY_LEN,keys,CPATH_KEY_MATERIAL_LEN); } if (write_all(fd, buf, LEN_ONION_RESPONSE, 1) != LEN_ONION_RESPONSE) { log_err(LD_BUG,"writing response buf failed. Exiting."); goto end; } log_debug(LD_OR,"finished writing response."); } } end: if (onion_key) crypto_free_pk_env(onion_key); if (last_onion_key) crypto_free_pk_env(last_onion_key); tor_close_socket(fd); crypto_thread_cleanup(); spawn_exit(); }