Back to index

tor  0.2.3.19-rc
Functions | Variables
relay.h File Reference

Header file for relay.c. More...

This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

int circuit_receive_relay_cell (cell_t *cell, circuit_t *circ, cell_direction_t cell_direction)
 Receive a relay cell:
void relay_header_pack (uint8_t *dest, const relay_header_t *src)
 Pack the relay_header_t host-order structure src into network-order in the buffer dest.
void relay_header_unpack (relay_header_t *dest, const uint8_t *src)
 Unpack the network-order buffer src into a host-order relay_header_t structure dest.
int relay_send_command_from_edge (streamid_t stream_id, circuit_t *circ, uint8_t relay_command, const char *payload, size_t payload_len, crypt_path_t *cpath_layer)
 Make a relay cell out of relay_command and payload, and send it onto the open circuit circ.
int connection_edge_send_command (edge_connection_t *fromconn, uint8_t relay_command, const char *payload, size_t payload_len)
 Make a relay cell out of relay_command and payload, and send it onto the open circuit circ.
int connection_edge_package_raw_inbuf (edge_connection_t *conn, int package_partial, int *max_cells)
 If conn has an entire relay payload of bytes on its inbuf (or package_partial is true), and the appropriate package windows aren't empty, grab a cell and send it down the circuit.
void connection_edge_consider_sending_sendme (edge_connection_t *conn)
 Called when we've just received a relay data cell, when we've just finished flushing all bytes to stream conn, or when we've flushed some bytes to the stream conn.
void init_cell_pool (void)
 Allocate structures to hold cells.
void free_cell_pool (void)
 Free all storage used to hold cells (and insertion times if we measure cell statistics).
void clean_cell_pool (void)
 Free excess storage in cell pool.
void dump_cell_pool_usage (int severity)
 Log current statistics for cell pool allocation at log level severity.
void cell_queue_clear (cell_queue_t *queue)
 Remove and free every cell in queue.
void cell_queue_append (cell_queue_t *queue, packed_cell_t *cell)
 Append cell to the end of queue.
void cell_queue_append_packed_copy (cell_queue_t *queue, const cell_t *cell)
 Append a newly allocated copy of cell to the end of queue
void append_cell_to_circuit_queue (circuit_t *circ, or_connection_t *orconn, cell_t *cell, cell_direction_t direction, streamid_t fromstream)
 Add cell to the queue of circ writing to orconn transmitting in direction.
void connection_or_unlink_all_active_circs (or_connection_t *conn)
 Remove all circuits from the list of circuits with pending cells on conn.
int connection_or_flush_from_first_active_circuit (or_connection_t *conn, int max, time_t now)
 Pull as many cells as possible (but no more than max) from the queue of the first active circuit on conn, and write them to conn->outbuf.
void assert_active_circuits_ok (or_connection_t *orconn)
 Fail with an assert if the active circuits ring on orconn is corrupt.
void make_circuit_inactive_on_conn (circuit_t *circ, or_connection_t *conn)
 Remove circ from the list of circuits with pending cells on conn.
void make_circuit_active_on_conn (circuit_t *circ, or_connection_t *conn)
 Add circ to the list of circuits with pending cells on conn.
int append_address_to_payload (uint8_t *payload_out, const tor_addr_t *addr)
 Append an encoded value of addr to payload_out, which must have at least 18 bytes of free space.
const uint8_t * decode_address_from_payload (tor_addr_t *addr_out, const uint8_t *payload, int payload_len)
 Given payload_len bytes at payload, starting with an address encoded as by append_address_to_payload(), try to decode the address into *addr_out.
unsigned cell_ewma_get_tick (void)
 Compute and return the current cell_ewma tick.
void cell_ewma_set_scale_factor (const or_options_t *options, const networkstatus_t *consensus)
 Adjust the global cell scale factor based on options
void circuit_clear_cell_queue (circuit_t *circ, or_connection_t *orconn)
 Remove all the cells queued on circ for orconn.

Variables

uint64_t stats_n_relay_cells_relayed
 Stats: how many relay cells have originated at this hop, or have been relayed onward (not recognized at this hop)?
uint64_t stats_n_relay_cells_delivered
 Stats: how many relay cells have been delivered to streams at this hop?
uint64_t stats_n_data_cells_packaged
 How many relay_data cells have we built, ever?
uint64_t stats_n_data_bytes_packaged
 How many bytes of data have we put in relay_data cells have we built, ever? This would be RELAY_PAYLOAD_SIZE*stats_n_data_cells_packaged if every relay cell we ever sent were completely full of data.
uint64_t stats_n_data_cells_received
 How many relay_data cells have we received, ever?
uint64_t stats_n_data_bytes_received
 How many bytes of data have we received relay_data cells, ever? This would be RELAY_PAYLOAD_SIZE*stats_n_data_cells_packaged if every relay cell we ever received were completely full of data.

Detailed Description

Header file for relay.c.

Definition in file relay.h.


Function Documentation

int append_address_to_payload ( uint8_t *  payload_out,
const tor_addr_t addr 
)

Append an encoded value of addr to payload_out, which must have at least 18 bytes of free space.

The encoding is, as specified in tor-spec.txt: RESOLVED_TYPE_IPV4 or RESOLVED_TYPE_IPV6 [1 byte] LENGTH [1 byte] ADDRESS [length bytes] Return the number of bytes added, or -1 on error

Definition at line 2555 of file relay.c.

{
  uint32_t a;
  switch (tor_addr_family(addr)) {
  case AF_INET:
    payload_out[0] = RESOLVED_TYPE_IPV4;
    payload_out[1] = 4;
    a = tor_addr_to_ipv4n(addr);
    memcpy(payload_out+2, &a, 4);
    return 6;
  case AF_INET6:
    payload_out[0] = RESOLVED_TYPE_IPV6;
    payload_out[1] = 16;
    memcpy(payload_out+2, tor_addr_to_in6_addr8(addr), 16);
    return 18;
  case AF_UNSPEC:
  default:
    return -1;
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void append_cell_to_circuit_queue ( circuit_t circ,
or_connection_t orconn,
cell_t cell,
cell_direction_t  direction,
streamid_t  fromstream 
)

Add cell to the queue of circ writing to orconn transmitting in direction.

Definition at line 2500 of file relay.c.

{
  cell_queue_t *queue;
  int streams_blocked;
  if (circ->marked_for_close)
    return;

  if (direction == CELL_DIRECTION_OUT) {
    queue = &circ->n_conn_cells;
    streams_blocked = circ->streams_blocked_on_n_conn;
  } else {
    or_circuit_t *orcirc = TO_OR_CIRCUIT(circ);
    queue = &orcirc->p_conn_cells;
    streams_blocked = circ->streams_blocked_on_p_conn;
  }

  cell_queue_append_packed_copy(queue, cell);

  /* If we have too many cells on the circuit, we should stop reading from
   * the edge streams for a while. */
  if (!streams_blocked && queue->n >= CELL_QUEUE_HIGHWATER_SIZE)
    set_streams_blocked_on_circ(circ, orconn, 1, 0); /* block streams */

  if (streams_blocked && fromstream) {
    /* This edge connection is apparently not blocked; block it. */
    set_streams_blocked_on_circ(circ, orconn, 1, fromstream);
  }

  if (queue->n == 1) {
    /* This was the first cell added to the queue.  We need to make this
     * circuit active. */
    log_debug(LD_GENERAL, "Made a circuit active.");
    make_circuit_active_on_conn(circ, orconn);
  }

  if (! connection_get_outbuf_len(TO_CONN(orconn))) {
    /* There is no data at all waiting to be sent on the outbuf.  Add a
     * cell, so that we can notice when it gets flushed, flushed_some can
     * get called, and we can start putting more data onto the buffer then.
     */
    log_debug(LD_GENERAL, "Primed a buffer.");
    connection_or_flush_from_first_active_circuit(orconn, 1, approx_time());
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

Fail with an assert if the active circuits ring on orconn is corrupt.

Definition at line 2629 of file relay.c.

{
  circuit_t *head = orconn->active_circuits;
  circuit_t *cur = head;
  int n = 0;
  if (! head)
    return;
  do {
    circuit_t *next = *next_circ_on_conn_p(cur, orconn);
    circuit_t *prev = *prev_circ_on_conn_p(cur, orconn);
    cell_ewma_t *ewma;
    tor_assert(next);
    tor_assert(prev);
    tor_assert(*next_circ_on_conn_p(prev, orconn) == cur);
    tor_assert(*prev_circ_on_conn_p(next, orconn) == cur);
    if (orconn == cur->n_conn) {
      ewma = &cur->n_cell_ewma;
      tor_assert(!ewma->is_for_p_conn);
    } else {
      ewma = &TO_OR_CIRCUIT(cur)->p_cell_ewma;
      tor_assert(ewma->is_for_p_conn);
    }
    tor_assert(ewma->heap_index != -1);
    tor_assert(ewma == smartlist_get(orconn->active_circuit_pqueue,
                                     ewma->heap_index));
    n++;
    cur = next;
  } while (cur != head);

  tor_assert(n == smartlist_len(orconn->active_circuit_pqueue));
}

Here is the call graph for this function:

unsigned cell_ewma_get_tick ( void  )

Compute and return the current cell_ewma tick.

Definition at line 2068 of file relay.c.

{
  return ((unsigned)approx_time() / EWMA_TICK_LEN);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void cell_ewma_set_scale_factor ( const or_options_t options,
const networkstatus_t consensus 
)

Adjust the global cell scale factor based on options

Definition at line 2088 of file relay.c.

{
  int32_t halflife_ms;
  double halflife;
  const char *source;
  if (options && options->CircuitPriorityHalflife >= -EPSILON) {
    halflife = options->CircuitPriorityHalflife;
    source = "CircuitPriorityHalflife in configuration";
  } else if (consensus && (halflife_ms = networkstatus_get_param(
                 consensus, "CircuitPriorityHalflifeMsec",
                 -1, -1, INT32_MAX)) >= 0) {
    halflife = ((double)halflife_ms)/1000.0;
    source = "CircuitPriorityHalflifeMsec in consensus";
  } else {
    halflife = EWMA_DEFAULT_HALFLIFE;
    source = "Default value";
  }

  if (halflife <= EPSILON) {
    /* The cell EWMA algorithm is disabled. */
    ewma_scale_factor = 0.1;
    ewma_enabled = 0;
    log_info(LD_OR,
             "Disabled cell_ewma algorithm because of value in %s",
             source);
  } else {
    /* convert halflife into halflife-per-tick. */
    halflife /= EWMA_TICK_LEN;
    /* compute per-tick scale factor. */
    ewma_scale_factor = exp( LOG_ONEHALF / halflife );
    ewma_enabled = 1;
    log_info(LD_OR,
             "Enabled cell_ewma algorithm because of value in %s; "
             "scale factor is %f per %d seconds",
             source, ewma_scale_factor, EWMA_TICK_LEN);
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void cell_queue_append ( cell_queue_t queue,
packed_cell_t cell 
)

Append cell to the end of queue.

Definition at line 1859 of file relay.c.

{
  if (queue->tail) {
    tor_assert(!queue->tail->next);
    queue->tail->next = cell;
  } else {
    queue->head = cell;
  }
  queue->tail = cell;
  cell->next = NULL;
  ++queue->n;
}

Here is the caller graph for this function:

void cell_queue_append_packed_copy ( cell_queue_t queue,
const cell_t cell 
)

Append a newly allocated copy of cell to the end of queue

Definition at line 1874 of file relay.c.

{
  packed_cell_t *copy = packed_cell_copy(cell);
  /* Remember the time when this cell was put in the queue. */
  if (get_options()->CellStatistics) {
    struct timeval now;
    uint32_t added;
    insertion_time_queue_t *it_queue = queue->insertion_times;
    if (!it_pool)
      it_pool = mp_pool_new(sizeof(insertion_time_elem_t), 1024);
    tor_gettimeofday_cached(&now);
#define SECONDS_IN_A_DAY 86400L
    added = (uint32_t)(((now.tv_sec % SECONDS_IN_A_DAY) * 100L)
            + ((uint32_t)now.tv_usec / (uint32_t)10000L));
    if (!it_queue) {
      it_queue = tor_malloc_zero(sizeof(insertion_time_queue_t));
      queue->insertion_times = it_queue;
    }
    if (it_queue->last && it_queue->last->insertion_time == added) {
      it_queue->last->counter++;
    } else {
      insertion_time_elem_t *elem = mp_pool_get(it_pool);
      elem->next = NULL;
      elem->insertion_time = added;
      elem->counter = 1;
      if (it_queue->last) {
        it_queue->last->next = elem;
        it_queue->last = elem;
      } else {
        it_queue->first = it_queue->last = elem;
      }
    }
  }
  cell_queue_append(queue, copy);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void cell_queue_clear ( cell_queue_t queue)

Remove and free every cell in queue.

Definition at line 1912 of file relay.c.

{
  packed_cell_t *cell, *next;
  cell = queue->head;
  while (cell) {
    next = cell->next;
    packed_cell_free_unchecked(cell);
    cell = next;
  }
  queue->head = queue->tail = NULL;
  queue->n = 0;
  if (queue->insertion_times) {
    while (queue->insertion_times->first) {
      insertion_time_elem_t *elem = queue->insertion_times->first;
      queue->insertion_times->first = elem->next;
      mp_pool_release(elem);
    }
    tor_free(queue->insertion_times);
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void circuit_clear_cell_queue ( circuit_t circ,
or_connection_t orconn 
)

Remove all the cells queued on circ for orconn.

Definition at line 2609 of file relay.c.

{
  cell_queue_t *queue;
  if (circ->n_conn == orconn) {
    queue = &circ->n_conn_cells;
  } else {
    or_circuit_t *orcirc = TO_OR_CIRCUIT(circ);
    tor_assert(orcirc->p_conn == orconn);
    queue = &orcirc->p_conn_cells;
  }

  if (queue->n)
    make_circuit_inactive_on_conn(circ,orconn);

  cell_queue_clear(queue);
}

Here is the call graph for this function:

Here is the caller graph for this function:

int circuit_receive_relay_cell ( cell_t cell,
circuit_t circ,
cell_direction_t  cell_direction 
)

Receive a relay cell:

  • Crypt it (encrypt if headed toward the origin or if we are the origin; decrypt if we're headed toward the exit).
  • Check if recognized (if exitward).
  • If recognized and the digest checks out, then find if there's a stream that the cell is intended for, and deliver it to the right connection_edge.
  • If not recognized, then we need to relay it: append it to the appropriate cell_queue on circ.

Return -reason on failure.

Definition at line 166 of file relay.c.

{
  or_connection_t *or_conn=NULL;
  crypt_path_t *layer_hint=NULL;
  char recognized=0;
  int reason;

  tor_assert(cell);
  tor_assert(circ);
  tor_assert(cell_direction == CELL_DIRECTION_OUT ||
             cell_direction == CELL_DIRECTION_IN);
  if (circ->marked_for_close)
    return 0;

  if (relay_crypt(circ, cell, cell_direction, &layer_hint, &recognized) < 0) {
    log_warn(LD_BUG,"relay crypt failed. Dropping connection.");
    return -END_CIRC_REASON_INTERNAL;
  }

  if (recognized) {
    edge_connection_t *conn = relay_lookup_conn(circ, cell, cell_direction,
                                                layer_hint);
    if (cell_direction == CELL_DIRECTION_OUT) {
      ++stats_n_relay_cells_delivered;
      log_debug(LD_OR,"Sending away from origin.");
      if ((reason=connection_edge_process_relay_cell(cell, circ, conn, NULL))
          < 0) {
        log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
               "connection_edge_process_relay_cell (away from origin) "
               "failed.");
        return reason;
      }
    }
    if (cell_direction == CELL_DIRECTION_IN) {
      ++stats_n_relay_cells_delivered;
      log_debug(LD_OR,"Sending to origin.");
      if ((reason = connection_edge_process_relay_cell(cell, circ, conn,
                                                       layer_hint)) < 0) {
        log_warn(LD_OR,
                 "connection_edge_process_relay_cell (at origin) failed.");
        return reason;
      }
    }
    return 0;
  }

  /* not recognized. pass it on. */
  if (cell_direction == CELL_DIRECTION_OUT) {
    cell->circ_id = circ->n_circ_id; /* switch it */
    or_conn = circ->n_conn;
  } else if (! CIRCUIT_IS_ORIGIN(circ)) {
    cell->circ_id = TO_OR_CIRCUIT(circ)->p_circ_id; /* switch it */
    or_conn = TO_OR_CIRCUIT(circ)->p_conn;
  } else {
    log_fn(LOG_PROTOCOL_WARN, LD_OR,
           "Dropping unrecognized inbound cell on origin circuit.");
    return 0;
  }

  if (!or_conn) {
    // XXXX Can this splice stuff be done more cleanly?
    if (! CIRCUIT_IS_ORIGIN(circ) &&
        TO_OR_CIRCUIT(circ)->rend_splice &&
        cell_direction == CELL_DIRECTION_OUT) {
      or_circuit_t *splice = TO_OR_CIRCUIT(circ)->rend_splice;
      tor_assert(circ->purpose == CIRCUIT_PURPOSE_REND_ESTABLISHED);
      tor_assert(splice->_base.purpose == CIRCUIT_PURPOSE_REND_ESTABLISHED);
      cell->circ_id = splice->p_circ_id;
      cell->command = CELL_RELAY; /* can't be relay_early anyway */
      if ((reason = circuit_receive_relay_cell(cell, TO_CIRCUIT(splice),
                                               CELL_DIRECTION_IN)) < 0) {
        log_warn(LD_REND, "Error relaying cell across rendezvous; closing "
                 "circuits");
        /* XXXX Do this here, or just return -1? */
        circuit_mark_for_close(circ, -reason);
        return reason;
      }
      return 0;
    }
    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
           "Didn't recognize cell, but circ stops here! Closing circ.");
    return -END_CIRC_REASON_TORPROTOCOL;
  }

  log_debug(LD_OR,"Passing on unrecognized cell.");

  ++stats_n_relay_cells_relayed; /* XXXX no longer quite accurate {cells}
                                  * we might kill the circ before we relay
                                  * the cells. */

  append_cell_to_circuit_queue(circ, or_conn, cell, cell_direction, 0);
  return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void clean_cell_pool ( void  )

Free excess storage in cell pool.

Definition at line 1806 of file relay.c.

Here is the call graph for this function:

Here is the caller graph for this function:

Called when we've just received a relay data cell, when we've just finished flushing all bytes to stream conn, or when we've flushed some bytes to the stream conn.

If conn->outbuf is not too full, and our deliver window is low, send back a suitable number of stream-level sendme cells.

Definition at line 1509 of file relay.c.

{
  circuit_t *circ;

  if (connection_outbuf_too_full(TO_CONN(conn)))
    return;

  circ = circuit_get_by_edge_conn(conn);
  if (!circ) {
    /* this can legitimately happen if the destroy has already
     * arrived and torn down the circuit */
    log_info(LD_APP,"No circuit associated with conn. Skipping.");
    return;
  }

  while (conn->deliver_window <= STREAMWINDOW_START - STREAMWINDOW_INCREMENT) {
    log_debug(conn->_base.type == CONN_TYPE_AP ?LD_APP:LD_EXIT,
              "Outbuf %d, Queuing stream sendme.",
              (int)conn->_base.outbuf_flushlen);
    conn->deliver_window += STREAMWINDOW_INCREMENT;
    if (connection_edge_send_command(conn, RELAY_COMMAND_SENDME,
                                     NULL, 0) < 0) {
      log_warn(LD_APP,"connection_edge_send_command failed. Skipping.");
      return; /* the circuit's closed, don't continue */
    }
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

int connection_edge_package_raw_inbuf ( edge_connection_t conn,
int  package_partial,
int *  max_cells 
)

If conn has an entire relay payload of bytes on its inbuf (or package_partial is true), and the appropriate package windows aren't empty, grab a cell and send it down the circuit.

If *max_cells is given, package no more than max_cells. Decrement *max_cells by the number of cells packaged.

Return -1 (and send a RELAY_COMMAND_END cell if necessary) if conn should be marked for close, else return 0.

Definition at line 1372 of file relay.c.

{
  size_t bytes_to_process, length;
  char payload[CELL_PAYLOAD_SIZE];
  circuit_t *circ;
  const unsigned domain = conn->_base.type == CONN_TYPE_AP ? LD_APP : LD_EXIT;
  int sending_from_optimistic = 0;
  const int sending_optimistically =
    conn->_base.type == CONN_TYPE_AP &&
    conn->_base.state != AP_CONN_STATE_OPEN;
  entry_connection_t *entry_conn =
    conn->_base.type == CONN_TYPE_AP ? EDGE_TO_ENTRY_CONN(conn) : NULL;
  crypt_path_t *cpath_layer = conn->cpath_layer;

  tor_assert(conn);

  if (conn->_base.marked_for_close) {
    log_warn(LD_BUG,
             "called on conn that's already marked for close at %s:%d.",
             conn->_base.marked_for_close_file, conn->_base.marked_for_close);
    return 0;
  }

  if (max_cells && *max_cells <= 0)
    return 0;

 repeat_connection_edge_package_raw_inbuf:

  circ = circuit_get_by_edge_conn(conn);
  if (!circ) {
    log_info(domain,"conn has no circuit! Closing.");
    conn->end_reason = END_STREAM_REASON_CANT_ATTACH;
    return -1;
  }

  if (circuit_consider_stop_edge_reading(circ, cpath_layer))
    return 0;

  if (conn->package_window <= 0) {
    log_info(domain,"called with package_window %d. Skipping.",
             conn->package_window);
    connection_stop_reading(TO_CONN(conn));
    return 0;
  }

  sending_from_optimistic = entry_conn &&
    entry_conn->sending_optimistic_data != NULL;

  if (PREDICT_UNLIKELY(sending_from_optimistic)) {
    bytes_to_process = generic_buffer_len(entry_conn->sending_optimistic_data);
    if (PREDICT_UNLIKELY(!bytes_to_process)) {
      log_warn(LD_BUG, "sending_optimistic_data was non-NULL but empty");
      bytes_to_process = connection_get_inbuf_len(TO_CONN(conn));
      sending_from_optimistic = 0;
    }
  } else {
    bytes_to_process = connection_get_inbuf_len(TO_CONN(conn));
  }

  if (!bytes_to_process)
    return 0;

  if (!package_partial && bytes_to_process < RELAY_PAYLOAD_SIZE)
    return 0;

  if (bytes_to_process > RELAY_PAYLOAD_SIZE) {
    length = RELAY_PAYLOAD_SIZE;
  } else {
    length = bytes_to_process;
  }
  stats_n_data_bytes_packaged += length;
  stats_n_data_cells_packaged += 1;

  if (PREDICT_UNLIKELY(sending_from_optimistic)) {
    /* XXXX We could be more efficient here by sometimes packing
     * previously-sent optimistic data in the same cell with data
     * from the inbuf. */
    generic_buffer_get(entry_conn->sending_optimistic_data, payload, length);
    if (!generic_buffer_len(entry_conn->sending_optimistic_data)) {
        generic_buffer_free(entry_conn->sending_optimistic_data);
        entry_conn->sending_optimistic_data = NULL;
    }
  } else {
    connection_fetch_from_buf(payload, length, TO_CONN(conn));
  }

  log_debug(domain,"(%d) Packaging %d bytes (%d waiting).", conn->_base.s,
            (int)length, (int)connection_get_inbuf_len(TO_CONN(conn)));

  if (sending_optimistically && !sending_from_optimistic) {
    /* This is new optimistic data; remember it in case we need to detach and
       retry */
    if (!entry_conn->pending_optimistic_data)
      entry_conn->pending_optimistic_data = generic_buffer_new();
    generic_buffer_add(entry_conn->pending_optimistic_data, payload, length);
  }

  if (connection_edge_send_command(conn, RELAY_COMMAND_DATA,
                                   payload, length) < 0 )
    /* circuit got marked for close, don't continue, don't need to mark conn */
    return 0;

  if (!cpath_layer) { /* non-rendezvous exit */
    tor_assert(circ->package_window > 0);
    circ->package_window--;
  } else { /* we're an AP, or an exit on a rendezvous circ */
    tor_assert(cpath_layer->package_window > 0);
    cpath_layer->package_window--;
  }

  if (--conn->package_window <= 0) { /* is it 0 after decrement? */
    connection_stop_reading(TO_CONN(conn));
    log_debug(domain,"conn->package_window reached 0.");
    circuit_consider_stop_edge_reading(circ, cpath_layer);
    return 0; /* don't process the inbuf any more */
  }
  log_debug(domain,"conn->package_window is now %d",conn->package_window);

  if (max_cells) {
    *max_cells -= 1;
    if (*max_cells <= 0)
      return 0;
  }

  /* handle more if there's more, or return 0 if there isn't */
  goto repeat_connection_edge_package_raw_inbuf;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int connection_edge_send_command ( edge_connection_t fromconn,
uint8_t  relay_command,
const char *  payload,
size_t  payload_len 
)

Make a relay cell out of relay_command and payload, and send it onto the open circuit circ.

fromconn is the stream that's sending the relay cell, or NULL if it's a control cell. cpath_layer is NULL for OR->OP cells, or the destination hop for OP->OR cells.

If you can't send the cell, mark the circuit for close and return -1. Else return 0.

Definition at line 624 of file relay.c.

{
  /* XXXX NM Split this function into a separate versions per circuit type? */
  circuit_t *circ;
  crypt_path_t *cpath_layer = fromconn->cpath_layer;
  tor_assert(fromconn);
  circ = fromconn->on_circuit;

  if (fromconn->_base.marked_for_close) {
    log_warn(LD_BUG,
             "called on conn that's already marked for close at %s:%d.",
             fromconn->_base.marked_for_close_file,
             fromconn->_base.marked_for_close);
    return 0;
  }

  if (!circ) {
    if (fromconn->_base.type == CONN_TYPE_AP) {
      log_info(LD_APP,"no circ. Closing conn.");
      connection_mark_unattached_ap(EDGE_TO_ENTRY_CONN(fromconn),
                                    END_STREAM_REASON_INTERNAL);
    } else {
      log_info(LD_EXIT,"no circ. Closing conn.");
      fromconn->edge_has_sent_end = 1; /* no circ to send to */
      fromconn->end_reason = END_STREAM_REASON_INTERNAL;
      connection_mark_for_close(TO_CONN(fromconn));
    }
    return -1;
  }

  return relay_send_command_from_edge(fromconn->stream_id, circ,
                                      relay_command, payload,
                                      payload_len, cpath_layer);
}

Here is the call graph for this function:

Here is the caller graph for this function:

int connection_or_flush_from_first_active_circuit ( or_connection_t conn,
int  max,
time_t  now 
)

Pull as many cells as possible (but no more than max) from the queue of the first active circuit on conn, and write them to conn->outbuf.

Return the number of cells written. Advance the active circuit pointer to the next active circuit in the ring.

Definition at line 2364 of file relay.c.

{
  int n_flushed;
  cell_queue_t *queue;
  circuit_t *circ;
  int streams_blocked;

  /* The current (hi-res) time */
  struct timeval now_hires;

  /* The EWMA cell counter for the circuit we're flushing. */
  cell_ewma_t *cell_ewma = NULL;
  double ewma_increment = -1;

  circ = conn->active_circuits;
  if (!circ) return 0;
  assert_active_circuits_ok_paranoid(conn);

  /* See if we're doing the ewma circuit selection algorithm. */
  if (ewma_enabled) {
    unsigned tick;
    double fractional_tick;
    tor_gettimeofday_cached(&now_hires);
    tick = cell_ewma_tick_from_timeval(&now_hires, &fractional_tick);

    if (tick != conn->active_circuit_pqueue_last_recalibrated) {
      scale_active_circuits(conn, tick);
    }

    ewma_increment = pow(ewma_scale_factor, -fractional_tick);

    cell_ewma = smartlist_get(conn->active_circuit_pqueue, 0);
    circ = cell_ewma_to_circuit(cell_ewma);
  }

  if (circ->n_conn == conn) {
    queue = &circ->n_conn_cells;
    streams_blocked = circ->streams_blocked_on_n_conn;
  } else {
    queue = &TO_OR_CIRCUIT(circ)->p_conn_cells;
    streams_blocked = circ->streams_blocked_on_p_conn;
  }
  tor_assert(*next_circ_on_conn_p(circ,conn));

  for (n_flushed = 0; n_flushed < max && queue->head; ) {
    packed_cell_t *cell = cell_queue_pop(queue);
    tor_assert(*next_circ_on_conn_p(circ,conn));

    /* Calculate the exact time that this cell has spent in the queue. */
    if (get_options()->CellStatistics && !CIRCUIT_IS_ORIGIN(circ)) {
      struct timeval tvnow;
      uint32_t flushed;
      uint32_t cell_waiting_time;
      insertion_time_queue_t *it_queue = queue->insertion_times;
      tor_gettimeofday_cached(&tvnow);
      flushed = (uint32_t)((tvnow.tv_sec % SECONDS_IN_A_DAY) * 100L +
                 (uint32_t)tvnow.tv_usec / (uint32_t)10000L);
      if (!it_queue || !it_queue->first) {
        log_info(LD_GENERAL, "Cannot determine insertion time of cell. "
                             "Looks like the CellStatistics option was "
                             "recently enabled.");
      } else {
        or_circuit_t *orcirc = TO_OR_CIRCUIT(circ);
        insertion_time_elem_t *elem = it_queue->first;
        cell_waiting_time =
            (uint32_t)((flushed * 10L + SECONDS_IN_A_DAY * 1000L -
                        elem->insertion_time * 10L) %
                       (SECONDS_IN_A_DAY * 1000L));
#undef SECONDS_IN_A_DAY
        elem->counter--;
        if (elem->counter < 1) {
          it_queue->first = elem->next;
          if (elem == it_queue->last)
            it_queue->last = NULL;
          mp_pool_release(elem);
        }
        orcirc->total_cell_waiting_time += cell_waiting_time;
        orcirc->processed_cells++;
      }
    }

    /* If we just flushed our queue and this circuit is used for a
     * tunneled directory request, possibly advance its state. */
    if (queue->n == 0 && TO_CONN(conn)->dirreq_id)
      geoip_change_dirreq_state(TO_CONN(conn)->dirreq_id,
                                DIRREQ_TUNNELED,
                                DIRREQ_CIRC_QUEUE_FLUSHED);

    connection_write_to_buf(cell->body, CELL_NETWORK_SIZE, TO_CONN(conn));

    packed_cell_free_unchecked(cell);
    ++n_flushed;
    if (cell_ewma) {
      cell_ewma_t *tmp;
      cell_ewma->cell_count += ewma_increment;
      /* We pop and re-add the cell_ewma_t here, not above, since we need to
       * re-add it immediately to keep the priority queue consistent with
       * the linked-list implementation */
      tmp = pop_first_cell_ewma_from_conn(conn);
      tor_assert(tmp == cell_ewma);
      add_cell_ewma_to_conn(conn, cell_ewma);
    }
    if (circ != conn->active_circuits) {
      /* If this happens, the current circuit just got made inactive by
       * a call in connection_write_to_buf().  That's nothing to worry about:
       * circuit_make_inactive_on_conn() already advanced conn->active_circuits
       * for us.
       */
      assert_active_circuits_ok_paranoid(conn);
      goto done;
    }
  }
  tor_assert(*next_circ_on_conn_p(circ,conn));
  assert_active_circuits_ok_paranoid(conn);
  conn->active_circuits = *next_circ_on_conn_p(circ, conn);

  /* Is the cell queue low enough to unblock all the streams that are waiting
   * to write to this circuit? */
  if (streams_blocked && queue->n <= CELL_QUEUE_LOWWATER_SIZE)
    set_streams_blocked_on_circ(circ, conn, 0, 0); /* unblock streams */

  /* Did we just run out of cells on this circuit's queue? */
  if (queue->n == 0) {
    log_debug(LD_GENERAL, "Made a circuit inactive.");
    make_circuit_inactive_on_conn(circ, conn);
  }
 done:
  if (n_flushed)
    conn->timestamp_last_added_nonpadding = now;
  return n_flushed;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Remove all circuits from the list of circuits with pending cells on conn.

Definition at line 2286 of file relay.c.

{
  circuit_t *head = orconn->active_circuits;
  circuit_t *cur = head;
  if (! head)
    return;
  do {
    circuit_t *next = *next_circ_on_conn_p(cur, orconn);
    *prev_circ_on_conn_p(cur, orconn) = NULL;
    *next_circ_on_conn_p(cur, orconn) = NULL;
    cur = next;
  } while (cur != head);
  orconn->active_circuits = NULL;

  SMARTLIST_FOREACH(orconn->active_circuit_pqueue, cell_ewma_t *, e,
                    e->heap_index = -1);
  smartlist_clear(orconn->active_circuit_pqueue);
}

Here is the call graph for this function:

Here is the caller graph for this function:

const uint8_t* decode_address_from_payload ( tor_addr_t addr_out,
const uint8_t *  payload,
int  payload_len 
)

Given payload_len bytes at payload, starting with an address encoded as by append_address_to_payload(), try to decode the address into *addr_out.

Return the next byte in the payload after the address on success, or NULL on failure.

Definition at line 2581 of file relay.c.

{
  if (payload_len < 2)
    return NULL;
  if (payload_len < 2+payload[1])
    return NULL;

  switch (payload[0]) {
  case RESOLVED_TYPE_IPV4:
    if (payload[1] != 4)
      return NULL;
    tor_addr_from_ipv4n(addr_out, get_uint32(payload+2));
    break;
  case RESOLVED_TYPE_IPV6:
    if (payload[1] != 16)
      return NULL;
    tor_addr_from_ipv6_bytes(addr_out, (char*)(payload+2));
    break;
  default:
    tor_addr_make_unspec(addr_out);
    break;
  }
  return payload + 2 + payload[1];
}

Here is the call graph for this function:

Here is the caller graph for this function:

void dump_cell_pool_usage ( int  severity)

Log current statistics for cell pool allocation at log level severity.

Definition at line 1831 of file relay.c.

{
  circuit_t *c;
  int n_circs = 0;
  int n_cells = 0;
  for (c = _circuit_get_global_list(); c; c = c->next) {
    n_cells += c->n_conn_cells.n;
    if (!CIRCUIT_IS_ORIGIN(c))
      n_cells += TO_OR_CIRCUIT(c)->p_conn_cells.n;
    ++n_circs;
  }
  log(severity, LD_MM, "%d cells allocated on %d circuits. %d cells leaked.",
      n_cells, n_circs, total_cells_allocated - n_cells);
  mp_pool_log_status(cell_pool, severity);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void free_cell_pool ( void  )

Free all storage used to hold cells (and insertion times if we measure cell statistics).

Definition at line 1791 of file relay.c.

{
  /* Maybe we haven't called init_cell_pool yet; need to check for it. */
  if (cell_pool) {
    mp_pool_destroy(cell_pool);
    cell_pool = NULL;
  }
  if (it_pool) {
    mp_pool_destroy(it_pool);
    it_pool = NULL;
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void init_cell_pool ( void  )

Allocate structures to hold cells.

Definition at line 1782 of file relay.c.

Here is the call graph for this function:

Here is the caller graph for this function:

void make_circuit_active_on_conn ( circuit_t circ,
or_connection_t conn 
)

Add circ to the list of circuits with pending cells on conn.

No effect if circ is already linked.

Definition at line 2207 of file relay.c.

{
  circuit_t **nextp = next_circ_on_conn_p(circ, conn);
  circuit_t **prevp = prev_circ_on_conn_p(circ, conn);

  if (*nextp && *prevp) {
    /* Already active. */
    return;
  }

  assert_active_circuits_ok_paranoid(conn);

  if (! conn->active_circuits) {
    conn->active_circuits = circ;
    *prevp = *nextp = circ;
  } else {
    circuit_t *head = conn->active_circuits;
    circuit_t *old_tail = *prev_circ_on_conn_p(head, conn);
    *next_circ_on_conn_p(old_tail, conn) = circ;
    *nextp = head;
    *prev_circ_on_conn_p(head, conn) = circ;
    *prevp = old_tail;
  }

  if (circ->n_conn == conn) {
    add_cell_ewma_to_conn(conn, &circ->n_cell_ewma);
  } else {
    or_circuit_t *orcirc = TO_OR_CIRCUIT(circ);
    tor_assert(conn == orcirc->p_conn);
    add_cell_ewma_to_conn(conn, &orcirc->p_cell_ewma);
  }

  assert_active_circuits_ok_paranoid(conn);
}

Here is the call graph for this function:

Here is the caller graph for this function:

Remove circ from the list of circuits with pending cells on conn.

No effect if circ is already unlinked.

Definition at line 2245 of file relay.c.

{
  circuit_t **nextp = next_circ_on_conn_p(circ, conn);
  circuit_t **prevp = prev_circ_on_conn_p(circ, conn);
  circuit_t *next = *nextp, *prev = *prevp;

  if (!next && !prev) {
    /* Already inactive. */
    return;
  }

  assert_active_circuits_ok_paranoid(conn);

  tor_assert(next && prev);
  tor_assert(*prev_circ_on_conn_p(next, conn) == circ);
  tor_assert(*next_circ_on_conn_p(prev, conn) == circ);

  if (next == circ) {
    conn->active_circuits = NULL;
  } else {
    *prev_circ_on_conn_p(next, conn) = prev;
    *next_circ_on_conn_p(prev, conn) = next;
    if (conn->active_circuits == circ)
      conn->active_circuits = next;
  }
  *prevp = *nextp = NULL;

  if (circ->n_conn == conn) {
    remove_cell_ewma_from_conn(conn, &circ->n_cell_ewma);
  } else {
    or_circuit_t *orcirc = TO_OR_CIRCUIT(circ);
    tor_assert(conn == orcirc->p_conn);
    remove_cell_ewma_from_conn(conn, &orcirc->p_cell_ewma);
  }

  assert_active_circuits_ok_paranoid(conn);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void relay_header_pack ( uint8_t *  dest,
const relay_header_t src 
)

Pack the relay_header_t host-order structure src into network-order in the buffer dest.

See tor-spec.txt for details about the wire format.

Definition at line 459 of file relay.c.

{
  set_uint8(dest, src->command);
  set_uint16(dest+1, htons(src->recognized));
  set_uint16(dest+3, htons(src->stream_id));
  memcpy(dest+5, src->integrity, 4);
  set_uint16(dest+9, htons(src->length));
}

Here is the call graph for this function:

Here is the caller graph for this function:

void relay_header_unpack ( relay_header_t dest,
const uint8_t *  src 
)

Unpack the network-order buffer src into a host-order relay_header_t structure dest.

Definition at line 472 of file relay.c.

{
  dest->command = get_uint8(src);
  dest->recognized = ntohs(get_uint16(src+1));
  dest->stream_id = ntohs(get_uint16(src+3));
  memcpy(dest->integrity, src+5, 4);
  dest->length = ntohs(get_uint16(src+9));
}

Here is the call graph for this function:

Here is the caller graph for this function:

int relay_send_command_from_edge ( streamid_t  stream_id,
circuit_t circ,
uint8_t  relay_command,
const char *  payload,
size_t  payload_len,
crypt_path_t cpath_layer 
)

Make a relay cell out of relay_command and payload, and send it onto the open circuit circ.

stream_id is the ID on circ for the stream that's sending the relay cell, or 0 if it's a control cell. cpath_layer is NULL for OR->OP cells, or the destination hop for OP->OR cells.

If you can't send the cell, mark the circuit for close and return -1. Else return 0.

Definition at line 523 of file relay.c.

{
  cell_t cell;
  relay_header_t rh;
  cell_direction_t cell_direction;
  /* XXXX NM Split this function into a separate versions per circuit type? */

  tor_assert(circ);
  tor_assert(payload_len <= RELAY_PAYLOAD_SIZE);

  memset(&cell, 0, sizeof(cell_t));
  cell.command = CELL_RELAY;
  if (cpath_layer) {
    cell.circ_id = circ->n_circ_id;
    cell_direction = CELL_DIRECTION_OUT;
  } else if (! CIRCUIT_IS_ORIGIN(circ)) {
    cell.circ_id = TO_OR_CIRCUIT(circ)->p_circ_id;
    cell_direction = CELL_DIRECTION_IN;
  } else {
    return -1;
  }

  memset(&rh, 0, sizeof(rh));
  rh.command = relay_command;
  rh.stream_id = stream_id;
  rh.length = payload_len;
  relay_header_pack(cell.payload, &rh);
  if (payload_len)
    memcpy(cell.payload+RELAY_HEADER_SIZE, payload, payload_len);

  log_debug(LD_OR,"delivering %d cell %s.", relay_command,
            cell_direction == CELL_DIRECTION_OUT ? "forward" : "backward");

  /* If we are sending an END cell and this circuit is used for a tunneled
   * directory request, advance its state. */
  if (relay_command == RELAY_COMMAND_END && circ->dirreq_id)
    geoip_change_dirreq_state(circ->dirreq_id, DIRREQ_TUNNELED,
                              DIRREQ_END_CELL_SENT);

  if (cell_direction == CELL_DIRECTION_OUT && circ->n_conn) {
    /* if we're using relaybandwidthrate, this conn wants priority */
    circ->n_conn->client_used = approx_time();
  }

  if (cell_direction == CELL_DIRECTION_OUT) {
    origin_circuit_t *origin_circ = TO_ORIGIN_CIRCUIT(circ);
    if (origin_circ->remaining_relay_early_cells > 0 &&
        (relay_command == RELAY_COMMAND_EXTEND ||
         cpath_layer != origin_circ->cpath)) {
      /* If we've got any relay_early cells left and (we're sending
       * an extend cell or we're not talking to the first hop), use
       * one of them.  Don't worry about the conn protocol version:
       * append_cell_to_circuit_queue will fix it up. */
      cell.command = CELL_RELAY_EARLY;
      --origin_circ->remaining_relay_early_cells;
      log_debug(LD_OR, "Sending a RELAY_EARLY cell; %d remaining.",
                (int)origin_circ->remaining_relay_early_cells);
      /* Memorize the command that is sent as RELAY_EARLY cell; helps debug
       * task 878. */
      origin_circ->relay_early_commands[
          origin_circ->relay_early_cells_sent++] = relay_command;
    } else if (relay_command == RELAY_COMMAND_EXTEND) {
      /* If no RELAY_EARLY cells can be sent over this circuit, log which
       * commands have been sent as RELAY_EARLY cells before; helps debug
       * task 878. */
      smartlist_t *commands_list = smartlist_new();
      int i = 0;
      char *commands = NULL;
      for (; i < origin_circ->relay_early_cells_sent; i++)
        smartlist_add(commands_list, (char *)
            relay_command_to_string(origin_circ->relay_early_commands[i]));
      commands = smartlist_join_strings(commands_list, ",", 0, NULL);
      log_warn(LD_BUG, "Uh-oh.  We're sending a RELAY_COMMAND_EXTEND cell, "
               "but we have run out of RELAY_EARLY cells on that circuit. "
               "Commands sent before: %s", commands);
      tor_free(commands);
      smartlist_free(commands_list);
    }
  }

  if (circuit_package_relay_cell(&cell, circ, cell_direction, cpath_layer,
                                 stream_id) < 0) {
    log_warn(LD_BUG,"circuit_package_relay_cell failed. Closing.");
    circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL);
    return -1;
  }
  return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

How many bytes of data have we put in relay_data cells have we built, ever? This would be RELAY_PAYLOAD_SIZE*stats_n_data_cells_packaged if every relay cell we ever sent were completely full of data.

Definition at line 1353 of file relay.c.

How many bytes of data have we received relay_data cells, ever? This would be RELAY_PAYLOAD_SIZE*stats_n_data_cells_packaged if every relay cell we ever received were completely full of data.

Definition at line 1359 of file relay.c.

How many relay_data cells have we built, ever?

Definition at line 1349 of file relay.c.

How many relay_data cells have we received, ever?

Definition at line 1355 of file relay.c.

Stats: how many relay cells have been delivered to streams at this hop?

Definition at line 69 of file relay.c.

Stats: how many relay cells have originated at this hop, or have been relayed onward (not recognized at this hop)?

Definition at line 65 of file relay.c.