Skip to content
This repository has been archived by the owner. It is now read-only.
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also .

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also .
base repository: Yawning/tor
base: master
head repository: Yawning/tor
compare: feature13737
Checking mergeability… Don’t worry, you can still create the pull request.
  • 3 commits
  • 12 files changed
  • 0 comments
  • 1 contributor
Commits on Nov 16, 2015
Previously it only made sense to initialize the cpu worker code if
the tor was in "Server Mode" since only CREATE cell processing used
said code.

In the bright future, more things will be multithreaded.
Commits on Nov 18, 2015
This uses the cpuworkers to process CREATED/EXTENDED cells.  There is
no fast path for CREATE_FAST because it's extra code and deprecated.
Showing with 431 additions and 114 deletions.
  1. +5 −0 changes/feature13737
  2. +87 −26 src/or/circuitbuild.c
  3. +7 −0 src/or/circuitbuild.h
  4. +5 −3 src/or/circuitlist.c
  5. +5 −10 src/or/command.c
  6. +2 −1 src/or/config.c
  7. +299 −58 src/or/cpuworker.c
  8. +9 −3 src/or/cpuworker.h
  9. +2 −4 src/or/main.c
  10. +1 −1 src/or/onion.c
  11. +9 −4 src/or/or.h
  12. +0 −4 src/or/relay.c
@@ -0,0 +1,5 @@
o Major features (performance):
- Add support for using the thread pool to handle the client side
onion skin processing. This will allow for better server side
performance for Hidden Services that handle large numbers of
clients. Implements feature 13737.
@@ -26,6 +26,7 @@
#include "connection_edge.h"
#include "connection_or.h"
#include "control.h"
#include "cpuworker.h"
#include "directory.h"
#include "entrynodes.h"
#include "main.h"
@@ -49,6 +50,19 @@
#define MIN(a,b) ((a)<(b)?(a):(b))
#endif

/** Type for a linked list of origin circuits that are waiting for a free CPU
* worker to process a waiting onion handshake (client side). */
typedef struct origin_entry_s {
origin_circuit_t *circ;
crypt_path_t *hop;
struct created_cell_t onionskin;
TOR_TAILQ_ENTRY(origin_entry_s) qh;
} origin_entry_t;

/** A tail queue of origin circuits waiting for CPU workers. */
static TOR_TAILQ_HEAD(origin_queue_s, origin_entry_s) origin_queue =
TOR_TAILQ_HEAD_INITIALIZER(origin_queue);

static channel_t * channel_connect_for_circuit(const tor_addr_t *addr,
uint16_t port,
const char *id_digest);
@@ -1246,16 +1260,14 @@ circuit_init_cpath_crypto(crypt_path_t *cpath, const char *key_data,
* (The body of <b>reply</b> varies depending on what sort of handshake
* this is.)
*
* Calculate the appropriate keys and digests, make sure KH is
* correct, and initialize this hop of the cpath.
* Dispatch the handshake off to the cpuworker thread pool.
*
* Return - reason if we want to mark circ for close, else return 0.
*/
int
circuit_finish_handshake(origin_circuit_t *circ,
const created_cell_t *reply)
{
char keys[CPATH_KEY_MATERIAL_LEN];
crypt_path_t *hop;
int rv;

@@ -1275,31 +1287,12 @@ circuit_finish_handshake(origin_circuit_t *circ,
}
tor_assert(hop->state == CPATH_STATE_AWAITING_KEYS);

{
const char *msg = NULL;
if (onion_skin_client_handshake(hop->handshake_state.tag,
&hop->handshake_state,
reply->reply, reply->handshake_len,
(uint8_t*)keys, sizeof(keys),
(uint8_t*)hop->rend_circ_nonce,
&msg) < 0) {
if (msg)
log_warn(LD_CIRC,"onion_skin_client_handshake failed: %s", msg);
return -END_CIRC_REASON_TORPROTOCOL;
}
}

onion_handshake_state_release(&hop->handshake_state);

if (circuit_init_cpath_crypto(hop, keys, 0)<0) {
return -END_CIRC_REASON_TORPROTOCOL;
circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_ONIONSKIN_PENDING);
if ((rv = assign_onionskin_client_to_cpuworker(circ, reply, hop)) < 0) {
log_debug(LD_GENERAL,"Failed to hand off CREATED cell. Closing.");
return - END_CIRC_REASON_RESOURCELIMIT;
}

hop->state = CPATH_STATE_OPEN;
log_info(LD_CIRC,"Finished building circuit hop:");
circuit_log_path(LOG_INFO,LD_CIRC,circ);
control_event_circuit_status(circ, CIRC_EVENT_EXTENDED, 0);

return 0;
}

@@ -2403,3 +2396,71 @@ build_state_get_exit_nickname(cpath_build_state_t *state)
return state->chosen_exit->nickname;
}

/** Add <b>circ</b> to the end of origin_queue. Returns 0 on success, -1 on
* failure. */
int
origin_pending_add(origin_circuit_t *circ,
const struct created_cell_t *onionskin,
crypt_path_t *hop)
{
origin_entry_t *ent;

/* XXX/yawning: Should there be a limit for the max number of pending
* client onionskins, like there is for server?
*/
ent = tor_malloc_zero(sizeof(*ent));
ent->circ = circ;
ent->hop = hop;
memcpy(&ent->onionskin, onionskin, sizeof(*onionskin));

TOR_TAILQ_INSERT_TAIL(&origin_queue, ent, qh);

return 0;
}

/** Remove the highest priority item from origin_queue and return it, or
* return NULL if the queue is empty. The caller is responsible for freeing
* onionskin_out.
*/
origin_circuit_t *
origin_next_task(struct created_cell_t **onionskin_out, crypt_path_t **hop_out)
{

origin_entry_t *ent;
origin_circuit_t *ret;
struct created_cell_t *onionskin;

if (TOR_TAILQ_EMPTY(&origin_queue))
return NULL;

ent = TOR_TAILQ_FIRST(&origin_queue);
ret = ent->circ;
*hop_out = ent->hop;
onionskin = tor_malloc_zero(sizeof(*onionskin));
memcpy(onionskin, &ent->onionskin, sizeof(*onionskin));
*onionskin_out = onionskin;

TOR_TAILQ_REMOVE(&origin_queue, ent, qh);
memwipe(ent, 0, sizeof(*ent));
tor_free(ent);

return ret;
}

void
origin_pending_remove(origin_circuit_t *circ)
{
origin_entry_t *ent;

TOR_TAILQ_FOREACH(ent, &origin_queue, qh) {
if (ent->circ == circ) {
TOR_TAILQ_REMOVE(&origin_queue, ent, qh);
memwipe(ent, 0, sizeof(*ent));
tor_free(ent);
break;
}
}

cpuworker_cancel_circ_handshake(TO_CIRCUIT(circ));
}

@@ -59,6 +59,13 @@ const char *build_state_get_exit_nickname(cpath_build_state_t *state);
const node_t *choose_good_entry_server(uint8_t purpose,
cpath_build_state_t *state);

int origin_pending_add(origin_circuit_t *circ,
const struct created_cell_t *onionskin,
crypt_path_t *hop);
origin_circuit_t *origin_next_task(struct created_cell_t **onionskin_out,
crypt_path_t **hop_out);
void origin_pending_remove(origin_circuit_t *circ);

#ifdef CIRCUITBUILD_PRIVATE
STATIC circid_t get_unique_circ_id_by_chan(channel_t *chan);
#if defined(ENABLE_TOR2WEB_MODE) || defined(TOR_UNIT_TESTS)
@@ -765,6 +765,7 @@ circuit_free(circuit_t *circ)
if (!circ)
return;

should_free = (circ->workqueue_entry == NULL);
if (CIRCUIT_IS_ORIGIN(circ)) {
origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
mem = ocirc;
@@ -801,8 +802,6 @@ circuit_free(circuit_t *circ)
memlen = sizeof(or_circuit_t);
tor_assert(circ->magic == OR_CIRCUIT_MAGIC);

should_free = (ocirc->workqueue_entry == NULL);

crypto_cipher_free(ocirc->p_crypto);
crypto_digest_free(ocirc->p_digest);
crypto_cipher_free(ocirc->n_crypto);
@@ -1753,7 +1752,10 @@ circuit_about_to_free(circuit_t *circ)
int orig_reason = circ->marked_for_close_orig_reason;

if (circ->state == CIRCUIT_STATE_ONIONSKIN_PENDING) {
onion_pending_remove(TO_OR_CIRCUIT(circ));
if (CIRCUIT_IS_ORIGIN(circ))
origin_pending_remove(TO_ORIGIN_CIRCUIT(circ));
else
onion_pending_remove(TO_OR_CIRCUIT(circ));
}
/* If the circuit ever became OPEN, we sent it to the reputation history
* module then. If it isn't OPEN, we send it there now to remember which
@@ -310,7 +310,7 @@ command_process_create_cell(cell_t *cell, channel_t *chan)
/* hand it off to the cpuworkers, and then return. */
if (connection_or_digest_is_known_relay(chan->identity_digest))
rep_hist_note_circuit_handshake_requested(create_cell->handshake_type);
if (assign_onionskin_to_cpuworker(circ, create_cell) < 0) {
if (assign_onionskin_server_to_cpuworker(circ, create_cell) < 0) {
log_debug(LD_GENERAL,"Failed to hand off onionskin. Closing.");
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_RESOURCELIMIT);
return;
@@ -360,8 +360,7 @@ command_process_create_cell(cell_t *cell, channel_t *chan)
* that it's intended for. If we're not the origin of the circuit, package
* the 'created' cell in an 'extended' relay cell and pass it back. If we
* are the origin of the circuit, send it to circuit_finish_handshake() to
* finish processing keys, and then call circuit_send_next_onion_skin() to
* extend to the next hop in the circuit if necessary.
* dispatch the cell to the cpuworker for processing.
*/
static void
command_process_created_cell(cell_t *cell, channel_t *chan)
@@ -395,18 +394,14 @@ command_process_created_cell(cell_t *cell, channel_t *chan)
origin_circuit_t *origin_circ = TO_ORIGIN_CIRCUIT(circ);
int err_reason = 0;
log_debug(LD_OR,"at OP. Finishing handshake.");
/* circuit_finish_handshake() will dispatch the created cell to the
* cpuworker.
*/
if ((err_reason = circuit_finish_handshake(origin_circ,
&extended_cell.created_cell)) < 0) {
circuit_mark_for_close(circ, -err_reason);
return;
}
log_debug(LD_OR,"Moving to next skin.");
if ((err_reason = circuit_send_next_onion_skin(origin_circ)) < 0) {
log_info(LD_OR,"circuit_send_next_onion_skin failed.");
/* XXX push this circuit_close lower */
circuit_mark_for_close(circ, -err_reason);
return;
}
} else { /* pack it into an extended relay cell, and send it. */
uint8_t command=0;
uint16_t len=0;
@@ -1737,8 +1737,9 @@ options_act(const or_options_t *old_options)
log_info(LD_GENERAL,
"Worker-related options changed. Rotating workers.");

cpu_init();

if (server_mode(options) && !server_mode(old_options)) {
cpu_init();
ip_address_changed(0);
if (have_completed_a_circuit() || !any_predicted_circuits(time(NULL)))
inform_testing_reachability();

No commit comments for this range