Fix bug with bind()/connect() and IPv4 addresses

Our standard utilities for converting InetAddress to sockaddr convert
IPv4 addresses to IPv4-mapped sockaddr_in6 instances.  This works fine
for most use cases, but when calling functions with AF_INET (aka IPv4)
sockets returned from Libcore.os.socket(), they need to be given a
sockaddr_in or they fail with EAFNOSUPPORT.

We have a utility to deal with this (NET_IPV4_FALLBACK), but the
versions of bind() and connect() that took SocketAddress instances
instead of InetAddress instances didn't use it.  Follow the lead of
sendTo() and convert InetSocketAddress instances to InetAddress/port
pairs and call the InetAddress version of the call so we get the
benefit of NET_IPV4_FALLBACK.

Bug: 123562238
Test: cts -m CtsLibcoreTestCases
Change-Id: Ib8c1fda7be3dda8e6eee31fd15f2d0c4567a5712
diff --git a/luni/src/main/native/libcore_io_Linux.cpp b/luni/src/main/native/libcore_io_Linux.cpp
index 5d621de..635619a 100644
--- a/luni/src/main/native/libcore_io_Linux.cpp
+++ b/luni/src/main/native/libcore_io_Linux.cpp
@@ -986,7 +986,15 @@
 }
 
 static void Linux_bindSocketAddress(
-        JNIEnv* env, jobject, jobject javaFd, jobject javaSocketAddress) {
+        JNIEnv* env, jobject thisObj, jobject javaFd, jobject javaSocketAddress) {
+    if (env->IsInstanceOf(javaSocketAddress, JniConstants::GetInetSocketAddressClass(env))) {
+        // Use the InetAddress version so we get the benefit of NET_IPV4_FALLBACK.
+        jobject javaInetAddress;
+        jint port;
+        javaInetSocketAddressToInetAddressAndPort(env, javaSocketAddress, javaInetAddress, port);
+        Linux_bind(env, thisObj, javaFd, javaInetAddress, port);
+        return;
+    }
     sockaddr_storage ss;
     socklen_t sa_len;
     if (!javaSocketAddressToSockaddr(env, javaSocketAddress, ss, sa_len)) {
@@ -1160,7 +1168,15 @@
 }
 
 static void Linux_connectSocketAddress(
-        JNIEnv* env, jobject, jobject javaFd, jobject javaSocketAddress) {
+        JNIEnv* env, jobject thisObj, jobject javaFd, jobject javaSocketAddress) {
+    if (env->IsInstanceOf(javaSocketAddress, JniConstants::GetInetSocketAddressClass(env))) {
+        // Use the InetAddress version so we get the benefit of NET_IPV4_FALLBACK.
+        jobject javaInetAddress;
+        jint port;
+        javaInetSocketAddressToInetAddressAndPort(env, javaSocketAddress, javaInetAddress, port);
+        Linux_connect(env, thisObj, javaFd, javaInetAddress, port);
+        return;
+    }
     sockaddr_storage ss;
     socklen_t sa_len;
     if (!javaSocketAddressToSockaddr(env, javaSocketAddress, ss, sa_len)) {
diff --git a/luni/src/test/java/libcore/libcore/io/OsTest.java b/luni/src/test/java/libcore/libcore/io/OsTest.java
index 5d09939..91105bf 100644
--- a/luni/src/test/java/libcore/libcore/io/OsTest.java
+++ b/luni/src/test/java/libcore/libcore/io/OsTest.java
@@ -408,9 +408,7 @@
     SocketAddress addrIpv6 = new InetSocketAddress(InetAddress.getByName("::1"), 0);
     SocketAddress addrUnix = UnixSocketAddress.createAbstract("/abstract_name_unix_socket");
 
-    // TODO: fix and uncomment. Currently fails with EAFNOSUPPORT because
-    // Linux_bindSocketAddress uses NET_FAILURE_RETRY instead of NET_IPV4_RETRY.
-    // expectBindConnectSendtoSuccess(makeIpv4Socket(), "ipv4", addrIpv4);
+    expectBindConnectSendtoSuccess(makeIpv4Socket(), "ipv4", addrIpv4);
     expectBindConnectSendtoErrno(EAFNOSUPPORT, EAFNOSUPPORT, EAFNOSUPPORT,
                                  makeIpv4Socket(), "ipv4", addrIpv6);
     expectBindConnectSendtoErrno(EAFNOSUPPORT, EAFNOSUPPORT, EAFNOSUPPORT,