diff options
Diffstat (limited to 'src/or/circuit.c')
-rw-r--r-- | src/or/circuit.c | 95 |
1 files changed, 53 insertions, 42 deletions
diff --git a/src/or/circuit.c b/src/or/circuit.c index be05caafd..d3053eb27 100644 --- a/src/or/circuit.c +++ b/src/or/circuit.c @@ -512,52 +512,59 @@ void circuit_about_to_close_connection(connection_t *conn) { circuit_t *circ; connection_t *prevconn; - if(!connection_speaks_cells(conn)) { - /* it's an edge conn. need to remove it from the linked list of - * conn's for this circuit. Send an 'end' relay command. - * But don't kill the circuit. - */ - - circ = circuit_get_by_conn(conn); - if(!circ) + switch(conn->type) { + case CONN_TYPE_OR: + /* We must close all the circuits on it. */ + while((circ = circuit_get_by_conn(conn))) { + if(circ->n_conn == conn) /* it's closing in front of us */ + circ->n_conn = NULL; + if(circ->p_conn == conn) /* it's closing behind us */ + circ->p_conn = NULL; + circuit_close(circ); + } return; + case CONN_TYPE_AP: + case CONN_TYPE_EXIT: - if(conn == circ->p_streams) { - circ->p_streams = conn->next_stream; - goto send_end; - } - if(conn == circ->n_streams) { - circ->n_streams = conn->next_stream; - goto send_end; - } - for(prevconn = circ->p_streams; prevconn && prevconn->next_stream && prevconn->next_stream != conn; prevconn = prevconn->next_stream) ; - if(prevconn && prevconn->next_stream) { - prevconn->next_stream = conn->next_stream; - goto send_end; - } - for(prevconn = circ->n_streams; prevconn && prevconn->next_stream && prevconn->next_stream != conn; prevconn = prevconn->next_stream) ; - if(prevconn && prevconn->next_stream) { - prevconn->next_stream = conn->next_stream; - goto send_end; - } - log_fn(LOG_ERR,"edge conn not in circuit's list?"); - assert(0); /* should never get here */ -send_end: - connection_edge_send_command(conn, circ, RELAY_COMMAND_END, - NULL, 0, conn->cpath_layer); - return; - } + /* It's an edge conn. Need to remove it from the linked list of + * conn's for this circuit. Confirm that 'end' relay command has + * been sent. But don't kill the circuit. + */ - /* this connection speaks cells. We must close all the circuits on it. */ - while((circ = circuit_get_by_conn(conn))) { - if(circ->n_conn == conn) /* it's closing in front of us */ - circ->n_conn = NULL; - if(circ->p_conn == conn) /* it's closing behind us */ - circ->p_conn = NULL; - circuit_close(circ); - } + circ = circuit_get_by_conn(conn); + if(!circ) + return; + + if(!conn->has_sent_end) { + log_fn(LOG_INFO,"Edge connection hasn't sent end yet? Bug."); + connection_edge_send_command(conn, circ, RELAY_COMMAND_END, + NULL, 0, conn->cpath_layer); + } + + if(conn == circ->p_streams) { + circ->p_streams = conn->next_stream; + return; + } + if(conn == circ->n_streams) { + circ->n_streams = conn->next_stream; + return; + } + for(prevconn = circ->p_streams; prevconn && prevconn->next_stream && prevconn->next_stream != conn; prevconn = prevconn->next_stream) ; + if(prevconn && prevconn->next_stream) { + prevconn->next_stream = conn->next_stream; + return; + } + for(prevconn = circ->n_streams; prevconn && prevconn->next_stream && prevconn->next_stream != conn; prevconn = prevconn->next_stream) ; + if(prevconn && prevconn->next_stream) { + prevconn->next_stream = conn->next_stream; + return; + } + log_fn(LOG_ERR,"edge conn not in circuit's list?"); + assert(0); /* should never get here */ + } /* end switch */ } + /* FIXME this now leaves some out */ void circuit_dump_by_conn(connection_t *conn, int severity) { circuit_t *circ; @@ -903,7 +910,11 @@ int circuit_truncated(circuit_t *circ, crypt_path_t *layer) { for(stream = circ->p_streams; stream; stream=stream->next_stream) { if(stream->cpath_layer == victim) { log_fn(LOG_INFO, "Marking stream %d for close.", *(int*)stream->stream_id); -/*ENDCLOSE*/ stream->marked_for_close = 1; + /* no need to send 'end' relay cells, + * because the other side's already dead + */ + stream->marked_for_close = 1; + stream->has_sent_end = 1; } } |