if (s->closing) {
return;
}
+ /* nread might be 0, which does not indicate an error or EOF.
+ * This is equivalent to EAGAIN or EWOULDBLOCK under read(2). */
+ if (nread == 0) {
+ return;
+ }
+ if (nread == UV_EOF) {
+ nread = 0;
+ }
struct worker_ctx *worker = loop->data;
/* TCP pipelining is rather complicated and requires cooperation from the worker
* so the whole message reassembly and demuxing logic is inside worker */
}
tls_p->buf = buf;
- tls_p->nread = nread;
+ tls_p->nread = nread >= 0 ? nread : 0;
tls_p->handle = handle;
tls_p->consumed = 0; /* TODO: doesn't handle split TLS records */
if (ret < 0) {
return ret;
}
+ if (count == 0) {
+ break;
+ }
submitted += ret;
}
return submitted;
}
ssize_t submitted = 0;
+ ssize_t retries = 0;
do {
count = gnutls_record_uncork(ctx->tls_session, 0);
if (count < 0) {
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);
+ return kr_error(EIO);
+ }
} else {
submitted += count;
if (count == 0 && submitted != sizeof(pkt_size) + pkt->size) {
ctx->handshake_state == TLS_HS_DONE);
ctx->buf = buf;
- ctx->nread = nread;
+ ctx->nread = nread >= 0 ? nread : 0;
ctx->session = session;
ctx->consumed = 0;
static int qr_task_finalize(struct qr_task *task, int state)
{
assert(task && task->leading == false);
+ if (task->finished) {
+ return 0;
+ }
struct request_ctx *ctx = task->ctx;
kr_resolve_finish(&ctx->req, state);
task->finished = true;