Anyone?
While I could volunteer all y'all for testing that seems a bit silly.
I'd rather have someone to read the diff because
- The tricky cases will be very rare to hit in normal operations,
DNS answers are just not that big.
- I'd like to hear that this is actually a good pattern to do this and
I'm not completely off the trail
Eventually I will put it in though, to make progress.
Thanks.
On Thu, Nov 19, 2020 at 03:59:03PM +0100, Florian Obser wrote:
> On Fri, Nov 13, 2020 at 05:53:53PM +0100, Florian Obser wrote:
> > The recent fix for handling large (about 16k) answers in unwind has
> > the downside that we are now always copying at least 16k per answer
> > between the resolver and frontend process.
> > That seems wasteful.
> >
> > This re-arranges things to only copy what its needed.
> >
> > Tests, OKs?
> >
>
> Anyone? So far I had one (1) test report.
>
> diff --git frontend.c frontend.c
> index 8adbb07219b..74715087c5f 100644
> --- frontend.c
> +++ frontend.c
> @@ -86,7 +86,8 @@ struct pending_query {
> int fd;
> int bogus;
> int rcode_override;
> - ssize_t answer_len;
> + int answer_len;
> + int received;
> uint8_t *answer;
> };
>
> @@ -424,10 +425,7 @@ frontend_dispatch_resolver(int fd, short event, void
> *bula)
> struct imsgev *iev = bula;
> struct imsgbuf *ibuf = &iev->ibuf;
> struct imsg imsg;
> - struct query_imsg *query_imsg;
> - struct answer_imsg *answer_imsg;
> int n, shut = 0, chg;
> - uint8_t *p;
>
> if (event & EV_READ) {
> if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
> @@ -449,45 +447,30 @@ frontend_dispatch_resolver(int fd, short event, void
> *bula)
> break;
>
> switch (imsg.hdr.type) {
> - case IMSG_ANSWER_HEADER:
> - if (IMSG_DATA_SIZE(imsg) != sizeof(*query_imsg))
> - fatalx("%s: IMSG_ANSWER_HEADER wrong length: "
> - "%lu", __func__, IMSG_DATA_SIZE(imsg));
> - query_imsg = (struct query_imsg *)imsg.data;
> - if ((pq = find_pending_query(query_imsg->id)) ==
> - NULL) {
> - log_warnx("cannot find pending query %llu",
> - query_imsg->id);
> - break;
> - }
> - if (query_imsg->err) {
> - send_answer(pq);
> - pq = NULL;
> - break;
> - }
> - pq->bogus = query_imsg->bogus;
> - break;
> - case IMSG_ANSWER:
> - if (IMSG_DATA_SIZE(imsg) != sizeof(*answer_imsg))
> + case IMSG_ANSWER: {
> + struct answer_header *answer_header;
> + int data_len;
> + uint8_t *data;
> +
> + if (IMSG_DATA_SIZE(imsg) < sizeof(*answer_header))
> fatalx("%s: IMSG_ANSWER wrong length: "
> "%lu", __func__, IMSG_DATA_SIZE(imsg));
> - answer_imsg = (struct answer_imsg *)imsg.data;
> - if ((pq = find_pending_query(answer_imsg->id)) ==
> + answer_header = (struct answer_header *)imsg.data;
> + data = (uint8_t *)imsg.data + sizeof(*answer_header);
> + if (answer_header->answer_len > 65535)
> + fatalx("%s: IMSG_ANSWER answer too big: %d",
> + __func__, answer_header->answer_len);
> + data_len = IMSG_DATA_SIZE(imsg) -
> + sizeof(*answer_header);
> +
> + if ((pq = find_pending_query(answer_header->id)) ==
> NULL) {
> - log_warnx("cannot find pending query %llu",
> - answer_imsg->id);
> + log_warnx("%s: cannot find pending query %llu",
> + __func__, answer_header->id);
> break;
> }
>
> - p = realloc(pq->answer, pq->answer_len +
> - answer_imsg->len);
> -
> - if (p != NULL) {
> - pq->answer = p;
> - memcpy(pq->answer + pq->answer_len,
> - answer_imsg->answer, answer_imsg->len);
> - pq->answer_len += answer_imsg->len;
> - } else {
> + if (answer_header->srvfail) {
> free(pq->answer);
> pq->answer_len = 0;
> pq->answer = NULL;
> @@ -495,9 +478,32 @@ frontend_dispatch_resolver(int fd, short event, void
> *bula)
> send_answer(pq);
> break;
> }
> - if (!answer_imsg->truncated)
> +
> + if (pq->answer == NULL) {
> + pq->answer = malloc(answer_header->answer_len);
> + if (pq->answer == NULL) {
> + pq->answer_len = 0;
> + pq->rcode_override =
> + LDNS_RCODE_SERVFAIL;
> + send_answer(pq);
> + break;
> + }
> + pq->answer_len = answer_header->answer_len;
> + pq->received = 0;
> + pq->bogus = answer_header->bogus;
> + }
> +
> + if (pq->received + data_len > pq->answer_len)
> + fatalx("%s: IMSG_ANSWER answer too big: %d",
> + __func__, data_len);
> +
> + memcpy(pq->answer + pq->received, data, data_len);
> + pq->received += data_len;
> +
> + if (pq->received == pq->answer_len)
> send_answer(pq);
> break;
> + }
> case IMSG_CTL_RESOLVER_INFO:
> case IMSG_CTL_AUTOCONF_RESOLVER_INFO:
> case IMSG_CTL_MEM_INFO:
> diff --git resolver.c resolver.c
> index fb34dee87d6..c3faba08faf 100644
> --- resolver.c
> +++ resolver.c
> @@ -884,7 +884,7 @@ resolve_done(struct uw_resolver *res, void *arg, int
> rcode,
> sldns_buffer *buf = NULL;
> struct regional *region = NULL;
> struct query_imsg *query_imsg;
> - struct answer_imsg answer_imsg;
> + struct answer_header *answer_header;
> struct running_query *rq;
> struct timespec tp, elapsed;
> int64_t ms;
> @@ -894,12 +894,19 @@ resolve_done(struct uw_resolver *res, void *arg, int
> rcode,
> char rcode_buf[16];
> char qclass_buf[16];
> char qtype_buf[16];
> - uint8_t *p;
> + uint8_t *p, *data;
> + uint8_t answer_imsg[MAX_IMSGSIZE - IMSG_HEADER_SIZE];
>
> clock_gettime(CLOCK_MONOTONIC, &tp);
>
> query_imsg = (struct query_imsg *)arg;
>
> + answer_header = (struct answer_header *)answer_imsg;
> + data = answer_imsg + sizeof(*answer_header);
> + answer_header->id = query_imsg->id;
> + answer_header->srvfail = 0;
> + answer_header->answer_len = answer_len;
> +
> timespecsub(&tp, &query_imsg->tp, &elapsed);
>
> ms = elapsed.tv_sec * 1000 + elapsed.tv_nsec / 1000000;
> @@ -1004,43 +1011,33 @@ resolve_done(struct uw_resolver *res, void *arg, int
> rcode,
> if (result->rcode == LDNS_RCODE_SERVFAIL)
> goto servfail;
>
> - query_imsg->err = 0;
> -
> if (sec == SECURE)
> res->state = VALIDATING;
>
> if (res->state == VALIDATING && sec == BOGUS) {
> - query_imsg->bogus = !force_acceptbogus;
> - if (query_imsg->bogus && why_bogus != NULL)
> + answer_header->bogus = !force_acceptbogus;
> + if (answer_header->bogus && why_bogus != NULL)
> log_warnx("%s", why_bogus);
> } else
> - query_imsg->bogus = 0;
> + answer_header->bogus = 0;
>
> - if (resolver_imsg_compose_frontend(IMSG_ANSWER_HEADER, 0, query_imsg,
> - sizeof(*query_imsg)) == -1)
> - fatalx("IMSG_ANSWER_HEADER failed for \"%s %s %s\"",
> - query_imsg->qname, qclass_buf, qtype_buf);
> -
> - answer_imsg.id = query_imsg->id;
> p = answer_packet;
> - while ((size_t)answer_len > MAX_ANSWER_SIZE) {
> - answer_imsg.truncated = 1;
> - answer_imsg.len = MAX_ANSWER_SIZE;
> - memcpy(&answer_imsg.answer, p, MAX_ANSWER_SIZE);
> - if (resolver_imsg_compose_frontend(IMSG_ANSWER, 0, &answer_imsg,
> - sizeof(answer_imsg)) == -1)
> + do {
> + int len;
> +
> + if ((size_t)answer_len > sizeof(answer_imsg) -
> + sizeof(*answer_header))
> + len = sizeof(answer_imsg) - sizeof(*answer_header);
> + else
> + len = answer_len;
> + memcpy(data, p, len);
> + if (resolver_imsg_compose_frontend(IMSG_ANSWER, 0,
> + &answer_imsg, sizeof(*answer_header) + len) == -1)
> fatalx("IMSG_ANSWER failed for \"%s %s %s\"",
> query_imsg->qname, qclass_buf, qtype_buf);
> - p += MAX_ANSWER_SIZE;
> - answer_len -= MAX_ANSWER_SIZE;
> - }
> - answer_imsg.truncated = 0;
> - answer_imsg.len = answer_len;
> - memcpy(&answer_imsg.answer, p, answer_len);
> - if (resolver_imsg_compose_frontend(IMSG_ANSWER, 0, &answer_imsg,
> - sizeof(answer_imsg)) == -1)
> - fatalx("IMSG_ANSWER failed for \"%s %s %s\"",
> - query_imsg->qname, qclass_buf, qtype_buf);
> + answer_len -= len;
> + p += len;
> + } while (answer_len > 0);
>
> TAILQ_REMOVE(&running_queries, rq, entry);
> evtimer_del(&rq->timer_ev);
> @@ -1052,9 +1049,9 @@ resolve_done(struct uw_resolver *res, void *arg, int
> rcode,
> /* try_next_resolver() might free rq */
> if (try_next_resolver(rq) != 0 && running_res == 0) {
> /* we are the last one, send SERVFAIL */
> - query_imsg->err = -4; /* UB_SERVFAIL */
> - resolver_imsg_compose_frontend(IMSG_ANSWER_HEADER, 0,
> - query_imsg, sizeof(*query_imsg));
> + answer_header->srvfail = 1;
> + resolver_imsg_compose_frontend(IMSG_ANSWER, 0,
> + answer_imsg, sizeof(*answer_header));
> }
> out:
> free(query_imsg);
> diff --git unwind.h unwind.h
> index 9ebd8f47f87..161619cd34c 100644
> --- unwind.h
> +++ unwind.h
> @@ -116,7 +116,6 @@ enum imsg_type {
> IMSG_SOCKET_IPC_FRONTEND,
> IMSG_SOCKET_IPC_RESOLVER,
> IMSG_QUERY,
> - IMSG_ANSWER_HEADER,
> IMSG_ANSWER,
> IMSG_CTL_RESOLVER_INFO,
> IMSG_CTL_AUTOCONF_RESOLVER_INFO,
> @@ -170,18 +169,14 @@ struct query_imsg {
> char qname[NI_MAXHOST];
> int t;
> int c;
> - int err;
> - int bogus;
> struct timespec tp;
> };
>
> -struct answer_imsg {
> -#define MAX_ANSWER_SIZE MAX_IMSGSIZE - IMSG_HEADER_SIZE -
> sizeof(uint64_t) - \
> - 2 * sizeof(int)
> - uint64_t id;
> - int truncated;
> - int len;
> - uint8_t answer[MAX_ANSWER_SIZE];
> +struct answer_header {
> + uint64_t id;
> + int srvfail;
> + int bogus;
> + int answer_len;
> };
>
> extern uint32_t cmd_opts;
>
>
> --
> I'm not entirely sure you are real.
>
--
I'm not entirely sure you are real.