send_dg() refactor
Keep the logic but remove goto statement
simpify the code flow and remove the redundant code
Bug: 135717624
Test: atest
Change-Id: I7802be7782eb312ec9ecc16f907fe52dbe56be05
diff --git a/res_send.cpp b/res_send.cpp
index 66548bd..a4083b6 100644
--- a/res_send.cpp
+++ b/res_send.cpp
@@ -875,22 +875,37 @@
return n;
}
+bool ignoreInvalidAnswer(res_state statp, const sockaddr_storage& from, const uint8_t* buf,
+ int buflen, uint8_t* ans, int anssiz) {
+ const HEADER* hp = (const HEADER*)(const void*)buf;
+ HEADER* anhp = (HEADER*)(void*)ans;
+ if (hp->id != anhp->id) {
+ // response from old query, ignore it.
+ LOG(DEBUG) << __func__ << ": old answer:";
+ return true;
+ }
+ if (!res_ourserver_p(statp, (sockaddr*)(void*)&from)) {
+ // response from wrong server? ignore it.
+ LOG(DEBUG) << __func__ << ": not our server:";
+ return true;
+ }
+ if (!res_queriesmatch(buf, buf + buflen, ans, ans + anssiz)) {
+ // response contains wrong query? ignore it.
+ LOG(DEBUG) << __func__ << ": wrong query name:";
+ return true;
+ }
+ return false;
+}
+
static int send_dg(res_state statp, res_params* params, const uint8_t* buf, int buflen,
uint8_t* ans, int anssiz, int* terrno, int ns, int* v_circuit, int* gotsomewhere,
time_t* at, int* rcode, int* delay) {
- *at = time(NULL);
+ *at = time(nullptr);
*delay = 0;
- const HEADER* hp = (const HEADER*) (const void*) buf;
- HEADER* anhp = (HEADER*) (void*) ans;
- const struct sockaddr* nsap;
- int nsaplen;
- struct timespec now, timeout, finish, done;
- struct sockaddr_storage from;
- socklen_t fromlen;
- int resplen, n, s;
- nsap = get_nsaddr(statp, (size_t) ns);
- nsaplen = sockaddrSize(nsap);
+ const sockaddr* nsap = get_nsaddr(statp, (size_t)ns);
+ const int nsaplen = sockaddrSize(nsap);
+
if (statp->nssocks[ns] == -1) {
statp->nssocks[ns] = socket(nsap->sa_family, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (statp->nssocks[ns] < 0) {
@@ -931,120 +946,91 @@
}
LOG(DEBUG) << __func__ << ": new DG socket";
}
- s = statp->nssocks[ns];
- if (send(s, (const char*) buf, (size_t) buflen, 0) != buflen) {
+ if (send(statp->nssocks[ns], (const char*)buf, (size_t)buflen, 0) != buflen) {
PLOG(DEBUG) << __func__ << ": send: ";
res_nclose(statp);
return 0;
}
- // Wait for reply.
- timeout = get_timeout(statp, params, ns);
- now = evNowTime();
- finish = evAddTime(now, timeout);
-retry:
- n = retrying_poll(s, POLLIN, &finish);
+ timespec timeout = get_timeout(statp, params, ns);
+ timespec now = evNowTime();
+ timespec finish = evAddTime(now, timeout);
+ for (;;) {
+ // Wait for reply.
+ int n = retrying_poll(statp->nssocks[ns], POLLIN, &finish);
+ if (n == 0) {
+ *rcode = RCODE_TIMEOUT;
+ LOG(DEBUG) << __func__ << ": timeout";
+ *gotsomewhere = 1;
+ return 0;
+ }
+ if (n < 0) {
+ PLOG(DEBUG) << __func__ << ": poll: ";
+ res_nclose(statp);
+ return 0;
+ }
- if (n == 0) {
- *rcode = RCODE_TIMEOUT;
- LOG(DEBUG) << __func__ << ": timeout";
+ errno = 0;
+ sockaddr_storage from;
+ socklen_t fromlen = sizeof(from);
+ int resplen = recvfrom(statp->nssocks[ns], (char*)ans, (size_t)anssiz, 0,
+ (sockaddr*)(void*)&from, &fromlen);
+ if (resplen <= 0) {
+ PLOG(DEBUG) << __func__ << ": recvfrom: ";
+ res_nclose(statp);
+ return 0;
+ }
*gotsomewhere = 1;
- return 0;
+ if (resplen < HFIXEDSZ) {
+ // Undersized message.
+ LOG(DEBUG) << __func__ << ": undersized: " << resplen;
+ *terrno = EMSGSIZE;
+ res_nclose(statp);
+ return 0;
+ }
+
+ if (ignoreInvalidAnswer(statp, from, buf, buflen, ans, anssiz)) {
+ res_pquery(ans, (resplen > anssiz) ? anssiz : resplen);
+ continue;
+ }
+
+ HEADER* anhp = (HEADER*)(void*)ans;
+ if (anhp->rcode == FORMERR && (statp->netcontext_flags & NET_CONTEXT_FLAG_USE_EDNS)) {
+ // Do not retry if the server do not understand EDNS0.
+ // The case has to be captured here, as FORMERR packet do not
+ // carry query section, hence res_queriesmatch() returns 0.
+ LOG(DEBUG) << __func__ << ": server rejected query with EDNS0:";
+ res_pquery(ans, (resplen > anssiz) ? anssiz : resplen);
+ // record the error
+ statp->_flags |= RES_F_EDNS0ERR;
+ res_nclose(statp);
+ return 0;
+ }
+
+ timespec done = evNowTime();
+ *delay = _res_stats_calculate_rtt(&done, &now);
+ if (anhp->rcode == SERVFAIL || anhp->rcode == NOTIMP || anhp->rcode == REFUSED) {
+ LOG(DEBUG) << __func__ << ": server rejected query:";
+ res_pquery(ans, (resplen > anssiz) ? anssiz : resplen);
+ res_nclose(statp);
+ *rcode = anhp->rcode;
+ return 0;
+ }
+ if (anhp->tc) {
+ // To get the rest of answer,
+ // use TCP with same server.
+ LOG(DEBUG) << __func__ << ": truncated answer";
+ *v_circuit = 1;
+ res_nclose(statp);
+ return 1;
+ }
+ // All is well, or the error is fatal. Signal that the
+ // next nameserver ought not be tried.
+ if (resplen > 0) {
+ *rcode = anhp->rcode;
+ }
+ return resplen;
}
- if (n < 0) {
- PLOG(DEBUG) << __func__ << ": poll: ";
- res_nclose(statp);
- return 0;
- }
- errno = 0;
- fromlen = sizeof(from);
- resplen = recvfrom(s, (char*) ans, (size_t) anssiz, 0, (struct sockaddr*) (void*) &from,
- &fromlen);
- if (resplen <= 0) {
- PLOG(DEBUG) << __func__ << ": recvfrom: ";
- res_nclose(statp);
- return 0;
- }
- *gotsomewhere = 1;
- if (resplen < HFIXEDSZ) {
- /*
- * Undersized message.
- */
- LOG(DEBUG) << __func__ << ": undersized: " << resplen;
- *terrno = EMSGSIZE;
- res_nclose(statp);
- return 0;
- }
- if (hp->id != anhp->id) {
- /*
- * response from old query, ignore it.
- * XXX - potential security hazard could
- * be detected here.
- */
- LOG(DEBUG) << __func__ << ": old answer:";
- res_pquery(ans, (resplen > anssiz) ? anssiz : resplen);
- goto retry;
- }
- if (!res_ourserver_p(statp, (struct sockaddr*)(void*)&from)) {
- /*
- * response from wrong server? ignore it.
- * XXX - potential security hazard could
- * be detected here.
- */
- LOG(DEBUG) << __func__ << ": not our server:";
- res_pquery(ans, (resplen > anssiz) ? anssiz : resplen);
- goto retry;
- }
- if (anhp->rcode == FORMERR && (statp->netcontext_flags & NET_CONTEXT_FLAG_USE_EDNS)) {
- /*
- * Do not retry if the server do not understand EDNS0.
- * The case has to be captured here, as FORMERR packet do not
- * carry query section, hence res_queriesmatch() returns 0.
- */
- LOG(DEBUG) << __func__ << ": server rejected query with EDNS0:";
- res_pquery(ans, (resplen > anssiz) ? anssiz : resplen);
- /* record the error */
- statp->_flags |= RES_F_EDNS0ERR;
- res_nclose(statp);
- return 0;
- }
- if (!res_queriesmatch(buf, buf + buflen, ans, ans + anssiz)) {
- /*
- * response contains wrong query? ignore it.
- * XXX - potential security hazard could
- * be detected here.
- */
- LOG(DEBUG) << __func__ << ": wrong query name:";
- res_pquery(ans, (resplen > anssiz) ? anssiz : resplen);
- goto retry;
- }
- done = evNowTime();
- *delay = _res_stats_calculate_rtt(&done, &now);
- if (anhp->rcode == SERVFAIL || anhp->rcode == NOTIMP || anhp->rcode == REFUSED) {
- LOG(DEBUG) << __func__ << ": server rejected query:";
- res_pquery(ans, (resplen > anssiz) ? anssiz : resplen);
- res_nclose(statp);
- *rcode = anhp->rcode;
- return 0;
- }
- if (anhp->tc) {
- /*
- * To get the rest of answer,
- * use TCP with same server.
- */
- LOG(DEBUG) << __func__ << ": truncated answer";
- *v_circuit = 1;
- res_nclose(statp);
- return 1;
- }
- /*
- * All is well, or the error is fatal. Signal that the
- * next nameserver ought not be tried.
- */
- if (resplen > 0) {
- *rcode = anhp->rcode;
- }
- return resplen;
}
static void dump_error(const char* str, const struct sockaddr* address, int alen) {