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.