Record system call relevant errors correctly
As we have a specific field for errno in our stats proto now, add the
code to get it work accordingly. Also refine the errno assignment.
Bug: 150662964
Bug: 151166599
Test: atest
Merged-In: I781513e385e1cf2a77d1d052c4a450a94978e242
Change-Id: Ib96ebcc776860f9b067c84bda539312302dea522
(cherry picked from commit c2df16e7894616b5ca4f1f89764f9422cb313aa6)
diff --git a/res_send.cpp b/res_send.cpp
index a10bbd1..2b84e82 100644
--- a/res_send.cpp
+++ b/res_send.cpp
@@ -130,6 +130,7 @@
using android::net::IV_IPV4;
using android::net::IV_IPV6;
using android::net::IV_UNKNOWN;
+using android::net::LinuxErrno;
using android::net::NetworkDnsEventReported;
using android::net::NS_T_INVALID;
using android::net::NsRcode;
@@ -499,7 +500,8 @@
int retryTimes = (flags & ANDROID_RESOLV_NO_RETRY) ? 1 : params.retry_count;
int useTcp = buflen > PACKETSZ;
int gotsomewhere = 0;
- int terrno = ETIMEDOUT;
+ // Use an impossible error code as default value
+ int terrno = ETIME;
for (int attempt = 0; attempt < retryTimes; ++attempt) {
for (size_t ns = 0; ns < statp->nsaddrs.size(); ++ns) {
@@ -521,6 +523,8 @@
Stopwatch queryStopwatch;
int retry_count_for_event = 0;
size_t actualNs = ns;
+ // Use an impossible error code as default value
+ terrno = ETIME;
if (useTcp) {
// TCP; at most one attempt per server.
attempt = retryTimes;
@@ -558,6 +562,7 @@
dnsQueryEvent->set_rcode(static_cast<NsRcode>(*rcode));
dnsQueryEvent->set_protocol(query_proto);
dnsQueryEvent->set_type(getQueryType(buf, buflen));
+ dnsQueryEvent->set_linux_errno(static_cast<LinuxErrno>(terrno));
// Only record stats the first time we try a query. This ensures that
// queries that deterministically fail (e.g., a name that always returns
@@ -643,6 +648,7 @@
// It should never happen, but just in case.
if (ns >= statp->nsaddrs.size()) {
LOG(ERROR) << __func__ << ": Out-of-bound indexing: " << ns;
+ *terrno = EINVAL;
return -1;
}
@@ -675,15 +681,14 @@
statp->tcp_nssock.reset(socket(nsap->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0));
if (statp->tcp_nssock < 0) {
+ *terrno = errno;
+ PLOG(DEBUG) << __func__ << ": socket(vc): ";
switch (errno) {
case EPROTONOSUPPORT:
case EPFNOSUPPORT:
case EAFNOSUPPORT:
- PLOG(DEBUG) << __func__ << ": socket(vc): ";
return 0;
default:
- *terrno = errno;
- PLOG(DEBUG) << __func__ << ": socket(vc): ";
return -1;
}
}
@@ -831,6 +836,7 @@
*delay = res_stats_calculate_rtt(&done, &start_time);
*rcode = anhp->rcode;
}
+ *terrno = 0;
return (resplen);
}
@@ -972,6 +978,7 @@
// It should never happen, but just in case.
if (*ns >= statp->nsaddrs.size()) {
LOG(ERROR) << __func__ << ": Out-of-bound indexing: " << ns;
+ *terrno = EINVAL;
return -1;
}
@@ -984,15 +991,14 @@
if (statp->nssocks[*ns] == -1) {
statp->nssocks[*ns].reset(socket(nsap->sa_family, SOCK_DGRAM | SOCK_CLOEXEC, 0));
if (statp->nssocks[*ns] < 0) {
+ *terrno = errno;
+ PLOG(DEBUG) << __func__ << ": socket(dg): ";
switch (errno) {
case EPROTONOSUPPORT:
case EPFNOSUPPORT:
case EAFNOSUPPORT:
- PLOG(DEBUG) << __func__ << ": socket(dg): ";
return (0);
default:
- *terrno = errno;
- PLOG(DEBUG) << __func__ << ": socket(dg): ";
return (-1);
}
}
@@ -1001,6 +1007,7 @@
if (statp->_mark != MARK_UNSET) {
if (setsockopt(statp->nssocks[*ns], SOL_SOCKET, SO_MARK, &(statp->_mark),
sizeof(statp->_mark)) < 0) {
+ *terrno = errno;
statp->closeSockets();
return -1;
}
@@ -1010,11 +1017,13 @@
// ICMP port-unreachable error. This way we can detect the absence of
// a nameserver without timing out.
if (random_bind(statp->nssocks[*ns], nsap->sa_family) < 0) {
+ *terrno = errno;
dump_error("bind(dg)", nsap, nsaplen);
statp->closeSockets();
return (0);
}
if (connect(statp->nssocks[*ns], nsap, (socklen_t)nsaplen) < 0) {
+ *terrno = errno;
dump_error("connect(dg)", nsap, nsaplen);
statp->closeSockets();
return (0);
@@ -1022,6 +1031,7 @@
LOG(DEBUG) << __func__ << ": new DG socket";
}
if (send(statp->nssocks[*ns], (const char*)buf, (size_t)buflen, 0) != buflen) {
+ *terrno = errno;
PLOG(DEBUG) << __func__ << ": send: ";
statp->closeSockets();
return 0;
@@ -1037,6 +1047,7 @@
if (!result.has_value()) {
const bool isTimeout = (result.error().code() == ETIMEDOUT);
*rcode = (isTimeout) ? RCODE_TIMEOUT : *rcode;
+ *terrno = (isTimeout) ? ETIMEDOUT : errno;
*gotsomewhere = (isTimeout) ? 1 : *gotsomewhere;
// Leave the UDP sockets open on timeout so we can keep listening for
// a late response from this server while retrying on the next server.
@@ -1052,6 +1063,7 @@
int resplen =
recvfrom(fd, (char*)ans, (size_t)anssiz, 0, (sockaddr*)(void*)&from, &fromlen);
if (resplen <= 0) {
+ *terrno = errno;
PLOG(DEBUG) << __func__ << ": recvfrom: ";
continue;
}
@@ -1080,6 +1092,7 @@
res_pquery(ans, (resplen > anssiz) ? anssiz : resplen);
// record the error
statp->_flags |= RES_F_EDNS0ERR;
+ *terrno = EREMOTEIO;
continue;
}
@@ -1095,6 +1108,7 @@
// To get the rest of answer,
// use TCP with same server.
LOG(DEBUG) << __func__ << ": truncated answer";
+ *terrno = E2BIG;
*v_circuit = 1;
return 1;
}
@@ -1103,6 +1117,7 @@
*rcode = anhp->rcode;
*ns = receivedFromNs;
+ *terrno = 0;
return resplen;
}
if (!needRetry) return 0;