Exemple #1
0
/** 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();
}
Exemple #2
0
void scalliontor_readCPUWorkerCallback(int sockd, short ev_types, void * arg) {
	vtor_cpuworker_tp cpuw = arg;

enter:
	SCALLION_CPUWORKER_ASSERT(cpuw);
	if(cpuw->state == CPUW_NONE) {
		cpuw->state = CPUW_V2_READ;
	}

	switch (cpuw->state) {
	case CPUW_V2_READ: {
		size_t req_size = sizeof(cpuworker_request_t);
		char recvbuf[req_size];

		/* read until we have a full request */
		while(cpuw->num_partial_bytes < req_size) {
			memset(recvbuf, 0, req_size);
			size_t bytes_needed = req_size - cpuw->num_partial_bytes;

			int ioResult = recv(cpuw->fd, recvbuf, bytes_needed, 0);
//			int ioResult = recv(cpuw->fd, (&(cpuw->req))+cpuw->offset, bytesNeeded-cpuw->offset, 0);

			ioResult = scalliontor_checkIOResult(cpuw->fd, ioResult);
			if(ioResult < 0) goto end; // error, kill ourself
			else if(ioResult == 0) goto ret; // EAGAIN
			else g_assert(ioResult > 0); // yay

			/* we read some bytes */
			size_t bytes_read = (size_t)ioResult;
			g_assert(bytes_read <= bytes_needed);

			/* copy these bytes into our request buffer */
			gpointer req_loc = (gpointer) &(cpuw->req);
			gpointer req_w_loc = &req_loc[cpuw->num_partial_bytes];

			SCALLION_CPUWORKER_ASSERT(cpuw);
			memcpy(req_w_loc, recvbuf, bytes_read);
			SCALLION_CPUWORKER_ASSERT(cpuw);

			cpuw->num_partial_bytes += bytes_read;
			g_assert(cpuw->num_partial_bytes <= req_size);
		}

		/* we got what we needed, assert this */
		if(cpuw->num_partial_bytes == req_size) {
			/* got full request, process it */
			cpuw->state = CPUW_V2_PROCESS;
			cpuw->num_partial_bytes = 0;
			goto enter;
		} else {
		  log_err(LD_BUG,"read tag failed. Exiting.");
		  goto end;
		}
	}

	case CPUW_V2_PROCESS: {
		tor_assert(cpuw->req.magic == CPUWORKER_REQUEST_MAGIC);

		SCALLION_CPUWORKER_ASSERT(cpuw);
		memset(&(cpuw->rpl), 0, sizeof(cpuworker_reply_t));
		SCALLION_CPUWORKER_ASSERT(cpuw);

		if (cpuw->req.task == CPUWORKER_TASK_ONION) {
			const create_cell_t *cc = &cpuw->req.create_cell;
			created_cell_t *cell_out = &cpuw->rpl.created_cell;
			int n = 0;
#ifdef SCALLION_USEV2CPUWORKERTIMING
			struct timeval tv_start, tv_end;
			cpuw->rpl.timed = cpuw->req.timed;
			cpuw->rpl.started_at = cpuw->req.started_at;
			cpuw->rpl.handshake_type = cc->handshake_type;
			if (cpuw->req.timed)
			  tor_gettimeofday(&tv_start);
#endif
			n = onion_skin_server_handshake(cc->handshake_type, cc->onionskin,
					cc->handshake_len, &cpuw->onion_keys, cell_out->reply,
					cpuw->rpl.keys, CPATH_KEY_MATERIAL_LEN,
					cpuw->rpl.rend_auth_material);
			if (n < 0) {
				/* failure */
				log_debug(LD_OR, "onion_skin_server_handshake failed.");
				memset(&cpuw->rpl, 0, sizeof(cpuworker_reply_t));
				memcpy(cpuw->rpl.tag, cpuw->req.tag, TAG_LEN);
				cpuw->rpl.success = 0;
			} else {
				/* success */
				log_debug(LD_OR, "onion_skin_server_handshake succeeded.");
				memcpy(cpuw->rpl.tag, cpuw->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;
				}
				cpuw->rpl.success = 1;
			}
			cpuw->rpl.magic = CPUWORKER_REPLY_MAGIC;
#ifdef SCALLION_USEV2CPUWORKERTIMING
			if (cpuw->req.timed) {
			  struct timeval tv_diff;
			  tor_gettimeofday(&tv_end);
			  timersub(&tv_end, &tv_start, &tv_diff);
			  int64_t usec = (int64_t)(((int64_t)tv_diff.tv_sec)*1000000 + tv_diff.tv_usec);
/** If any onionskin takes longer than this, we clip them to this
* time. (microseconds) */
#define MAX_BELIEVABLE_ONIONSKIN_DELAY (2*1000*1000)
			  if (usec < 0 || usec > MAX_BELIEVABLE_ONIONSKIN_DELAY)
				cpuw->rpl.n_usec = MAX_BELIEVABLE_ONIONSKIN_DELAY;
			  else
				cpuw->rpl.n_usec = (uint32_t) usec;
			  }
#endif
			/* write response after processing request */
			SCALLION_CPUWORKER_ASSERT(cpuw);
			cpuw->state = CPUW_V2_WRITE;
		} else if (cpuw->req.task == CPUWORKER_TASK_SHUTDOWN) {
			log_info(LD_OR, "Clean shutdown: exiting");
			cpuw->state = CPUW_NONE;
			goto end;
		} else {
			/* dont know the task, just ignore it and start over reading the next */
			cpuw->state = CPUW_V2_RESET;
		}

		goto enter;
	}

	case CPUW_V2_WRITE: {
		size_t rpl_size = sizeof(cpuworker_reply_t);
		char sendbuf[rpl_size];
		memset(sendbuf, 0, rpl_size);

		/* copy reply into send buffer */
		SCALLION_CPUWORKER_ASSERT(cpuw);
		memcpy(sendbuf, (gpointer) &(cpuw->rpl), rpl_size);
		SCALLION_CPUWORKER_ASSERT(cpuw);

		/* write until we wrote it all */
		while(cpuw->num_partial_bytes < rpl_size) {
			size_t bytes_needed = rpl_size - cpuw->num_partial_bytes;
			gpointer rpl_loc = (gpointer) sendbuf;
			gpointer rpl_r_loc = &rpl_loc[cpuw->num_partial_bytes];

			int ioResult = send(cpuw->fd, rpl_r_loc, bytes_needed, 0);

			ioResult = scalliontor_checkIOResult(cpuw->fd, ioResult);
			if(ioResult < 0) goto end; // error, kill ourself
			else if(ioResult == 0) goto ret; // EAGAIN
			else g_assert(ioResult > 0); // yay

			/* we wrote some bytes */
			size_t bytes_written = (size_t)ioResult;
			g_assert(bytes_written <= bytes_needed);

			cpuw->num_partial_bytes += bytes_written;
			g_assert(cpuw->num_partial_bytes <= rpl_size);
		}

		/* we sent what we needed, assert this */
		if(cpuw->num_partial_bytes == rpl_size) {
			/* sent full reply, start over */
			log_debug(LD_OR, "finished writing response.");
			cpuw->state = CPUW_V2_RESET;
			cpuw->num_partial_bytes = 0;
			goto enter;
		} else {
			log_err(LD_BUG,"writing response buf failed. Exiting.");
			goto end;
		}
	}

	case CPUW_V2_RESET: {
		memwipe(&cpuw->req, 0, sizeof(cpuworker_request_t));
		memwipe(&cpuw->rpl, 0, sizeof(cpuworker_reply_t));
		cpuw->state = CPUW_V2_READ;
		cpuw->num_partial_bytes = 0;
		goto enter;
	}
	}

ret:
	return;

end:
	if (cpuw != NULL) {
		memwipe(&cpuw->req, 0, sizeof(cpuw->req));
		memwipe(&cpuw->rpl, 0, sizeof(cpuw->rpl));
		release_server_onion_keys(&cpuw->onion_keys);
		tor_close_socket(cpuw->fd);
		event_del(&(cpuw->read_event));
		memset(cpuw, 0, sizeof(vtor_cpuworker_t));
		free(cpuw);
	}
}