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;