]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
daemon: avoid uv_try_write() usage both in tls-client and tls-server side; bugfixes
authorGrigorii Demidov <grigorii.demidov@nic.cz>
Tue, 6 Feb 2018 16:41:06 +0000 (17:41 +0100)
committerPetr Spacek <pspacek@knot-comcast-1.labs.office.nic.cz>
Thu, 8 Feb 2018 13:11:23 +0000 (14:11 +0100)
daemon/io.c
daemon/tls.c
daemon/tls.h
daemon/worker.c
daemon/worker.h

index 13909a3a1508e5a9e996d3bc6a77a4a1acff25e5..d0235f94809e0c8cff17b56a70f27f2218faa056 100644 (file)
@@ -298,6 +298,7 @@ static void _tcp_accept(uv_stream_t *master, int status, bool tls)
        session->has_tls = tls;
        if (tls && !session->tls_ctx) {
                session->tls_ctx = tls_new(master->loop->data);
+               session->tls_ctx->session = session;
        }
        uv_timer_t *timer = &session->timeout;
        uv_timer_start(timer, tcp_timeout_trigger, KR_CONN_RTT_MAX/2, KR_CONN_RTT_MAX/2);
index b5378f4d4c6771cdac1ea69bbbac9ad75d63ba3b..56117a1b6e0684c236c1026cca170a0870d79ebf 100644 (file)
 #define EPHEMERAL_CERT_EXPIRATION_SECONDS_RENEW_BEFORE 60*60*24*7
 #define GNUTLS_PIN_MIN_VERSION  0x030400
 
-struct tls_client_ctx_t {
-       gnutls_session_t tls_session;
-       tls_client_hs_state_t handshake_state;
-
-       struct session *session;
-       tls_handshake_cb handshake_cb;
-       const uint8_t *buf;
-       ssize_t nread;
-       ssize_t consumed;
-       uint8_t recv_buf[4096];
-       const struct tls_client_paramlist_entry *params;
-};
-
 /** @internal Debugging facility. */
 #ifdef DEBUG
 #define DEBUG_MSG(fmt...) kr_log_verbose("[tls] " fmt)
@@ -79,32 +66,6 @@ static int kres_gnutls_set_priority(gnutls_session_t session) {
        return err;
 }
 
-
-static ssize_t kres_gnutls_push(gnutls_transport_ptr_t h, const void *buf, size_t len)
-{
-       struct tls_ctx_t *t = (struct tls_ctx_t *)h;
-       const uv_buf_t ub = {(void *)buf, len};
-
-       DEBUG_MSG("[tls] push %zu <%p>\n", len, h);
-       if (t == NULL) {
-               errno = EFAULT;
-               return -1;
-       }
-
-       int ret = uv_try_write(t->handle, &ub, 1);
-       if (ret > 0) {
-               return (ssize_t) ret;
-       }
-       if (ret == UV_EAGAIN) {
-               errno = EAGAIN;
-       } else {
-               kr_log_error("[tls] uv_try_write: %s\n", uv_strerror(ret));
-               errno = EIO;
-       }
-       return -1;
-}
-
-
 static ssize_t kres_gnutls_pull(gnutls_transport_ptr_t h, void *buf, size_t len)
 {
        struct tls_ctx_t *t = (struct tls_ctx_t *)h;
@@ -168,32 +129,48 @@ struct tls_ctx_t *tls_new(struct worker_ctx *worker)
                return NULL;
        }
 
-       int err = gnutls_init(&tls->session, GNUTLS_SERVER | GNUTLS_NONBLOCK);
+       int err = gnutls_init(&tls->tls_session, GNUTLS_SERVER | GNUTLS_NONBLOCK);
        if (err != GNUTLS_E_SUCCESS) {
                kr_log_error("[tls] gnutls_init(): %s (%d)\n", gnutls_strerror_name(err), err);
                tls_free(tls);
                return NULL;
        }
        tls->credentials = tls_credentials_reserve(net->tls_credentials);
-       err = gnutls_credentials_set(tls->session, GNUTLS_CRD_CERTIFICATE, tls->credentials->credentials);
+       err = gnutls_credentials_set(tls->tls_session, GNUTLS_CRD_CERTIFICATE, tls->credentials->credentials);
        if (err != GNUTLS_E_SUCCESS) {
                kr_log_error("[tls] gnutls_credentials_set(): %s (%d)\n", gnutls_strerror_name(err), err);
                tls_free(tls);
                return NULL;
        }
-       if (kres_gnutls_set_priority(tls->session) != GNUTLS_E_SUCCESS) {
+       if (kres_gnutls_set_priority(tls->tls_session) != GNUTLS_E_SUCCESS) {
                tls_free(tls);
                return NULL;
        }
 
        tls->worker = worker;
 
-       gnutls_transport_set_pull_function(tls->session, kres_gnutls_pull);
-       gnutls_transport_set_push_function(tls->session, worker_gnutls_push);
-       gnutls_transport_set_ptr(tls->session, tls);
+       gnutls_transport_set_pull_function(tls->tls_session, kres_gnutls_pull);
+       gnutls_transport_set_push_function(tls->tls_session, worker_gnutls_push);
+       gnutls_transport_set_ptr(tls->tls_session, tls);
        return tls;
 }
 
+void tls_close(struct tls_ctx_t *ctx)
+{
+       if (ctx == NULL || ctx->tls_session == NULL) {
+               return;
+       }
+
+       assert(ctx->session);
+
+       if (ctx->handshake_done) {
+               DEBUG_MSG("[tls] closing tls connection to `%s`\n",
+                         kr_straddr(&ctx->session->peer.ip));
+               ctx->handshake_done = false;
+               gnutls_bye(ctx->tls_session, GNUTLS_SHUT_RDWR);
+       }
+}
+
 void tls_free(struct tls_ctx_t *tls)
 {
        if (!tls) {
@@ -202,15 +179,16 @@ void tls_free(struct tls_ctx_t *tls)
 
        if (tls->session) {
                /* Don't terminate TLS connection, just tear it down */
-               gnutls_deinit(tls->session);
-               tls->session = NULL;
+               gnutls_deinit(tls->tls_session);
+               tls->tls_session = NULL;
        }
 
        tls_credentials_release(tls->credentials);
        free(tls);
 }
 
-int tls_push(struct qr_task *task, uv_handle_t *handle, knot_pkt_t *pkt)
+int tls_push(struct qr_task *task, uv_handle_t *handle, knot_pkt_t *pkt,
+            bool server_side)
 {
        if (!pkt || !handle || !handle->data) {
                return kr_error(EINVAL);
@@ -218,51 +196,66 @@ int tls_push(struct qr_task *task, uv_handle_t *handle, knot_pkt_t *pkt)
 
        struct session *session = handle->data;
        const 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");
-               return kr_error(ENOENT);
+       static char const server_logstring[] = "tls";
+       static char const client_logstring[] = "tls-client";
+       const char *logstring = client_logstring;
+       gnutls_session_t tls_session = NULL;
+
+       if (server_side) {
+               logstring = server_logstring;
+               if (!session->tls_ctx) {
+                       kr_log_error("[%s] no tls context on push\n", logstring);
+                       return kr_error(ENOENT);
+               }
+               session->tls_ctx->task = task;
+               tls_session = session->tls_ctx->tls_session;
+       } else {
+               if (!session->tls_client_ctx) {
+                       kr_log_error("[%s] no tls context on push\n", logstring);
+                       return kr_error(ENOENT);
+               }
+               session->tls_client_ctx->task = task;
+               tls_session = session->tls_client_ctx->tls_session;
        }
 
-       assert(gnutls_record_check_corked(tls_p->session) == 0);
+       assert(gnutls_record_check_corked(tls_session) == 0);
 
-       tls_p->task = task;
-
-       gnutls_record_cork(tls_p->session);
+       gnutls_record_cork(tls_session);
        ssize_t count = 0;
-       if ((count = gnutls_record_send(tls_p->session, &pkt_size, sizeof(pkt_size)) < 0) ||
-           (count = gnutls_record_send(tls_p->session, pkt->wire, pkt->size) < 0)) {
-               kr_log_error("[tls] gnutls_record_send failed: %s (%zd)\n", gnutls_strerror_name(count), count);
+       if ((count = gnutls_record_send(tls_session, &pkt_size, sizeof(pkt_size)) < 0) ||
+           (count = gnutls_record_send(tls_session, pkt->wire, pkt->size) < 0)) {
+               kr_log_error("[%s] gnutls_record_send failed: %s (%zd)\n",
+                            logstring, gnutls_strerror_name(count), count);
                return kr_error(EIO);
        }
 
        ssize_t submitted = 0;
        ssize_t retries = 0;
        do {
-               count = gnutls_record_uncork(tls_p->session, 0);
+               count = gnutls_record_uncork(tls_session, 0);
                if (count < 0) {
                        if (gnutls_error_is_fatal(count)) {
-                               kr_log_error("[tls] gnutls_record_uncork failed: %s (%zd)\n",
-                                            gnutls_strerror_name(count), count);
+                               kr_log_error("[%s] gnutls_record_uncork failed: %s (%zd)\n",
+                                            logstring, gnutls_strerror_name(count), count);
                                return kr_error(EIO);
                        }
                        if (++retries > TLS_MAX_UNCORK_RETRIES) {
-                               kr_log_error("[tls] gnutls_record_uncork: too many sequential non-fatal errors (%zd), last error is: %s (%zd)\n",
-                                            retries, gnutls_strerror_name(count), count);
+                               kr_log_error("[%s] gnutls_record_uncork: too many sequential non-fatal errors (%zd), last error is: %s (%zd)\n",
+                                            logstring, retries, gnutls_strerror_name(count), count);
                                return kr_error(EIO);
                        }
                } else if (count != 0) {
                        submitted += count;
                        retries = 0;
-               } else if (gnutls_record_check_corked(tls_p->session) != 0) {
+               } else if (gnutls_record_check_corked(tls_session) != 0) {
                        if (++retries > TLS_MAX_UNCORK_RETRIES) {
-                               kr_log_error("[tls] gnutls_record_uncork: too many retries (%zd)\n",
-                                            retries);
+                               kr_log_error("[%s] gnutls_record_uncork: too many retries (%zd)\n",
+                                            logstring, retries);
                                return kr_error(EIO);
                        }
                } else if (submitted != sizeof(pkt_size) + pkt->size) {
-                       kr_log_error("[tls] gnutls_record_uncork didn't send all data(%zd of %zd)\n",
-                                    submitted, sizeof(pkt_size) + pkt->size);
+                       kr_log_error("[%s] gnutls_record_uncork didn't send all data(%zd of %zd)\n",
+                                    logstring, submitted, sizeof(pkt_size) + pkt->size);
                        return kr_error(EIO);
                }
        } while (submitted != sizeof(pkt_size) + pkt->size);
@@ -278,15 +271,18 @@ int tls_process(struct worker_ctx *worker, uv_stream_t *handle, const uint8_t *b
                return kr_error(ENOSYS);
        }
 
+       assert(tls_p->session == session);
+
        tls_p->buf = buf;
        tls_p->nread = nread >= 0 ? nread : 0;
-       tls_p->handle = handle;
        tls_p->consumed = 0;    /* TODO: doesn't handle split TLS records */
 
        /* Ensure TLS handshake is performed before receiving data. */
        while (!tls_p->handshake_done) {
-               int err = gnutls_handshake(tls_p->session);
+               int err = gnutls_handshake(tls_p->tls_session);
                if (err == GNUTLS_E_SUCCESS) {
+                       DEBUG_MSG("[tls] TLS handshake with %s has completed\n",
+                                 kr_straddr(&session->peer.ip));
                        tls_p->handshake_done = true;
                } else if (err == GNUTLS_E_AGAIN) {
                        return 0; /* No data, bail out */
@@ -297,7 +293,7 @@ int tls_process(struct worker_ctx *worker, uv_stream_t *handle, const uint8_t *b
 
        int submitted = 0;
        while (true) {
-               ssize_t count = gnutls_record_recv(tls_p->session, tls_p->recv_buf, sizeof(tls_p->recv_buf));
+               ssize_t count = gnutls_record_recv(tls_p->tls_session, tls_p->recv_buf, sizeof(tls_p->recv_buf));
                if (count == GNUTLS_E_AGAIN) {
                        break;    /* No data available */
                } else if (count == GNUTLS_E_INTERRUPTED) {
@@ -806,38 +802,13 @@ skip_pins:
        return GNUTLS_E_CERTIFICATE_ERROR;
 }
 
-static ssize_t kres_gnutls_client_push(gnutls_transport_ptr_t h, const void *buf, size_t len)
-{
-       struct tls_client_ctx_t *t = (struct tls_client_ctx_t *)h;
-       const uv_buf_t ub = {(void *)buf, len};
-
-       DEBUG_MSG("[tls_client] push %zu <%p>\n", len, h);
-       if (t == NULL) {
-               errno = EFAULT;
-               return -1;
-       }
-
-       int ret = uv_try_write((uv_stream_t *)t->session->handle, &ub, 1);
-       if (ret > 0) {
-               return (ssize_t) ret;
-       }
-       if (ret == UV_EAGAIN) {
-               errno = EAGAIN;
-       } else {
-               kr_log_error("[tls_client] uv_try_write: %s\n", uv_strerror(ret));
-               errno = EIO;
-       }
-       return -1;
-}
-
-
 static ssize_t kres_gnutls_client_pull(gnutls_transport_ptr_t h, void *buf, size_t len)
 {
        struct tls_client_ctx_t *t = (struct tls_client_ctx_t *)h;
        assert(t != NULL);
 
        ssize_t avail = t->nread - t->consumed;
-       DEBUG_MSG("[tls] pull wanted: %zu available: %zu\n", len, avail);
+       DEBUG_MSG("[tls_client] pull wanted: %zu available: %zu\n", len, avail);
        if (t->nread <= t->consumed) {
                errno = EAGAIN;
                return -1;
@@ -933,7 +904,8 @@ int tls_client_process(struct worker_ctx *worker, uv_stream_t *handle, const uin
                if (ctx->handshake_cb) {
                        ctx->handshake_cb(ctx->session, 0);
                }
-               DEBUG_MSG("[tls_client] TLS handshake with %s has completed.\n", kr_straddr(&session->peer.ip));
+               DEBUG_MSG("[tls_client] TLS handshake with %s has completed.\n",
+                         kr_straddr(&session->peer.ip));
        }
 
        int submitted = 0;
@@ -961,7 +933,8 @@ int tls_client_process(struct worker_ctx *worker, uv_stream_t *handle, const uin
        return submitted;
 }
 
-struct tls_client_ctx_t *tls_client_ctx_new(const struct tls_client_paramlist_entry *entry)
+struct tls_client_ctx_t *tls_client_ctx_new(const struct tls_client_paramlist_entry *entry,
+                                           struct worker_ctx *worker)
 {
        struct tls_client_ctx_t *ctx = calloc(1, sizeof (struct tls_client_ctx_t));
        if (!ctx) {
@@ -987,8 +960,10 @@ struct tls_client_ctx_t *tls_client_ctx_new(const struct tls_client_paramlist_en
                return NULL;
        }
 
+       ctx->worker = worker;
+
        gnutls_transport_set_pull_function(ctx->tls_session, kres_gnutls_client_pull);
-       gnutls_transport_set_push_function(ctx->tls_session, kres_gnutls_client_push);
+       gnutls_transport_set_push_function(ctx->tls_session, worker_gnutls_client_push);
        gnutls_transport_set_ptr(ctx->tls_session, ctx);
        return ctx;
 }
@@ -999,8 +974,9 @@ void tls_client_ctx_free(struct tls_client_ctx_t *ctx)
                return;
        }
 
-       if (ctx->session != NULL) {
+       if (ctx->tls_session != NULL) {
                gnutls_deinit(ctx->tls_session);
+               ctx->tls_session = NULL;
        }
 
        free (ctx);
@@ -1035,11 +1011,16 @@ int tls_client_connect_start(struct tls_client_ctx_t *ctx,
 
 void tls_client_close(struct tls_client_ctx_t *ctx)
 {
-       if (ctx == NULL || ctx->session == NULL) {
+       if (ctx == NULL || ctx->tls_session == NULL) {
                return;
        }
 
+       assert(ctx->session);
+
        if (ctx->handshake_state == TLS_HS_DONE) {
+               DEBUG_MSG("[tls client] closing tls connection to `%s`\n",
+                         kr_straddr(&ctx->session->peer.ip));
+               ctx->handshake_state = TLS_HS_CLOSING;
                gnutls_bye(ctx->tls_session, GNUTLS_SHUT_RDWR);
        }
 }
index 45ffcb142cc286ae85790bc1e6a4f8d9e64e7fcc..7285b40482e0135ba4c8b55e0a6cbc690dd50abf 100644 (file)
@@ -49,10 +49,10 @@ struct qr_task;
 
 /* gnutls_record_recv and gnutls_record_send */
 struct tls_ctx_t {
-       gnutls_session_t session;
+       gnutls_session_t tls_session;
        bool handshake_done;
 
-       uv_stream_t *handle;
+       struct session *session;
 
        /* for reading from the network */
        const uint8_t *buf;
@@ -68,19 +68,39 @@ typedef enum tls_client_hs_state {
        TLS_HS_NOT_STARTED = 0,
        TLS_HS_IN_PROGRESS,
        TLS_HS_DONE,
+       TLS_HS_CLOSING,
        TLS_HS_LAST
 } tls_client_hs_state_t;
 
 typedef int (*tls_handshake_cb) (struct session *session, int status);
 
+struct tls_client_ctx_t {
+       gnutls_session_t tls_session;
+       tls_client_hs_state_t handshake_state;
+
+       struct session *session;
+       tls_handshake_cb handshake_cb;
+       const uint8_t *buf;
+       ssize_t nread;
+       ssize_t consumed;
+       uint8_t recv_buf[4096];
+       const struct tls_client_paramlist_entry *params;
+       struct worker_ctx *worker;
+       struct qr_task *task;
+};
+
 /*! Create an empty TLS context in query context */
 struct tls_ctx_t* tls_new(struct worker_ctx *worker);
 
-/*! Close a TLS context */
+/*! Close a TLS context (call gnutls_bye()) */
+void tls_close(struct tls_ctx_t *tls);
+
+/*! Release a TLS context */
 void tls_free(struct tls_ctx_t* tls);
 
 /*! Push new data to TLS context for sending */
-int tls_push(struct qr_task *task, uv_handle_t* handle, knot_pkt_t * pkt);
+int tls_push(struct qr_task *task, uv_handle_t* handle, knot_pkt_t * pkt,
+            bool server_side);
 
 /*! Unwrap incoming data from a TLS stream and pass them to TCP session.
  * @return the number of newly-completed requests (>=0) or an error code
@@ -115,7 +135,8 @@ int tls_client_params_set(map_t *tls_client_paramlist,
 int tls_client_params_free(map_t *tls_client_paramlist);
 
 /*! Allocate new client TLS context */
-struct tls_client_ctx_t *tls_client_ctx_new(const struct tls_client_paramlist_entry *entry);
+struct tls_client_ctx_t *tls_client_ctx_new(const struct tls_client_paramlist_entry *entry,
+                                           struct worker_ctx *worker);
 
 int tls_client_process(struct worker_ctx *worker, uv_stream_t *handle,
                       const uint8_t *buf, ssize_t nread);
index e35524b1471e6ef75bb7ef81dbf62cb373195e9f..df73a5babe5e680523488a309ddb29d853d167a4 100644 (file)
@@ -369,6 +369,10 @@ static void session_close(struct session *session)
                if (session->tls_client_ctx) {
                        tls_client_close(session->tls_client_ctx);
                }
+               if (session->tls_ctx) {
+                       tls_close(session->tls_ctx);
+               }
+
                session->timeout.data = session;
                uv_close((uv_handle_t *)&session->timeout, on_session_timer_close);
        }
@@ -870,7 +874,7 @@ static void on_send(uv_udp_send_t *req, int status)
        iorequest_release(worker, req);
 }
 
-void on_write(uv_write_t *req, int status)
+static void on_task_write(uv_write_t *req, int status)
 {
        uv_handle_t *handle = (uv_handle_t *)(req->handle);
        uv_loop_t *loop = handle->loop;
@@ -882,10 +886,21 @@ void on_write(uv_write_t *req, int status)
        iorequest_release(worker, req);
 }
 
+static void on_nontask_write(uv_write_t *req, int status)
+{
+       uv_handle_t *handle = (uv_handle_t *)(req->handle);
+       uv_loop_t *loop = handle->loop;
+       struct worker_ctx *worker = loop->data;
+       assert(worker == get_worker());
+       iorequest_release(worker, req);
+}
+
 ssize_t worker_gnutls_push(gnutls_transport_ptr_t h, const void *buf, size_t len)
 {
        struct tls_ctx_t *t = (struct tls_ctx_t *)h;
-       const uv_buf_t ub = {(void *)buf, len};
+       const uv_buf_t uv_buf[1] = {
+               { (char *)buf, len }
+       };
 
        VERBOSE_MSG(NULL,"[tls] push %zu <%p>\n", len, h);
        if (t == NULL) {
@@ -893,27 +908,69 @@ ssize_t worker_gnutls_push(gnutls_transport_ptr_t h, const void *buf, size_t len
                return -1;
        }
 
-       assert(t->handle);
-       assert(t->handle->type == UV_TCP);
+       assert(t->session && t->session->handle &&
+              t->session->handle->type == UV_TCP);
+
+       struct worker_ctx *worker = t->worker;
+       assert(worker);
 
-       if (!t->handshake_done) {
-               int ret = uv_try_write(t->handle, &ub, 1);
-               if (ret > 0) {
-                       return (ssize_t) ret;
+       void *ioreq = worker_iohandle_borrow(worker);
+       if (!ioreq) {
+               errno = EFAULT;
+               return -1;
+       }
+
+       uv_write_t *write_req = (uv_write_t *)ioreq;
+
+       struct qr_task *task = t->task;
+       uv_write_cb write_cb = on_task_write;
+       if (t->handshake_done) {
+               assert(task);
+       } else {
+               task = NULL;
+               write_cb = on_nontask_write;
+       }
+
+       write_req->data = task;
+
+       ssize_t ret = -1;
+       int res = uv_write(write_req, (uv_stream_t *)t->session->handle, uv_buf, 1, write_cb);
+       if (res == 0) {
+               if (task) {
+                       qr_task_ref(task); /* Pending ioreq on current task */
                }
-               if (ret == UV_EAGAIN) {
-                       errno = EAGAIN;
-               } else {
-                       kr_log_error("[tls] uv_try_write: %s\n", uv_strerror(ret));
-                       errno = EIO;
+               if (worker->too_many_open &&
+                   worker->stats.rconcurrent <
+                       worker->rconcurrent_highwatermark - 10) {
+                       worker->too_many_open = false;
                }
+               ret = len;
+       } else {
+               VERBOSE_MSG(NULL,"[tls] uv_write: %s\n", uv_strerror(res));
+               iorequest_release(worker, ioreq);
+               errno = EIO;
+               /* TODO ret == UV_EMFILE */
+       }
+       return ret;
+}
+
+ssize_t worker_gnutls_client_push(gnutls_transport_ptr_t h, const void *buf, size_t len)
+{
+       struct tls_client_ctx_t *t = (struct tls_client_ctx_t *)h;
+       const uv_buf_t uv_buf[1] = {
+               { (char *)buf, len }
+       };
+
+       VERBOSE_MSG(NULL,"[tls client] push %zu <%p>\n", len, h);
+       if (t == NULL) {
+               errno = EFAULT;
                return -1;
        }
+       assert(t->session && t->session->handle &&
+              t->session->handle->type == UV_TCP);
 
        struct worker_ctx *worker = t->worker;
-       struct qr_task *task = t->task;
-
-       assert(worker && task);
+       assert(worker);
 
        void *ioreq = worker_iohandle_borrow(worker);
        if (!ioreq) {
@@ -922,16 +979,24 @@ ssize_t worker_gnutls_push(gnutls_transport_ptr_t h, const void *buf, size_t len
        }
 
        uv_write_t *write_req = (uv_write_t *)ioreq;
-       uv_buf_t uv_buf[1] = {
-               { (char *)buf, len }
-       };
+
+       struct qr_task *task = t->task;
+       uv_write_cb write_cb = on_task_write;
+       if (t->handshake_state == TLS_HS_DONE) {
+               assert(task);
+       } else {
+               task = NULL;
+               write_cb = on_nontask_write;
+       }
 
        write_req->data = task;
 
        ssize_t ret = -1;
-       int res = uv_write(write_req, t->handle, uv_buf, 1, &on_write);
+       int res = uv_write(write_req, (uv_stream_t *)t->session->handle, uv_buf, 1, write_cb);
        if (res == 0) {
-               qr_task_ref(task); /* Pending ioreq on current task */
+               if (task) {
+                       qr_task_ref(task); /* Pending ioreq on current task */
+               }
                if (worker->too_many_open &&
                    worker->stats.rconcurrent <
                        worker->rconcurrent_highwatermark - 10) {
@@ -939,7 +1004,7 @@ ssize_t worker_gnutls_push(gnutls_transport_ptr_t h, const void *buf, size_t len
                }
                ret = len;
        } else {
-               VERBOSE_MSG(NULL,"[tls] uv_write: %s\n", uv_strerror(res));
+               VERBOSE_MSG(NULL,"[tls_client] uv_write: %s\n", uv_strerror(res));
                iorequest_release(worker, ioreq);
                errno = EIO;
                /* TODO ret == UV_EMFILE */
@@ -958,18 +1023,14 @@ static int qr_task_send(struct qr_task *task, uv_handle_t *handle, struct sockad
        assert(session->closing == false);
        if (session->has_tls) {
                struct kr_request *req = &task->ctx->req;
-               int ret = kr_ok();
-               if (!session->outgoing) {
-                       ret = tls_push(task, handle, pkt);
-               } else {
-                       ret = kr_resolve_checkout(req, NULL, addr,
-                                                 SOCK_STREAM, pkt);
+               if (session->outgoing) {
+                       int ret = kr_resolve_checkout(req, NULL, addr,
+                                                     SOCK_STREAM, pkt);
                        if (ret != kr_ok()) {
                                return ret;
                        }
-                       ret = tls_client_push(task, handle, pkt);
                }
-               return ret;
+               return tls_push(task, handle, pkt, !session->outgoing);
        }
 
        int ret = 0;
@@ -1015,7 +1076,7 @@ static int qr_task_send(struct qr_task *task, uv_handle_t *handle, struct sockad
                        { (char *)pkt->wire, pkt->size }
                };
                write_req->data = task;
-               ret = uv_write(write_req, (uv_stream_t *)handle, buf, 2, &on_write);
+               ret = uv_write(write_req, (uv_stream_t *)handle, buf, 2, &on_task_write);
        } else {
                assert(false);
        }
@@ -1698,7 +1759,7 @@ static int qr_task_step(struct qr_task *task,
                        struct tls_client_paramlist_entry *entry = map_get(&net->tls_client_params, key);
                        if (entry) {
                                assert(session->tls_client_ctx == NULL);
-                               struct tls_client_ctx_t *tls_ctx = tls_client_ctx_new(entry);
+                               struct tls_client_ctx_t *tls_ctx = tls_client_ctx_new(entry, worker);
                                if (!tls_ctx) {
                                        session_del_tasks(session, task);
                                        session_del_waiting(session, task);
index cac2a624423814a7ba4caba27584704c7907b83b..1a8161ac5103cadbd7a60efc49a01ee8c23e091e 100644 (file)
@@ -92,6 +92,8 @@ void worker_iohandle_release(struct worker_ctx *worker, void *h);
 
 ssize_t worker_gnutls_push(gnutls_transport_ptr_t h, const void *buf, size_t len);
 
+ssize_t worker_gnutls_client_push(gnutls_transport_ptr_t h, const void *buf, size_t len);
+
 /** @cond internal */
 
 /** Number of request within timeout window. */