|  | @@ -138,6 +138,8 @@ relay_crypt_one_payload(crypto_cipher_env_t *cipher, char *in,
 | 
	
		
			
				|  |  |   *    connection_edge.
 | 
	
		
			
				|  |  |   *  - Else connection_or_write_cell_to_buf to the conn on the other
 | 
	
		
			
				|  |  |   *    side of the circuit.
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * Return -reason on failure.
 | 
	
		
			
				|  |  |   */
 | 
	
		
			
				|  |  |  int
 | 
	
		
			
				|  |  |  circuit_receive_relay_cell(cell_t *cell, circuit_t *circ, int cell_direction)
 | 
	
	
		
			
				|  | @@ -145,6 +147,7 @@ circuit_receive_relay_cell(cell_t *cell, circuit_t *circ, int cell_direction)
 | 
	
		
			
				|  |  |    connection_t *conn=NULL;
 | 
	
		
			
				|  |  |    crypt_path_t *layer_hint=NULL;
 | 
	
		
			
				|  |  |    char recognized=0;
 | 
	
		
			
				|  |  | +  int reason;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    tor_assert(cell);
 | 
	
		
			
				|  |  |    tor_assert(circ);
 | 
	
	
		
			
				|  | @@ -163,20 +166,21 @@ circuit_receive_relay_cell(cell_t *cell, circuit_t *circ, int cell_direction)
 | 
	
		
			
				|  |  |      if (cell_direction == CELL_DIRECTION_OUT) {
 | 
	
		
			
				|  |  |        ++stats_n_relay_cells_delivered;
 | 
	
		
			
				|  |  |        debug(LD_OR,"Sending away from origin.");
 | 
	
		
			
				|  |  | -      if (connection_edge_process_relay_cell(cell, circ, conn, NULL) < 0) {
 | 
	
		
			
				|  |  | +      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 -1;
 | 
	
		
			
				|  |  | +        return reason;
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      if (cell_direction == CELL_DIRECTION_IN) {
 | 
	
		
			
				|  |  |        ++stats_n_relay_cells_delivered;
 | 
	
		
			
				|  |  |        debug(LD_OR,"Sending to origin.");
 | 
	
		
			
				|  |  | -      if (connection_edge_process_relay_cell(cell, circ, conn,
 | 
	
		
			
				|  |  | -                                             layer_hint) < 0) {
 | 
	
		
			
				|  |  | +      if ((reason = connection_edge_process_relay_cell(cell, circ, conn,
 | 
	
		
			
				|  |  | +                                                       layer_hint)) < 0) {
 | 
	
		
			
				|  |  |          warn(LD_OR,"connection_edge_process_relay_cell (at origin) failed.");
 | 
	
		
			
				|  |  | -        return -1;
 | 
	
		
			
				|  |  | +        return reason;
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      return 0;
 | 
	
	
		
			
				|  | @@ -197,19 +201,19 @@ circuit_receive_relay_cell(cell_t *cell, circuit_t *circ, int cell_direction)
 | 
	
		
			
				|  |  |        tor_assert(circ->rend_splice->purpose ==
 | 
	
		
			
				|  |  |                   CIRCUIT_PURPOSE_REND_ESTABLISHED);
 | 
	
		
			
				|  |  |        cell->circ_id = circ->rend_splice->p_circ_id;
 | 
	
		
			
				|  |  | -      if (circuit_receive_relay_cell(cell, circ->rend_splice,
 | 
	
		
			
				|  |  | -                                     CELL_DIRECTION_IN) < 0) {
 | 
	
		
			
				|  |  | +      if ((reason = circuit_receive_relay_cell(cell, circ->rend_splice,
 | 
	
		
			
				|  |  | +                                               CELL_DIRECTION_IN)) < 0) {
 | 
	
		
			
				|  |  |          warn(LD_REND, "Error relaying cell across rendezvous; closing "
 | 
	
		
			
				|  |  |               "circuits");
 | 
	
		
			
				|  |  |          /* XXXX Do this here, or just return -1? */
 | 
	
		
			
				|  |  | -        circuit_mark_for_close(circ);
 | 
	
		
			
				|  |  | -        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 -1;
 | 
	
		
			
				|  |  | +    return -END_CIRC_REASON_TORPROTOCOL;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    debug(LD_OR,"Passing on unrecognized cell.");
 | 
	
	
		
			
				|  | @@ -489,7 +493,7 @@ connection_edge_send_command(connection_t *fromconn, circuit_t *circ,
 | 
	
		
			
				|  |  |    if (circuit_package_relay_cell(&cell, circ, cell_direction, cpath_layer)
 | 
	
		
			
				|  |  |        < 0) {
 | 
	
		
			
				|  |  |      warn(LD_BUG,"circuit_package_relay_cell failed. Closing.");
 | 
	
		
			
				|  |  | -    circuit_mark_for_close(circ);
 | 
	
		
			
				|  |  | +    circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL);
 | 
	
		
			
				|  |  |      return -1;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    return 0;
 | 
	
	
		
			
				|  | @@ -655,7 +659,7 @@ connection_edge_process_end_not_open(
 | 
	
		
			
				|  |  |        warn(LD_PROTOCOL,
 | 
	
		
			
				|  |  |             "Got an end because of %s, but we're not an AP. Closing.",
 | 
	
		
			
				|  |  |             connection_edge_end_reason_str(reason));
 | 
	
		
			
				|  |  | -      return -1;
 | 
	
		
			
				|  |  | +      return - END_CIRC_REASON_TORPROTOCOL;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      info(LD_APP,"Address '%s' refused due to '%s'. Considering retrying.",
 | 
	
		
			
				|  |  |           safe_str(conn->socks_request->address),
 | 
	
	
		
			
				|  | @@ -848,7 +852,7 @@ connection_edge_process_relay_cell_not_open(
 | 
	
		
			
				|  |  |   * If <b>layer_hint</b> is defined, then we're the origin of the
 | 
	
		
			
				|  |  |   * circuit, and it specifies the hop that packaged <b>cell</b>.
 | 
	
		
			
				|  |  |   *
 | 
	
		
			
				|  |  | - * Return -1 if you want to warn and tear down the circuit, else 0.
 | 
	
		
			
				|  |  | + * Return -reason if you want to warn and tear down the circuit, else 0.
 | 
	
		
			
				|  |  |   */
 | 
	
		
			
				|  |  |  static int
 | 
	
		
			
				|  |  |  connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
 | 
	
	
		
			
				|  | @@ -858,6 +862,7 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
 | 
	
		
			
				|  |  |    static int num_seen=0;
 | 
	
		
			
				|  |  |    relay_header_t rh;
 | 
	
		
			
				|  |  |    unsigned domain = layer_hint?LD_APP:LD_EXIT;
 | 
	
		
			
				|  |  | +  int reason;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    tor_assert(cell);
 | 
	
		
			
				|  |  |    tor_assert(circ);
 | 
	
	
		
			
				|  | @@ -869,7 +874,7 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    if (rh.length > RELAY_PAYLOAD_SIZE) {
 | 
	
		
			
				|  |  |      warn(LD_PROTOCOL, "Relay cell length field too long. Closing circuit.");
 | 
	
		
			
				|  |  | -    return -1;
 | 
	
		
			
				|  |  | +    return - END_CIRC_REASON_TORPROTOCOL;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    /* either conn is NULL, in which case we've got a control cell, or else
 | 
	
	
		
			
				|  | @@ -904,7 +909,7 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
 | 
	
		
			
				|  |  |          connection_edge_end(conn, END_STREAM_REASON_TORPROTOCOL,
 | 
	
		
			
				|  |  |                              conn->cpath_layer);
 | 
	
		
			
				|  |  |          connection_mark_for_close(conn);
 | 
	
		
			
				|  |  | -        return -1;
 | 
	
		
			
				|  |  | +        return -END_CIRC_REASON_TORPROTOCOL;
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |        debug(domain,"circ deliver_window now %d.", layer_hint ?
 | 
	
		
			
				|  |  |              layer_hint->deliver_window : circ->deliver_window);
 | 
	
	
		
			
				|  | @@ -919,7 +924,7 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
 | 
	
		
			
				|  |  |        if (--conn->deliver_window < 0) { /* is it below 0 after decrement? */
 | 
	
		
			
				|  |  |          log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
 | 
	
		
			
				|  |  |                 "(relay data) conn deliver_window below 0. Killing.");
 | 
	
		
			
				|  |  | -        return -1; /* somebody's breaking protocol. kill the whole circuit. */
 | 
	
		
			
				|  |  | +        return -END_CIRC_REASON_TORPROTOCOL;
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |        stats_n_data_bytes_received += rh.length;
 | 
	
	
		
			
				|  | @@ -974,14 +979,14 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
 | 
	
		
			
				|  |  |          return 0;
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |        debug(domain,"Got an extended cell! Yay.");
 | 
	
		
			
				|  |  | -      if (circuit_finish_handshake(circ, CELL_CREATED,
 | 
	
		
			
				|  |  | -                                   cell->payload+RELAY_HEADER_SIZE) < 0) {
 | 
	
		
			
				|  |  | +      if ((reason = circuit_finish_handshake(circ, CELL_CREATED,
 | 
	
		
			
				|  |  | +                                       cell->payload+RELAY_HEADER_SIZE)) < 0) {
 | 
	
		
			
				|  |  |          warn(domain,"circuit_finish_handshake failed.");
 | 
	
		
			
				|  |  | -        return -1;
 | 
	
		
			
				|  |  | +        return reason;
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  | -      if (circuit_send_next_onion_skin(circ)<0) {
 | 
	
		
			
				|  |  | +      if ((reason=circuit_send_next_onion_skin(circ))<0) {
 | 
	
		
			
				|  |  |          info(domain,"circuit_send_next_onion_skin() failed.");
 | 
	
		
			
				|  |  | -        return -1;
 | 
	
		
			
				|  |  | +        return reason;
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |        return 0;
 | 
	
		
			
				|  |  |      case RELAY_COMMAND_TRUNCATE:
 | 
	
	
		
			
				|  | @@ -990,12 +995,17 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
 | 
	
		
			
				|  |  |          return 0;
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |        if (circ->n_conn) {
 | 
	
		
			
				|  |  | -        connection_send_destroy(circ->n_circ_id, circ->n_conn);
 | 
	
		
			
				|  |  | +        uint8_t reason = *(uint8_t*)(cell->payload + RELAY_HEADER_SIZE);
 | 
	
		
			
				|  |  | +        connection_or_send_destroy(circ->n_circ_id, circ->n_conn, reason);
 | 
	
		
			
				|  |  |          circuit_set_circid_orconn(circ, 0, NULL, N_CONN_CHANGED);
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |        debug(LD_EXIT, "Processed 'truncate', replying.");
 | 
	
		
			
				|  |  | -      connection_edge_send_command(NULL, circ, RELAY_COMMAND_TRUNCATED,
 | 
	
		
			
				|  |  | -                                   NULL, 0, NULL);
 | 
	
		
			
				|  |  | +      {
 | 
	
		
			
				|  |  | +        char payload[1];
 | 
	
		
			
				|  |  | +        payload[0] = (char)END_CIRC_REASON_REQUESTED;
 | 
	
		
			
				|  |  | +        connection_edge_send_command(NULL, circ, RELAY_COMMAND_TRUNCATED,
 | 
	
		
			
				|  |  | +                                     payload, sizeof(payload), NULL);
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  |        return 0;
 | 
	
		
			
				|  |  |      case RELAY_COMMAND_TRUNCATED:
 | 
	
		
			
				|  |  |        if (!layer_hint) {
 | 
	
	
		
			
				|  | @@ -1008,7 +1018,7 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
 | 
	
		
			
				|  |  |        if (conn) {
 | 
	
		
			
				|  |  |          log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
 | 
	
		
			
				|  |  |                 "'connected' unsupported while open. Closing circ.");
 | 
	
		
			
				|  |  | -        return -1;
 | 
	
		
			
				|  |  | +        return -END_CIRC_REASON_TORPROTOCOL;
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |        info(domain,"'connected' received, no conn attached anymore. Ignoring.");
 | 
	
		
			
				|  |  |        return 0;
 | 
	
	
		
			
				|  | @@ -1055,7 +1065,7 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
 | 
	
		
			
				|  |  |      case RELAY_COMMAND_RESOLVED:
 | 
	
		
			
				|  |  |        if (conn) {
 | 
	
		
			
				|  |  |          warn(domain,"'resolved' unsupported while open. Closing circ.");
 | 
	
		
			
				|  |  | -        return -1;
 | 
	
		
			
				|  |  | +        return -END_CIRC_REASON_TORPROTOCOL;
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |        info(domain,"'resolved' received, no conn attached anymore. Ignoring.");
 | 
	
		
			
				|  |  |        return 0;
 |