]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
daemon: kresd fall into endless loop in some circumstances when tls is used; fix
authorGrigorii Demidov <grigorii.demidov@nic.cz>
Fri, 5 Jan 2018 09:03:23 +0000 (10:03 +0100)
committerPetr Špaček <petr.spacek@nic.cz>
Mon, 8 Jan 2018 11:01:02 +0000 (12:01 +0100)
daemon/tls.c
daemon/worker.c

index c49f3612fc8b487a21e5f09cc5ed9268876bb1c2..e9ffa97105306c5028684ed07b00da4b6520a738 100644 (file)
@@ -869,6 +869,7 @@ int tls_client_push(struct qr_task *task, uv_handle_t *handle, knot_pkt_t *pkt)
                                return kr_error(EIO);
                        }
                } else {
+                       retries = 0;
                        submitted += count;
                        if (count == 0 && submitted != sizeof(pkt_size) + pkt->size) {
                                kr_log_error("[tls_client] gnutls_record_uncork didn't send all data: %s (%zd)\n",
index 821eabd4cd71167aa3cb9598e07cb3b3863a5b25..aebeb8e2f1d1dffa7a87a5033ac94f9eb3e95a18 100644 (file)
@@ -804,9 +804,21 @@ static int qr_task_on_send(struct qr_task *task, uv_handle_t *handle, int status
                        if (session->closing) {
                                return status;
                        }
+                       /* Finalize the task, if any errors.
+                        * We can't add it to the end of waiting list for retrying
+                        * since it may lead endless loop in some circumstances
+                        * (for instance: tls; send->tls_push->too many non-critical errors->
+                        * on_send with nonzero status->re-add to waiting->send->etc).*/
                        if (status != 0) {
-                               /* Add to the end for retry */
-                               session_add_waiting(session, task);
+                               qr_task_finalize(task, KR_STATE_FAIL);
+                               if (session->outgoing) {
+                                       qr_task_finalize(task, KR_STATE_FAIL);
+                               } else {
+                                       assert(task->ctx->source.session == session);
+                                       task->ctx->source.session = NULL;
+                               }
+                               session_del_tasks(session, task);
+                               qr_task_unref(task);
                        }
                        if (session->waiting.len > 0) {
                                struct qr_task *t = session->waiting.at[0];