summaryrefslogtreecommitdiffstats
path: root/daemon/session2.c
diff options
context:
space:
mode:
authorOto Šťáva <oto.stava@nic.cz>2024-05-31 12:09:42 +0200
committerOto Šťáva <oto.stava@nic.cz>2024-06-04 13:05:00 +0200
commit0a1f0024e0cdc3d18ac508b7ce759316338252bb (patch)
treec66ce82681df3c7d7257cb40d01edde9c086a181 /daemon/session2.c
parentSome more Clang-Tidy silencing (diff)
downloadknot-resolver-0a1f0024e0cdc3d18ac508b7ce759316338252bb.tar.xz
knot-resolver-0a1f0024e0cdc3d18ac508b7ce759316338252bb.zip
daemon/session2: fix asynchronous layer iterations
There were a few bugs in the protolayer system that prevented us from pausing iteration and resuming it properly. This commit should hopefully resolve them.
Diffstat (limited to 'daemon/session2.c')
-rw-r--r--daemon/session2.c126
1 files changed, 83 insertions, 43 deletions
diff --git a/daemon/session2.c b/daemon/session2.c
index 1a9068e4..19ea42dc 100644
--- a/daemon/session2.c
+++ b/daemon/session2.c
@@ -406,7 +406,7 @@ static int protolayer_iter_ctx_finish(struct protolayer_iter_ctx *ctx, int ret)
ctx->layer_ix, layer_name_ctx(ctx), ctx->status);
if (ctx->finished_cb)
- ctx->finished_cb(ret, s, &ctx->comm,
+ ctx->finished_cb(ret, s, ctx->comm,
ctx->finished_cb_baton);
mm_ctx_delete(&ctx->pool);
@@ -440,12 +440,12 @@ static int protolayer_push(struct protolayer_iter_ctx *ctx)
session2_transport_push(session,
ctx->payload.buffer.buf, ctx->payload.buffer.len,
ctx->payload.short_lived,
- &ctx->comm, protolayer_push_finished, ctx);
+ ctx->comm, protolayer_push_finished, ctx);
} else if (ctx->payload.type == PROTOLAYER_PAYLOAD_IOVEC) {
session2_transport_pushv(session,
ctx->payload.iovec.iov, ctx->payload.iovec.cnt,
ctx->payload.short_lived,
- &ctx->comm, protolayer_push_finished, ctx);
+ ctx->comm, protolayer_push_finished, ctx);
} else {
kr_assert(false && "Invalid payload type");
return kr_error(EINVAL);
@@ -473,8 +473,9 @@ static void protolayer_payload_ensure_long_lived(struct protolayer_iter_ctx *ctx
/** Processes as many layers as possible synchronously, returning when either
* a layer has gone asynchronous, or when the whole sequence has finished.
*
- * May be called multiple times on the same `ctx` to continue processing
- * after an asynchronous operation. */
+ * May be called multiple times on the same `ctx` to continue processing after
+ * an asynchronous operation - user code will do this via *layer sequence return
+ * functions*. */
static int protolayer_step(struct protolayer_iter_ctx *ctx)
{
while (true) {
@@ -484,38 +485,52 @@ static int protolayer_step(struct protolayer_iter_ctx *ctx)
enum protolayer_type protocol = protolayer_grps[ctx->session->proto].layers[ctx->layer_ix];
struct protolayer_globals *globals = &protolayer_globals[protocol];
+ bool was_async = ctx->async_mode;
ctx->async_mode = false;
- ctx->status = 0;
- ctx->action = PROTOLAYER_ITER_ACTION_NULL;
- protolayer_iter_cb cb = (ctx->direction == PROTOLAYER_UNWRAP)
- ? globals->unwrap : globals->wrap;
+ /* Basically if we went asynchronous, we want to "resume" from
+ * underneath this `if` block. */
+ if (!was_async) {
+ ctx->status = 0;
+ ctx->action = PROTOLAYER_ITER_ACTION_NULL;
- if (ctx->session->closing) {
- return protolayer_iter_ctx_finish(
- ctx, kr_error(ECANCELED));
- }
+ protolayer_iter_cb cb = (ctx->direction == PROTOLAYER_UNWRAP)
+ ? globals->unwrap : globals->wrap;
- if (cb) {
- struct protolayer_data *sess_data = protolayer_sess_data_get(
- ctx->session, ctx->layer_ix);
- struct protolayer_data *iter_data = protolayer_iter_data_get(
- ctx, ctx->layer_ix);
- enum protolayer_iter_cb_result result = cb(sess_data, iter_data, ctx);
- if (kr_fails_assert(result == PROTOLAYER_ITER_CB_RESULT_MAGIC)) {
- /* Callback did not use a continuation function to return. */
- return protolayer_iter_ctx_finish(ctx, kr_error(EINVAL));
+ if (ctx->session->closing) {
+ return protolayer_iter_ctx_finish(
+ ctx, kr_error(ECANCELED));
}
- } else {
- ctx->action = PROTOLAYER_ITER_ACTION_CONTINUE;
- }
+ if (cb) {
+ struct protolayer_data *sess_data = protolayer_sess_data_get(
+ ctx->session, ctx->layer_ix);
+ struct protolayer_data *iter_data = protolayer_iter_data_get(
+ ctx, ctx->layer_ix);
+ enum protolayer_iter_cb_result result = cb(sess_data, iter_data, ctx);
+ if (kr_fails_assert(result == PROTOLAYER_ITER_CB_RESULT_MAGIC)) {
+ /* Callback did not use a *layer
+ * sequence return function* (see
+ * glossary). */
+ return protolayer_iter_ctx_finish(ctx, kr_error(EINVAL));
+ }
+ } else {
+ ctx->action = PROTOLAYER_ITER_ACTION_CONTINUE;
+ }
+
+ if (!ctx->action) {
+ /* We're going asynchronous - the next step is
+ * probably going to be from some sort of a
+ * callback and we will "resume" from underneath
+ * this `if` block. */
+ ctx->async_mode = true;
+ protolayer_payload_ensure_long_lived(ctx);
+ return PROTOLAYER_RET_ASYNC;
+ }
+ }
- if (!ctx->action) {
- /* Next step is from a callback */
- ctx->async_mode = true;
- protolayer_payload_ensure_long_lived(ctx);
- return PROTOLAYER_RET_ASYNC;
+ if (kr_fails_assert(ctx->action)) {
+ return protolayer_iter_ctx_finish(ctx, kr_error(EINVAL));
}
if (ctx->action == PROTOLAYER_ITER_ACTION_BREAK) {
@@ -525,7 +540,7 @@ static int protolayer_step(struct protolayer_iter_ctx *ctx)
if (kr_fails_assert(ctx->status == 0)) {
/* Status should be zero without a BREAK. */
- return protolayer_iter_ctx_finish(ctx, kr_error(ECANCELED));
+ return protolayer_iter_ctx_finish(ctx, kr_error(EINVAL));
}
if (ctx->action == PROTOLAYER_ITER_ACTION_CONTINUE) {
@@ -566,6 +581,10 @@ static int session2_submit(
if (kr_fails_assert(session->proto < KR_PROTO_COUNT))
return kr_error(EFAULT);
+ bool had_comm_param = (comm != NULL);
+ if (!had_comm_param)
+ comm = &session->comm_storage;
+
struct protolayer_iter_ctx *ctx = malloc(session->iter_ctx_size);
kr_require(ctx);
@@ -578,13 +597,33 @@ static int session2_submit(
*ctx = (struct protolayer_iter_ctx) {
.payload = payload,
- .comm = (comm) ? *comm : session->comm,
.direction = direction,
.layer_ix = layer_ix,
.session = session,
.finished_cb = cb,
.finished_cb_baton = baton
};
+ if (had_comm_param) {
+ struct comm_addr_storage *addrst = &ctx->comm_addr_storage;
+ if (comm->src_addr) {
+ memcpy(&addrst->src_addr.ip, comm->src_addr,
+ kr_sockaddr_len(comm->src_addr));
+ ctx->comm_storage.src_addr = &addrst->src_addr.ip;
+ }
+ if (comm->comm_addr) {
+ memcpy(&addrst->comm_addr.ip, comm->comm_addr,
+ kr_sockaddr_len(comm->comm_addr));
+ ctx->comm_storage.comm_addr = &addrst->comm_addr.ip;
+ }
+ if (comm->dst_addr) {
+ memcpy(&addrst->dst_addr.ip, comm->dst_addr,
+ kr_sockaddr_len(comm->dst_addr));
+ ctx->comm_storage.dst_addr = &addrst->dst_addr.ip;
+ }
+ ctx->comm = &ctx->comm_storage;
+ } else {
+ ctx->comm = &session->comm_storage;
+ }
mm_ctx_mempool(&ctx->pool, CPU_PAGE_SIZE);
const struct protolayer_grp *grp = &protolayer_grps[session->proto];
@@ -616,25 +655,26 @@ static void *get_init_param(enum protolayer_type p,
return NULL;
}
-enum protolayer_iter_cb_result protolayer_continue(struct protolayer_iter_ctx *ctx)
+/** Called by *Layer sequence return functions* to proceed with protolayer
+ * processing. If the */
+static inline void maybe_async_do_step(struct protolayer_iter_ctx *ctx)
{
- if (ctx->async_mode) {
- protolayer_iter_ctx_next(ctx);
+ if (ctx->async_mode)
protolayer_step(ctx);
- } else {
- ctx->action = PROTOLAYER_ITER_ACTION_CONTINUE;
- }
+}
+
+enum protolayer_iter_cb_result protolayer_continue(struct protolayer_iter_ctx *ctx)
+{
+ ctx->action = PROTOLAYER_ITER_ACTION_CONTINUE;
+ maybe_async_do_step(ctx);
return PROTOLAYER_ITER_CB_RESULT_MAGIC;
}
enum protolayer_iter_cb_result protolayer_break(struct protolayer_iter_ctx *ctx, int status)
{
ctx->status = status;
- if (ctx->async_mode) {
- protolayer_iter_ctx_finish(ctx, PROTOLAYER_RET_NORMAL);
- } else {
- ctx->action = PROTOLAYER_ITER_ACTION_BREAK;
- }
+ ctx->action = PROTOLAYER_ITER_ACTION_BREAK;
+ maybe_async_do_step(ctx);
return PROTOLAYER_ITER_CB_RESULT_MAGIC;
}