|
|
|
@ -263,6 +263,19 @@ struct stcp_link *stcp_link_connect(struct ETCP_LINK *etcp_link, |
|
|
|
return link; |
|
|
|
return link; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Освобождение очереди с предварительным дренажем записей: queue_free не
|
|
|
|
|
|
|
|
* освобождает элементы (они должны извлекаться отдельно), иначе записи и их |
|
|
|
|
|
|
|
* dgram-буферы утекают при обрыве с данными в полёте. */ |
|
|
|
|
|
|
|
static void stcp_drain_free_queue(struct ll_queue *q) { |
|
|
|
|
|
|
|
if (!q) return; |
|
|
|
|
|
|
|
struct ll_entry *e; |
|
|
|
|
|
|
|
while ((e = queue_data_get(q)) != NULL) { |
|
|
|
|
|
|
|
queue_dgram_free(e); |
|
|
|
|
|
|
|
queue_entry_free(e); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
queue_free(q); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void stcp_link_close_impl(void *arg) { |
|
|
|
static void stcp_link_close_impl(void *arg) { |
|
|
|
struct stcp_link *link = (struct stcp_link *)arg; |
|
|
|
struct stcp_link *link = (struct stcp_link *)arg; |
|
|
|
callring_put(CR_SLINK_IMPL, (uintptr_t)link, (uintptr_t)(link->conn)); |
|
|
|
callring_put(CR_SLINK_IMPL, (uintptr_t)link, (uintptr_t)(link->conn)); |
|
|
|
@ -270,19 +283,26 @@ static void stcp_link_close_impl(void *arg) { |
|
|
|
if (link->cli) { |
|
|
|
if (link->cli) { |
|
|
|
struct stcp_conn *c = stcp_client_get_conn(link->cli); |
|
|
|
struct stcp_conn *c = stcp_client_get_conn(link->cli); |
|
|
|
if (!link->conn_pre_closed) { |
|
|
|
if (!link->conn_pre_closed) { |
|
|
|
if (c && c->rx_queue) queue_free(c->rx_queue); |
|
|
|
if (c && c->rx_queue) { stcp_drain_free_queue(c->rx_queue); c->rx_queue = NULL; } |
|
|
|
if (link->tx_queue) queue_free(link->tx_queue); |
|
|
|
if (link->tx_queue) { stcp_drain_free_queue(link->tx_queue); link->tx_queue = NULL; } |
|
|
|
stcp_client_destroy(link->cli); |
|
|
|
stcp_client_destroy(link->cli); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
if (link->saved_rx_queue) queue_free(link->saved_rx_queue); |
|
|
|
if (link->saved_rx_queue) { stcp_drain_free_queue(link->saved_rx_queue); link->saved_rx_queue = NULL; } |
|
|
|
if (link->tx_queue) queue_free(link->tx_queue); |
|
|
|
if (link->tx_queue) { stcp_drain_free_queue(link->tx_queue); link->tx_queue = NULL; } |
|
|
|
u_free(link->cli); |
|
|
|
u_free(link->cli); |
|
|
|
} |
|
|
|
} |
|
|
|
} else if (link->conn) { |
|
|
|
} else if (link->conn) { |
|
|
|
struct stcp_conn *conn = link->conn; |
|
|
|
if (!link->conn_pre_closed) { |
|
|
|
if (conn->rx_queue) { queue_free(conn->rx_queue); conn->rx_queue = NULL; } |
|
|
|
struct stcp_conn *conn = link->conn; |
|
|
|
if (link->tx_queue) { queue_free(link->tx_queue); link->tx_queue = NULL; } |
|
|
|
if (conn->rx_queue) { stcp_drain_free_queue(conn->rx_queue); conn->rx_queue = NULL; } |
|
|
|
stcp_conn_do_close(conn, 0); |
|
|
|
if (link->tx_queue) { stcp_drain_free_queue(link->tx_queue); link->tx_queue = NULL; } |
|
|
|
|
|
|
|
stcp_conn_do_close(conn, 0); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
/* conn уже закрыт и освобождается отложенно — не трогаем link->conn,
|
|
|
|
|
|
|
|
* работаем с сохранённой rx_queue. */ |
|
|
|
|
|
|
|
if (link->saved_rx_queue) { stcp_drain_free_queue(link->saved_rx_queue); link->saved_rx_queue = NULL; } |
|
|
|
|
|
|
|
if (link->tx_queue) { stcp_drain_free_queue(link->tx_queue); link->tx_queue = NULL; } |
|
|
|
|
|
|
|
} |
|
|
|
link->conn = NULL; |
|
|
|
link->conn = NULL; |
|
|
|
} |
|
|
|
} |
|
|
|
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "stcp_link_close_impl: link=%p cli=%p conn=%p conn_pre_closed=%d", (void*)link, (void*)link->cli, (void*)link->conn, link->conn_pre_closed); |
|
|
|
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "stcp_link_close_impl: link=%p cli=%p conn=%p conn_pre_closed=%d", (void*)link, (void*)link->cli, (void*)link->conn, link->conn_pre_closed); |
|
|
|
@ -314,6 +334,12 @@ void stcp_link_close(struct stcp_link *link) { |
|
|
|
link->saved_rx_queue = c->rx_queue; c->rx_queue = NULL; link->conn_pre_closed = 1; |
|
|
|
link->saved_rx_queue = c->rx_queue; c->rx_queue = NULL; link->conn_pre_closed = 1; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} else if (link->conn) { |
|
|
|
|
|
|
|
struct stcp_conn *c = link->conn; |
|
|
|
|
|
|
|
if (c->hs_timer) { uasync_cancel_timeout(link->ua, c->hs_timer); c->hs_timer = NULL; } |
|
|
|
|
|
|
|
if (c->state == STCP_STATE_CLOSED || c->state == STCP_STATE_ERROR) { |
|
|
|
|
|
|
|
link->saved_rx_queue = c->rx_queue; c->rx_queue = NULL; link->conn_pre_closed = 1; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
uasync_call_soon(link->ua, link, stcp_link_close_impl); |
|
|
|
uasync_call_soon(link->ua, link, stcp_link_close_impl); |
|
|
|
} |
|
|
|
} |
|
|
|
|