From: Marek VavruĊĦa Date: Tue, 5 May 2015 21:21:49 +0000 (+0200) Subject: daemon/io: fixed corrupted handles with exhausted TCP clients X-Git-Tag: v1.0.0-beta1~216 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8002457bb6c8b71e1048dc91ac46375aa2ee286b;p=thirdparty%2Fknot-resolver.git daemon/io: fixed corrupted handles with exhausted TCP clients the TCP allowed parallel processing of multiple requests over one client socket, however if the client socket disconnected, it left the running tasks reading from bad handle now each task takes ownership of the handle until it is finished, only then it is returned to the loop and closed --- diff --git a/daemon/io.c b/daemon/io.c index 298fa0d45..a62bea699 100644 --- a/daemon/io.c +++ b/daemon/io.c @@ -105,7 +105,15 @@ static void tcp_recv(uv_stream_t *handle, ssize_t nread, const uv_buf_t *buf) knot_pkt_t *query = knot_pkt_new(buf->base + 2, nbytes, worker->mm); query->max_size = sizeof(worker->bufs.wire); - worker_exec(worker, (uv_handle_t *)handle, query, NULL); + int ret = worker_exec(worker, (uv_handle_t *)handle, query, NULL); + if (ret == 0) { + /* Push - pull, stop reading from this handle until + * the task is finished. Since the handle has no track of the + * pending tasks, it might be freed before the task finishes + * leading various errors. */ + uv_unref((uv_handle_t *)handle); + io_stop_read((uv_handle_t *)handle); + } knot_pkt_free(&query); } diff --git a/daemon/worker.c b/daemon/worker.c index 5a812309f..26a913a37 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -104,6 +104,12 @@ static struct qr_task *qr_task_create(struct worker_ctx *worker, uv_handle_t *ha static void qr_task_free(uv_handle_t *handle) { struct qr_task *task = handle->data; + /* Return handle to the event loop in case + * it was exclusively taken by this task. */ + if (!uv_has_ref(task->source.handle)) { + uv_ref(task->source.handle); + io_start_read(task->source.handle); + } mp_delete(task->req.pool.ctx); } @@ -165,7 +171,10 @@ static void qr_task_on_connect(uv_connect_t *connect, int status) static int qr_task_finalize(struct qr_task *task, int state) { kr_resolve_finish(&task->req, state); - qr_task_send(task, task->source.handle, (struct sockaddr *)&task->source.addr, task->req.answer); + int ret = qr_task_send(task, task->source.handle, (struct sockaddr *)&task->source.addr, task->req.answer); + if (ret != 0) { /* Broken connection */ + uv_close((uv_handle_t *)&task->timeout, qr_task_free); + } return state == KNOT_STATE_DONE ? 0 : kr_error(EIO); } diff --git a/daemon/worker.h b/daemon/worker.h index 503aba431..1f6afae23 100644 --- a/daemon/worker.h +++ b/daemon/worker.h @@ -27,9 +27,9 @@ struct worker_ctx { struct engine *engine; uv_loop_t *loop; mm_ctx_t *mm; - struct { - uint8_t wire[KNOT_WIRE_MAX_PKTSIZE]; - } bufs; + struct { + uint8_t wire[KNOT_WIRE_MAX_PKTSIZE]; + } bufs; }; /**