Properly restore errno if NET_FAILURE_RETRY fails.

If NET_FAILURE_RETRY fails, it throws an exception. In all but
one codepath, that exception ends up being passed back to Java
land immediately, so it doesn't matter what errno is set to.

However, in the case where we need to retry the socket call with
a sockaddr_in (i.e., NET_IPV4_FALLBACK), we clear the exception
and march on. This means that if errno is touched by
throwErrnoException (strace showed this happening, for example,
if futex() returns EAGAIN), we don't retry the socket call and
instead return the previous EAFNOSUPPORT error to the caller.

Also modify IO_FAILURE_RETRY for consistency.

Bug: 23088314
Change-Id: Ib92771ba2001c2696f83f61f48bd137a7a91a880
diff --git a/luni/src/main/native/libcore_io_Posix.cpp b/luni/src/main/native/libcore_io_Posix.cpp
index 783a1bb..bfe2380 100644
--- a/luni/src/main/native/libcore_io_Posix.cpp
+++ b/luni/src/main/native/libcore_io_Posix.cpp
@@ -135,9 +135,9 @@
  */
 #define NET_FAILURE_RETRY(jni_env, return_type, syscall_name, java_fd, ...) ({ \
     return_type _rc = -1; \
+    int _syscallErrno; \
     do { \
         bool _wasSignaled; \
-        int _syscallErrno; \
         { \
             int _fd = jniGetFDFromFileDescriptor(jni_env, java_fd); \
             AsynchronousCloseMonitor _monitor(_fd); \
@@ -156,6 +156,10 @@
             break; \
         } \
     } while (_rc == -1); /* _syscallErrno == EINTR && !_wasSignaled */ \
+    if (_rc == -1) { \
+        /* If the syscall failed, re-set errno: throwing an exception might have modified it. */ \
+        errno = _syscallErrno; \
+    } \
     _rc; })
 
 /**
@@ -170,9 +174,9 @@
  */
 #define IO_FAILURE_RETRY(jni_env, return_type, syscall_name, java_fd, ...) ({ \
     return_type _rc = -1; \
+    int _syscallErrno; \
     do { \
         bool _wasSignaled; \
-        int _syscallErrno; \
         { \
             int _fd = jniGetFDFromFileDescriptor(jni_env, java_fd); \
             AsynchronousCloseMonitor _monitor(_fd); \
@@ -191,6 +195,10 @@
             break; \
         } \
     } while (_rc == -1); /* && _syscallErrno == EINTR && !_wasSignaled */ \
+    if (_rc == -1) { \
+        /* If the syscall failed, re-set errno: throwing an exception might have modified it. */ \
+        errno = _syscallErrno; \
+    } \
     _rc; })
 
 #define NULL_ADDR_OK         true
diff --git a/luni/src/test/java/libcore/io/OsTest.java b/luni/src/test/java/libcore/io/OsTest.java
index f1d6668..1dcc3c6 100644
--- a/luni/src/test/java/libcore/io/OsTest.java
+++ b/luni/src/test/java/libcore/io/OsTest.java
@@ -426,6 +426,23 @@
     checkSocketPing(fd, ipv4Loopback, packet, ICMP_ECHO, ICMP_ECHOREPLY, false);
   }
 
+  public void test_Ipv4Fallback() throws Exception {
+    // This number of iterations gives a ~60% chance of creating the conditions that caused
+    // http://b/23088314 without making test times too long. On a hammerhead running MRZ37C using
+    // vogar, this test takes about 4s.
+    final int ITERATIONS = 10000;
+    for (int i = 0; i < ITERATIONS; i++) {
+      FileDescriptor mUdpSock = Libcore.os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+      try {
+          Libcore.os.bind(mUdpSock, Inet4Address.ANY, 0);
+      } catch(ErrnoException e) {
+          fail("ErrnoException after " + i + " iterations: " + e);
+      } finally {
+          Libcore.os.close(mUdpSock);
+      }
+    }
+  }
+
   public void test_unlink() throws Exception {
     File f = File.createTempFile("OsTest", "tst");
     assertTrue(f.exists());