uint64_t idle_in_timeout = the_network->tcp.in_idle_timeout;
uint64_t timeout = KR_CONN_RTT_MAX / 2;
session2_event(s, PROTOLAYER_EVENT_CONNECT, NULL);
- session2_timer_start(s, timeout, idle_in_timeout);
+ session2_timer_start(s, PROTOLAYER_EVENT_GENERAL_TIMEOUT,
+ timeout, idle_in_timeout);
io_start_read((uv_handle_t *)client);
}
static void session2_on_timeout(uv_timer_t *timer)
{
struct session2 *s = timer->data;
- session2_event(s, PROTOLAYER_EVENT_TIMEOUT, NULL);
+ session2_event(s, s->timer_event, NULL);
}
-int session2_timer_start(struct session2 *s, uint64_t timeout, uint64_t repeat)
+int session2_timer_start(struct session2 *s, enum protolayer_event_type event, uint64_t timeout, uint64_t repeat)
{
+ s->timer_event = event;
return uv_timer_start(&s->timer, session2_on_timeout, timeout, repeat);
}
* session - i.e. layers SHOULD NOT add
* any disconnection ceremony, if
* avoidable. */\
- XX(TIMEOUT) /**< Signal that the session has timed out. */\
+ XX(CONNECT_TIMEOUT) /**< Signal that a connection could not be established due to a timeout. */\
+ XX(GENERAL_TIMEOUT) /**< Signal that a general application-defined timeout has occurred. */\
XX(CONNECT) /**< Signal that a connection has been established. */\
XX(CONNECT_FAIL) /**< Signal that a connection could not have been established. */\
XX(MALFORMED) /**< Signal that a malformed request has been received. */\
struct protolayer_manager *layers; /**< Protocol layers of this session. */
knot_mm_t pool;
uv_timer_t timer; /**< For session-wide timeout events. */
+ enum protolayer_event_type timer_event; /**< The event fired on timeout. */
trie_t *tasks; /**< List of tasks associated with given session. */
queue_t(struct qr_task *) waiting; /**< List of tasks waiting for
* sending to upstream. */
* May return `NULL` if no peer is set. */
KR_EXPORT uv_handle_t *session2_get_handle(struct session2 *s);
-/** Start the session timer. When the timer ends, a `_TIMEOUT` event is sent
- * in the `_UNWRAP` direction. */
-int session2_timer_start(struct session2 *s, uint64_t timeout, uint64_t repeat);
+/** Start the session timer. On timeout, the specified `event` is sent in the
+ * `_UNWRAP` direction. Only a single timeout can be active at a time. */
+int session2_timer_start(struct session2 *s, enum protolayer_event_type event,
+ uint64_t timeout, uint64_t repeat);
/** Restart the session timer without changing any of its parameters. */
int session2_timer_restart(struct session2 *s);
while (tls->handshake_state <= TLS_HS_IN_PROGRESS) {
int ret = tls_handshake(tls, session);
if (ret != kr_ok()) {
+ if (ret == kr_error(EAGAIN)) {
+ session2_timer_stop(session);
+ session2_timer_start(session,
+ PROTOLAYER_EVENT_GENERAL_TIMEOUT,
+ MAX_TCP_INACTIVITY, MAX_TCP_INACTIVITY);
+ }
return false;
}
}
if (kr_fails_assert(qry && task->transport))
return status;
size_t timeout = task->transport->timeout;
- int ret = session2_timer_start(s, timeout, 0);
+ int ret = session2_timer_start(s, PROTOLAYER_EVENT_GENERAL_TIMEOUT,
+ timeout, 0);
/* Start next step with timeout, fatal if can't start a timer. */
if (ret != 0) {
subreq_finalize(task, &task->transport->address.ip, task->pktbuf);
}
session2_timer_stop(session);
- session2_timer_start(session, MAX_TCP_INACTIVITY, MAX_TCP_INACTIVITY);
+ session2_timer_start(session, PROTOLAYER_EVENT_GENERAL_TIMEOUT,
+ MAX_TCP_INACTIVITY, MAX_TCP_INACTIVITY);
}
static int transmit(struct qr_task *task)
memcpy(peer, addr, kr_sockaddr_len(addr));
/* Start watchdog to catch eventual connection timeout. */
- ret = session2_timer_start(session, KR_CONN_RTT_MAX, 0);
+ ret = session2_timer_start(session, PROTOLAYER_EVENT_CONNECT_TIMEOUT,
+ KR_CONN_RTT_MAX, 0);
if (ret != 0) {
worker_del_tcp_waiting(addr);
free(conn);
struct protolayer_manager *manager,
void *sess_data)
{
- if (event != PROTOLAYER_EVENT_TIMEOUT)
+ if (event != PROTOLAYER_EVENT_GENERAL_TIMEOUT)
return true;
struct session2 *session = manager->session;
if (!session2_tasklist_is_empty(s)) {
session2_timer_stop(s);
session2_timer_start(s,
+ PROTOLAYER_EVENT_GENERAL_TIMEOUT,
KR_RESOLVE_TIME_LIMIT / 2,
KR_RESOLVE_TIME_LIMIT / 2);
} else {
if (idle_time < idle_in_timeout) {
idle_in_timeout -= idle_time;
session2_timer_stop(s);
- session2_timer_start(s, idle_in_timeout, idle_in_timeout);
+ session2_timer_start(s, PROTOLAYER_EVENT_GENERAL_TIMEOUT,
+ idle_in_timeout, idle_in_timeout);
} else {
struct sockaddr *peer = session2_get_peer(s);
char *peer_str = kr_straddr(peer);
if (session->closing)
return true;
- if (event == PROTOLAYER_EVENT_TIMEOUT) {
- if (session->connected)
- return pl_dns_stream_resolution_timeout(manager->session);
- else
- return pl_dns_stream_connection_fail(manager->session,
- KR_SELECTION_TCP_CONNECT_TIMEOUT);
+ if (event == PROTOLAYER_EVENT_GENERAL_TIMEOUT) {
+ return pl_dns_stream_resolution_timeout(manager->session);
+ } else if (event == PROTOLAYER_EVENT_CONNECT_TIMEOUT) {
+ return pl_dns_stream_connection_fail(manager->session,
+ KR_SELECTION_TCP_CONNECT_TIMEOUT);
} else if (event == PROTOLAYER_EVENT_CONNECT) {
return pl_dns_stream_connected(session);
} else if (event == PROTOLAYER_EVENT_DISCONNECT