mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2025-02-24 14:51:11 +01:00
stop most cases of hanging up on a socks connection without sending
the socks reject. audit for remaining ones. also make things more uniform so we always remember to hold-open-until-flushed, etc. svn:r3891
This commit is contained in:
parent
efb5db449a
commit
36baf7219d
9 changed files with 79 additions and 78 deletions
|
@ -722,8 +722,7 @@ int circuit_truncated(circuit_t *circ, crypt_path_t *layer) {
|
|||
/* no need to send 'end' relay cells,
|
||||
* because the other side's already dead
|
||||
*/
|
||||
stream->has_sent_end = 1;
|
||||
connection_mark_for_close(stream);
|
||||
connection_close_unattached_ap(stream, END_STREAM_REASON_DESTROY);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -281,7 +281,8 @@ void connection_about_to_close_connection(connection_t *conn)
|
|||
if (conn->socks_request->has_finished == 0) {
|
||||
/* since conn gets removed right after this function finishes,
|
||||
* there's no point trying to send back a reply at this point. */
|
||||
log_fn(LOG_WARN,"Bug: Closing stream without sending back a socks reply.");
|
||||
log_fn(LOG_WARN,"Bug: Closing stream (marked at %s:%d) without sending back a socks reply.",
|
||||
conn->marked_for_close_file, conn->marked_for_close);
|
||||
} else {
|
||||
control_event_stream_status(conn, STREAM_EVENT_CLOSED);
|
||||
}
|
||||
|
|
|
@ -20,6 +20,26 @@ static smartlist_t *redirect_exit_list = NULL;
|
|||
static int connection_ap_handshake_process_socks(connection_t *conn);
|
||||
static int address_is_in_virtual_range(const char *addr);
|
||||
|
||||
/** An AP stream has failed/finished. If it hasn't already sent back
|
||||
* a socks reply, send one now (based on endreason). Also set
|
||||
* has_sent_end to 1, and mark the conn.
|
||||
*/
|
||||
void
|
||||
connection_close_unattached_ap(connection_t *conn, int endreason) {
|
||||
tor_assert(conn->type == CONN_TYPE_AP);
|
||||
conn->has_sent_end = 1; /* no circ yet */
|
||||
if (!conn->socks_request->has_finished) {
|
||||
socks5_reply_status_t socksreason =
|
||||
connection_edge_end_reason_socks5_response(endreason);
|
||||
if (conn->socks_request->command == SOCKS_COMMAND_CONNECT)
|
||||
connection_ap_handshake_socks_reply(conn, NULL, 0, socksreason);
|
||||
else
|
||||
connection_ap_handshake_socks_resolved(conn,RESOLVED_TYPE_ERROR,0,NULL);
|
||||
}
|
||||
connection_mark_for_close(conn);
|
||||
conn->hold_open_until_flushed = 1;
|
||||
}
|
||||
|
||||
/** There was an EOF. Send an end and mark the connection for close.
|
||||
*/
|
||||
int connection_edge_reached_eof(connection_t *conn) {
|
||||
|
@ -45,9 +65,9 @@ int connection_edge_reached_eof(connection_t *conn) {
|
|||
/* only mark it if not already marked. it's possible to
|
||||
* get the 'end' right around when the client hangs up on us. */
|
||||
connection_edge_end(conn, END_STREAM_REASON_DONE, conn->cpath_layer);
|
||||
if (conn->socks_request) /* eof, so don't send a socks reply back */
|
||||
conn->socks_request->has_finished = 1;
|
||||
connection_mark_for_close(conn);
|
||||
// conn->hold_open_until_flushed = 1; /* just because we shouldn't read
|
||||
// doesn't mean we shouldn't write */
|
||||
}
|
||||
return 0;
|
||||
#endif
|
||||
|
@ -70,9 +90,7 @@ int connection_edge_process_inbuf(connection_t *conn, int package_partial) {
|
|||
switch (conn->state) {
|
||||
case AP_CONN_STATE_SOCKS_WAIT:
|
||||
if (connection_ap_handshake_process_socks(conn) < 0) {
|
||||
conn->has_sent_end = 1; /* no circ yet */
|
||||
connection_mark_for_close(conn);
|
||||
conn->hold_open_until_flushed = 1; /* redundant but shouldn't hurt */
|
||||
connection_close_unattached_ap(conn, END_STREAM_REASON_TIMEOUT);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
|
@ -113,9 +131,13 @@ int connection_edge_destroy(uint16_t circ_id, connection_t *conn) {
|
|||
return 0; /* already marked; probably got an 'end' */
|
||||
log_fn(LOG_INFO,"CircID %d: At an edge. Marking connection for close.",
|
||||
circ_id);
|
||||
if (conn->type == CONN_TYPE_AP) {
|
||||
connection_close_unattached_ap(conn, END_STREAM_REASON_DESTROY);
|
||||
} else {
|
||||
conn->has_sent_end = 1; /* we're closing the circuit, nothing to send to */
|
||||
connection_mark_for_close(conn);
|
||||
conn->hold_open_until_flushed = 1;
|
||||
}
|
||||
conn->cpath_layer = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
@ -280,7 +302,7 @@ void connection_ap_expire_beginning(void) {
|
|||
if (conn->state == AP_CONN_STATE_CONTROLLER_WAIT) {
|
||||
if (now - conn->timestamp_lastread >= 120) {
|
||||
log_fn(LOG_NOTICE, "Closing unattached stream.");
|
||||
connection_mark_for_close(conn);
|
||||
connection_close_unattached_ap(conn, END_STREAM_REASON_TIMEOUT);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
@ -294,8 +316,7 @@ void connection_ap_expire_beginning(void) {
|
|||
if (!circ) { /* it's vanished? */
|
||||
log_fn(LOG_INFO,"Conn is waiting (address %s), but lost its circ.",
|
||||
conn->socks_request->address);
|
||||
conn->has_sent_end = 1; /* No circuit to receive end cell. */
|
||||
connection_mark_for_close(conn);
|
||||
connection_close_unattached_ap(conn, END_STREAM_REASON_TIMEOUT);
|
||||
continue;
|
||||
}
|
||||
if (circ->purpose == CIRCUIT_PURPOSE_C_REND_JOINED) {
|
||||
|
@ -303,7 +324,7 @@ void connection_ap_expire_beginning(void) {
|
|||
log_fn(LOG_NOTICE,"Rend stream is %d seconds late. Giving up on address '%s'.",
|
||||
(int)(now - conn->timestamp_lastread), conn->socks_request->address);
|
||||
connection_edge_end(conn, END_STREAM_REASON_TIMEOUT, conn->cpath_layer);
|
||||
connection_mark_for_close(conn);
|
||||
connection_close_unattached_ap(conn, END_STREAM_REASON_TIMEOUT);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
@ -324,10 +345,7 @@ void connection_ap_expire_beginning(void) {
|
|||
conn->timestamp_lastread += 15;
|
||||
/* move it back into 'pending' state, and try to attach. */
|
||||
if (connection_ap_detach_retriable(conn, circ)<0) {
|
||||
/* it will never work */
|
||||
/* Don't need to send end -- we're not connected */
|
||||
conn->has_sent_end = 1;
|
||||
connection_mark_for_close(conn);
|
||||
connection_close_unattached_ap(conn, END_STREAM_REASON_MISC);
|
||||
}
|
||||
} /* end for */
|
||||
}
|
||||
|
@ -350,10 +368,7 @@ void connection_ap_attach_pending(void)
|
|||
conn->state != AP_CONN_STATE_CIRCUIT_WAIT)
|
||||
continue;
|
||||
if (connection_ap_handshake_attach_circuit(conn) < 0) {
|
||||
/* -1 means it will never work */
|
||||
/* Don't send end; there is no 'other side' yet */
|
||||
conn->has_sent_end = 1;
|
||||
connection_mark_for_close(conn);
|
||||
connection_close_unattached_ap(conn, END_STREAM_REASON_MISC);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -911,9 +926,7 @@ static int connection_ap_handshake_process_socks(connection_t *conn) {
|
|||
answer = in.s_addr;
|
||||
connection_ap_handshake_socks_resolved(conn,RESOLVED_TYPE_IPV4,4,
|
||||
(char*)&answer);
|
||||
conn->has_sent_end = 1;
|
||||
connection_mark_for_close(conn);
|
||||
conn->hold_open_until_flushed = 1;
|
||||
connection_close_unattached_ap(conn, END_STREAM_REASON_DONE);
|
||||
return 0;
|
||||
}
|
||||
rep_hist_note_used_resolve(time(NULL)); /* help predict this next time */
|
||||
|
@ -1016,9 +1029,7 @@ int connection_ap_handshake_send_begin(connection_t *ap_conn, circuit_t *circ)
|
|||
|
||||
ap_conn->stream_id = get_unique_stream_id_by_circ(circ);
|
||||
if (ap_conn->stream_id==0) {
|
||||
/* Don't send end: there is no 'other side' yet */
|
||||
ap_conn->has_sent_end = 1;
|
||||
connection_mark_for_close(ap_conn);
|
||||
connection_close_unattached_ap(ap_conn, END_STREAM_REASON_INTERNAL);
|
||||
circuit_mark_for_close(circ);
|
||||
return -1;
|
||||
}
|
||||
|
@ -1038,7 +1049,8 @@ int connection_ap_handshake_send_begin(connection_t *ap_conn, circuit_t *circ)
|
|||
ap_conn->package_window = STREAMWINDOW_START;
|
||||
ap_conn->deliver_window = STREAMWINDOW_START;
|
||||
ap_conn->state = AP_CONN_STATE_CONNECT_WAIT;
|
||||
log_fn(LOG_INFO,"Address/port sent, ap socket %d, n_circ_id %d",ap_conn->s,circ->n_circ_id);
|
||||
log_fn(LOG_INFO,"Address/port sent, ap socket %d, n_circ_id %d",
|
||||
ap_conn->s, circ->n_circ_id);
|
||||
control_event_stream_status(ap_conn, STREAM_EVENT_SENT_CONNECT);
|
||||
return 0;
|
||||
}
|
||||
|
@ -1061,9 +1073,7 @@ int connection_ap_handshake_send_resolve(connection_t *ap_conn, circuit_t *circ)
|
|||
|
||||
ap_conn->stream_id = get_unique_stream_id_by_circ(circ);
|
||||
if (ap_conn->stream_id==0) {
|
||||
/* Don't send end: there is no 'other side' yet */
|
||||
ap_conn->has_sent_end = 1;
|
||||
connection_mark_for_close(ap_conn);
|
||||
connection_close_unattached_ap(ap_conn, END_STREAM_REASON_INTERNAL);
|
||||
circuit_mark_for_close(circ);
|
||||
return -1;
|
||||
}
|
||||
|
@ -1079,7 +1089,8 @@ int connection_ap_handshake_send_resolve(connection_t *ap_conn, circuit_t *circ)
|
|||
return -1; /* circuit is closed, don't continue */
|
||||
|
||||
ap_conn->state = AP_CONN_STATE_RESOLVE_WAIT;
|
||||
log_fn(LOG_INFO,"Address sent for resolve, ap socket %d, n_circ_id %d",ap_conn->s,circ->n_circ_id);
|
||||
log_fn(LOG_INFO,"Address sent for resolve, ap socket %d, n_circ_id %d",
|
||||
ap_conn->s, circ->n_circ_id);
|
||||
control_event_stream_status(ap_conn, STREAM_EVENT_SENT_RESOLVE);
|
||||
return 0;
|
||||
}
|
||||
|
@ -1133,8 +1144,7 @@ int connection_ap_make_bridge(char *address, uint16_t port) {
|
|||
|
||||
/* attaching to a dirty circuit is fine */
|
||||
if (connection_ap_handshake_attach_circuit(conn) < 0) {
|
||||
conn->has_sent_end = 1; /* no circ to send to */
|
||||
connection_mark_for_close(conn);
|
||||
connection_close_unattached_ap(conn, END_STREAM_REASON_MISC);
|
||||
tor_close_socket(fd[1]);
|
||||
return -1;
|
||||
}
|
||||
|
@ -1202,7 +1212,6 @@ void connection_ap_handshake_socks_resolved(connection_t *conn,
|
|||
(answer_type == RESOLVED_TYPE_IPV4 ||
|
||||
answer_type == RESOLVED_TYPE_IPV6) ?
|
||||
SOCKS5_SUCCEEDED : SOCKS5_HOST_UNREACHABLE);
|
||||
conn->socks_request->has_finished = 1;
|
||||
}
|
||||
|
||||
/** Send a socks reply to stream <b>conn</b>, using the appropriate
|
||||
|
|
|
@ -736,7 +736,7 @@ static int handle_control_attachstream(connection_t *conn, uint32_t len,
|
|||
if (!circ_id) {
|
||||
ap_conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
|
||||
if (connection_ap_handshake_attach_circuit(ap_conn)<0)
|
||||
connection_mark_for_close(ap_conn);
|
||||
connection_close_unattached_ap(ap_conn, END_STREAM_REASON_MISC);
|
||||
send_control_done(conn);
|
||||
return 0;
|
||||
}
|
||||
|
@ -802,7 +802,6 @@ handle_control_closestream(connection_t *conn, uint32_t len,
|
|||
uint32_t conn_id;
|
||||
connection_t *ap_conn;
|
||||
uint8_t reason;
|
||||
int hold_open;
|
||||
|
||||
if (len < 6) {
|
||||
send_control_error(conn, ERR_SYNTAX, "closestream message too short");
|
||||
|
@ -811,7 +810,6 @@ handle_control_closestream(connection_t *conn, uint32_t len,
|
|||
|
||||
conn_id = ntohl(get_uint32(body));
|
||||
reason = *(uint8_t*)(body+4);
|
||||
hold_open = (*(uint8_t*)(body+5)) & 1;
|
||||
|
||||
if (!(ap_conn = connection_get_by_global_id(conn_id))
|
||||
|| ap_conn->state != CONN_TYPE_AP
|
||||
|
@ -820,19 +818,11 @@ handle_control_closestream(connection_t *conn, uint32_t len,
|
|||
"No AP connection found with given ID");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!ap_conn->socks_request->has_finished) {
|
||||
socks5_reply_status_t status =
|
||||
connection_edge_end_reason_socks5_response(reason);
|
||||
connection_ap_handshake_socks_reply(ap_conn, NULL, 0, status);
|
||||
}
|
||||
if (hold_open)
|
||||
ap_conn->hold_open_until_flushed = 1;
|
||||
connection_mark_for_close(ap_conn);
|
||||
|
||||
connection_close_unattached_ap(ap_conn, reason);
|
||||
send_control_done(conn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
handle_control_closecircuit(connection_t *conn, uint32_t len,
|
||||
const char *body)
|
||||
|
|
|
@ -741,6 +741,9 @@ hibernate_go_dormant(time_t now) {
|
|||
connection_edge_end(conn, END_STREAM_REASON_HIBERNATING,
|
||||
conn->cpath_layer);
|
||||
log_fn(LOG_INFO,"Closing conn type %d", conn->type);
|
||||
if (conn->type == CONN_TYPE_AP) /* send socks failure if needed */
|
||||
connection_close_unattached_ap(conn, END_STREAM_REASON_HIBERNATING);
|
||||
else
|
||||
connection_mark_for_close(conn);
|
||||
}
|
||||
|
||||
|
|
|
@ -476,11 +476,10 @@ void directory_all_unreachable(time_t now) {
|
|||
|
||||
while ((conn = connection_get_by_type_state(CONN_TYPE_AP,
|
||||
AP_CONN_STATE_CIRCUIT_WAIT))) {
|
||||
conn->has_sent_end = 1; /* it's not connected anywhere, so no need to end */
|
||||
log_fn(LOG_NOTICE,"Network down? Failing connection to '%s:%d'.",
|
||||
conn->socks_request->address, conn->socks_request->port);
|
||||
connection_ap_handshake_socks_reply(conn, NULL, 0, SOCKS5_NET_UNREACHABLE);
|
||||
connection_mark_for_close(conn);
|
||||
connection_close_unattached_ap(conn, END_STREAM_REASON_TIMEOUT);
|
||||
// XXX should maybe reflect SOCKS5_NET_UNREACHABLE here. what reason is that?
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -589,14 +588,14 @@ static void run_connection_housekeeping(int i, time_t now) {
|
|||
conn->hold_open_until_flushed = 1;
|
||||
} else if (!clique_mode(options) && !circuit_get_by_conn(conn) &&
|
||||
(!router || !server_mode(options) || !router_is_clique_mode(router))) {
|
||||
log_fn(LOG_INFO,"Expiring non-used connection to %d (%s:%d) [Not in clique mode].",
|
||||
log_fn(LOG_INFO,"Expiring non-used OR connection to %d (%s:%d) [Not in clique mode].",
|
||||
i,conn->address, conn->port);
|
||||
connection_mark_for_close(conn);
|
||||
conn->hold_open_until_flushed = 1;
|
||||
} else if (
|
||||
now >= conn->timestamp_lastempty + options->KeepalivePeriod*10 &&
|
||||
now >= conn->timestamp_lastwritten + options->KeepalivePeriod*10) {
|
||||
log_fn(LOG_NOTICE,"Expiring stuck connection to %d (%s:%d). (%d bytes to flush; %d seconds since last write)",
|
||||
log_fn(LOG_NOTICE,"Expiring stuck OR connection to %d (%s:%d). (%d bytes to flush; %d seconds since last write)",
|
||||
i, conn->address, conn->port,
|
||||
(int)buf_datalen(conn->outbuf),
|
||||
(int)(now-conn->timestamp_lastwritten));
|
||||
|
|
|
@ -1308,6 +1308,7 @@ int connection_or_nonopen_was_started_here(connection_t *conn);
|
|||
|
||||
/********************************* connection_edge.c ***************************/
|
||||
|
||||
void connection_close_unattached_ap(connection_t *conn, int endreason);
|
||||
int connection_edge_reached_eof(connection_t *conn);
|
||||
int connection_edge_process_inbuf(connection_t *conn, int package_partial);
|
||||
int connection_edge_destroy(uint16_t circ_id, connection_t *conn);
|
||||
|
|
|
@ -416,8 +416,12 @@ int connection_edge_send_command(connection_t *fromconn, circuit_t *circ,
|
|||
if (!circ) {
|
||||
log_fn(LOG_WARN,"no circ. Closing conn.");
|
||||
tor_assert(fromconn);
|
||||
if (fromconn->type == CONN_TYPE_AP) {
|
||||
connection_close_unattached_ap(fromconn, END_STREAM_REASON_INTERNAL);
|
||||
} else {
|
||||
fromconn->has_sent_end = 1; /* no circ to send to */
|
||||
connection_mark_for_close(fromconn);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -496,13 +500,13 @@ connection_edge_end_reason_socks5_response(int reason)
|
|||
case END_STREAM_REASON_CONNECTREFUSED:
|
||||
return SOCKS5_CONNECTION_REFUSED;
|
||||
case END_STREAM_REASON_EXITPOLICY:
|
||||
return SOCKS5_CONNECTION_REFUSED;
|
||||
return SOCKS5_CONNECTION_REFUSED; // XXX should be SOCKS5_NOT_ALLOWED ?
|
||||
case END_STREAM_REASON_DESTROY:
|
||||
return SOCKS5_GENERAL_ERROR;
|
||||
case END_STREAM_REASON_DONE:
|
||||
return SOCKS5_SUCCEEDED;
|
||||
case END_STREAM_REASON_TIMEOUT:
|
||||
return SOCKS5_TTL_EXPIRED;
|
||||
return SOCKS5_TTL_EXPIRED; // XXX is this correct?
|
||||
case END_STREAM_REASON_RESOURCELIMIT:
|
||||
return SOCKS5_GENERAL_ERROR;
|
||||
case END_STREAM_REASON_HIBERNATING:
|
||||
|
@ -603,8 +607,7 @@ connection_edge_process_relay_cell_not_open(
|
|||
} else {
|
||||
log_fn(LOG_INFO,"Address '%s' resolved to 0.0.0.0. Closing,",
|
||||
conn->socks_request->address);
|
||||
conn->has_sent_end = 1; /* we just got an 'end', don't need to send one */
|
||||
connection_mark_for_close(conn);
|
||||
connection_close_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
|
||||
return 0;
|
||||
}
|
||||
client_dns_set_addressmap(conn->socks_request->address, addr,
|
||||
|
@ -658,12 +661,13 @@ connection_edge_process_relay_cell_not_open(
|
|||
rh->length));
|
||||
if (CIRCUIT_IS_ORIGIN(circ))
|
||||
circuit_log_path(LOG_INFO,circ);
|
||||
if (conn->type == CONN_TYPE_AP) {
|
||||
connection_close_unattached_ap(conn,
|
||||
*(char *)(cell->payload+RELAY_HEADER_SIZE));
|
||||
} else {
|
||||
conn->has_sent_end = 1; /* we just got an 'end', don't need to send one */
|
||||
if (conn->type == CONN_TYPE_AP)
|
||||
connection_ap_handshake_socks_reply(conn, NULL, 0,
|
||||
connection_edge_end_reason_socks5_response(*(char *)
|
||||
(cell->payload+RELAY_HEADER_SIZE)));
|
||||
connection_mark_for_close(conn);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -681,7 +685,7 @@ connection_edge_process_relay_cell_not_open(
|
|||
if (!addr) {
|
||||
log_fn(LOG_INFO,"...but it claims the IP address was 0.0.0.0. Closing.");
|
||||
connection_edge_end(conn, END_STREAM_REASON_TORPROTOCOL, conn->cpath_layer);
|
||||
connection_mark_for_close(conn);
|
||||
connection_close_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
|
||||
return 0;
|
||||
}
|
||||
client_dns_set_addressmap(conn->socks_request->address, addr,
|
||||
|
@ -705,17 +709,14 @@ connection_edge_process_relay_cell_not_open(
|
|||
tor_assert(conn->socks_request->command == SOCKS_COMMAND_RESOLVE);
|
||||
if (rh->length < 2 || cell->payload[RELAY_HEADER_SIZE+1]+2>rh->length) {
|
||||
log_fn(LOG_WARN, "Dropping malformed 'resolved' cell");
|
||||
conn->has_sent_end = 1;
|
||||
connection_mark_for_close(conn);
|
||||
connection_close_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
|
||||
return 0;
|
||||
}
|
||||
connection_ap_handshake_socks_resolved(conn,
|
||||
cell->payload[RELAY_HEADER_SIZE], /*answer_type*/
|
||||
cell->payload[RELAY_HEADER_SIZE+1], /*answer_len*/
|
||||
cell->payload+RELAY_HEADER_SIZE+2); /* answer */
|
||||
conn->has_sent_end = 1;
|
||||
connection_mark_for_close(conn);
|
||||
conn->hold_open_until_flushed = 1;
|
||||
connection_close_unattached_ap(conn, END_STREAM_REASON_DONE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -394,14 +394,12 @@ void rend_client_desc_here(char *query) {
|
|||
if (connection_ap_handshake_attach_circuit(conn) < 0) {
|
||||
/* it will never work */
|
||||
log_fn(LOG_WARN,"attaching to a rend circ failed. Closing conn.");
|
||||
conn->has_sent_end = 1;
|
||||
connection_mark_for_close(conn);
|
||||
connection_close_unattached_ap(conn, END_STREAM_REASON_MISC);
|
||||
}
|
||||
tor_assert(conn->state != AP_CONN_STATE_RENDDESC_WAIT); /* avoid loop */
|
||||
} else { /* 404, or fetch didn't get that far */
|
||||
log_fn(LOG_NOTICE,"Closing stream for '%s.onion': hidden service is unavailable (try again later).", query);
|
||||
conn->has_sent_end = 1;
|
||||
connection_mark_for_close(conn);
|
||||
connection_close_unattached_ap(conn, END_STREAM_REASON_TIMEOUT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue