diff --git a/daemon/io.c b/daemon/io.c index 1a69dbeeb012143c85fc0c312522465217613fd5..5d1e9837d9ffd8930310ecad209af16545f182e7 100644 --- a/daemon/io.c +++ b/daemon/io.c @@ -208,7 +208,7 @@ static void tcp_recv(uv_stream_t *handle, ssize_t nread, const uv_buf_t *buf) * so the whole message reassembly and demuxing logic is inside worker */ int ret = 0; if (s->has_tls) { - ret = worker_process_tls(worker, handle, (const uint8_t *)buf->base, nread); + ret = tls_process(worker, handle, (const uint8_t *)buf->base, nread); } else { ret = worker_process_tcp(worker, handle, (const uint8_t *)buf->base, nread); } diff --git a/daemon/tls.c b/daemon/tls.c index 56b449e8e0af8cf851aa8ec735e55ae8a1d624f5..b6fdac8368910d9ddad1b5b32cc07c3532e286ed 100644 --- a/daemon/tls.c +++ b/daemon/tls.c @@ -41,10 +41,6 @@ struct tls_ctx_t { ssize_t nread; ssize_t consumed; uint8_t recv_buf[4096]; - - /* for writing to the network */ - uv_write_t *writer; - uv_write_cb write_cb; }; /** @internal Debugging facility. */ @@ -109,38 +105,6 @@ kres_gnutls_pull(gnutls_transport_ptr_t h, void *buf, size_t len) return transfer; } -static ssize_t -kres_gnutls_push_vec(gnutls_transport_ptr_t h, const giovec_t * iov, int iovcnt) -{ - struct tls_ctx_t *t = (struct tls_ctx_t *)h; - int ret; - - DEBUG_MSG("vecpush %d (%p) handle: <%p> writer <%p>\n", iovcnt, iov, t->handle, t->writer); - - /* - * because of the struct of giovec_t is identical to struct iovec; - * and uv_buf_t header (uv-unix.h) says it may be cast to struct - * iovec; so we should be able to just cast directly. - */ - ret = uv_write(t->writer, t->handle, (uv_buf_t *) iov, iovcnt, t->write_cb); - if (ret >= 0) { - /* Pending ioreq on current task */ - return (ssize_t) ret; - } - switch (ret) { - case UV_EAGAIN: - errno = EAGAIN; - break; - case UV_EINTR: - errno = EINTR; - break; - default: - kr_log_error("[tls] uv_write unknown error: %d\n", ret); - errno = EIO; /* dkg just picked this at random */ - } - return -1; -} - struct tls_ctx_t * tls_new(struct worker_ctx *worker) { @@ -236,65 +200,50 @@ tls_free(struct tls_ctx_t *tls) free(tls); } -int -push_tls(struct qr_task *task, uv_handle_t * handle, knot_pkt_t * pkt, - uv_write_t * writer, qr_task_send_cb on_send) +int tls_push(struct qr_task *task, uv_handle_t* handle, knot_pkt_t * pkt) { - ssize_t count; - if (!pkt) { - kr_log_error("[tls] cannot push null packet\n"); - return on_send(task, handle, kr_error(EIO)); + if (!pkt || !handle || !handle->data) { + return kr_error(EINVAL); } - uint16_t pkt_size = htons(pkt->size); + ssize_t count; struct session *session = handle->data; - if (!session) { - kr_log_error("[tls] no session on push\n"); - return on_send(task, handle, kr_error(EIO)); - } + uint16_t pkt_size = htons(pkt->size); struct tls_ctx_t *tls_p = session->tls_ctx; if (!tls_p) { kr_log_error("[tls] no tls context on push\n"); - /* FIXME: might be necessary if we ever do outbound TLS */ - return on_send(task, handle, kr_error(EIO)); + return kr_error(ENOENT); } - tls_p->handle = (uv_stream_t *) handle; - tls_p->writer = writer; gnutls_record_cork(tls_p->session); count = gnutls_record_send(tls_p->session, &pkt_size, sizeof(pkt_size)); if (count != sizeof(pkt_size)) { kr_log_error("[tls] gnutls_record_send pkt_size fail wanted: %u (%zd) %s\n", pkt_size, count, gnutls_strerror_name(count)); - return on_send(task, handle, kr_error(EIO)); + return kr_error(EIO); } count = gnutls_record_send(tls_p->session, pkt->wire, pkt->size); if (count != pkt->size) { kr_log_error("[tls] gnutls_record_send wire fail wanted: %zu (%zd) %s\n", pkt->size, count, gnutls_strerror_name(count)); - return on_send(task, handle, kr_error(EIO)); + return kr_error(EIO); } count = gnutls_record_uncork(tls_p->session, 0); if (count != sizeof(pkt_size) + pkt->size) { if (count == GNUTLS_E_AGAIN || count == GNUTLS_E_INTERRUPTED) { kr_log_error("[tls] gnutls_record_send incomplete: %zu (%zd) %s\n", pkt->size, count, gnutls_strerror_name(count)); - /* - * FIXME: we need to know when this frees up; when it - * does, we should do gnutls_record_send(tls.session, - * NULL, 0); how do i know? - */ + return kr_error(EAGAIN); } else { kr_log_error("[tls] gnutls_record_send wire fail wanted: %zu (%zd) %s\n", pkt->size, count, gnutls_strerror_name(count)); } - return on_send(task, handle, kr_error(EIO)); + return kr_error(EIO); } - return count; + return 0; } -int -worker_process_tls(struct worker_ctx *worker, uv_stream_t * handle, const uint8_t * buf, ssize_t nread) +int tls_process(struct worker_ctx *worker, uv_stream_t * handle, const uint8_t * buf, ssize_t nread) { struct session *session = handle->data; struct tls_ctx_t *tls_p = session->tls_ctx; diff --git a/daemon/tls.h b/daemon/tls.h index 14646272b25f356c4ec47b7e53380caf605eceed..fdce96bd761d4142daffcec8722c67da4aa59487 100644 --- a/daemon/tls.h +++ b/daemon/tls.h @@ -24,7 +24,5 @@ struct tls_ctx_t; struct tls_ctx_t* tls_new(struct worker_ctx *worker); void tls_free(struct tls_ctx_t* tls); -int push_tls(struct qr_task *task, uv_handle_t *handle, knot_pkt_t *pkt, - uv_write_t *writer, qr_task_send_cb on_send); - -int worker_process_tls(struct worker_ctx *worker, uv_stream_t *handle, const uint8_t *buf, ssize_t nread); +int tls_push(struct qr_task *task, uv_handle_t* handle, knot_pkt_t * pkt); +int tls_process(struct worker_ctx *worker, uv_stream_t *handle, const uint8_t *buf, ssize_t nread); diff --git a/daemon/worker.c b/daemon/worker.c index 3a5380f11c2b699c2800961d761161d0ba0beca7..1ab3d5d76ebdcda62eaa4b3ca0b8bdd9279b7da1 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -444,30 +444,32 @@ static int qr_task_send(struct qr_task *task, uv_handle_t *handle, struct sockad if (!handle) { return qr_task_on_send(task, handle, kr_error(EIO)); } - struct req *send_req = req_borrow(task->worker); - if (!send_req) { - return qr_task_on_send(task, handle, kr_error(ENOMEM)); + + /* Synchronous push to TLS context, bypassing event loop. */ + struct session *session = handle->data; + if (session->has_tls) { + int ret = tls_push(task, handle, pkt); + return qr_task_on_send(task, handle, ret); } /* Send using given protocol */ int ret = 0; + struct req *send_req = req_borrow(task->worker); + if (!send_req) { + return qr_task_on_send(task, handle, kr_error(ENOMEM)); + } if (handle->type == UV_UDP) { uv_buf_t buf = { (char *)pkt->wire, pkt->size }; send_req->as.send.data = task; ret = uv_udp_send(&send_req->as.send, (uv_udp_t *)handle, &buf, 1, addr, &on_send); } else { - struct session *session = handle->data; - if (session->has_tls) { - ret = push_tls(task, handle, pkt, &send_req->as.write, qr_task_on_send); - } else { - uint16_t pkt_size = htons(pkt->size); - uv_buf_t buf[2] = { - { (char *)&pkt_size, sizeof(pkt_size) }, - { (char *)pkt->wire, pkt->size } - }; - send_req->as.write.data = task; - ret = uv_write(&send_req->as.write, (uv_stream_t *)handle, buf, 2, &on_write); - } + uint16_t pkt_size = htons(pkt->size); + uv_buf_t buf[2] = { + { (char *)&pkt_size, sizeof(pkt_size) }, + { (char *)pkt->wire, pkt->size } + }; + send_req->as.write.data = task; + ret = uv_write(&send_req->as.write, (uv_stream_t *)handle, buf, 2, &on_write); } if (ret == 0) { qr_task_ref(task); /* Pending ioreq on current task */