OSDN Git Service

Use native code to convert IP addresses to strings.
[android-x86/dalvik.git] / libcore / luni / src / main / native / org_apache_harmony_luni_platform_OSNetworkSystem.cpp
index a1bf0c0..909f211 100644 (file)
 #include <stdio.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
-// Temporary hack to fix the sim build until bionic is updated.
-#ifdef HAVE_ANDROID_OS
-#include <netinet/in6.h>
-#else
-#define ipv6mr_ifindex ipv6mr_interface
-#endif
 #include <netinet/tcp.h>
 #include <netdb.h>
 #include <sys/time.h>
 struct CachedFields {
     jfieldID fd_descriptor;
     jclass iaddr_class;
-    jmethodID iaddr_class_init;
     jmethodID iaddr_getbyaddress;
+    jclass i4addr_class;
+    jmethodID i4addr_class_init;
     jfieldID iaddr_ipaddress;
     jclass genericipmreq_class;
     jclass integer_class;
@@ -177,6 +172,7 @@ struct CachedFields {
     jfieldID byte_class_value;
     jclass string_class;
     jmethodID string_class_init;
+    jclass socketimpl_class;
     jfieldID socketimpl_address;
     jfieldID socketimpl_port;
     jclass dpack_class;
@@ -337,53 +333,151 @@ static jobject socketAddressToInetAddress(JNIEnv *env,
  * @param port the port number
  * @param sockaddress the sockaddr_storage structure to write to
  *
- * @return 0 on success, -1 on failure
+ * @return 0 on success, a system error code on failure
  *
  * @exception SocketError if the address family is unknown
  */
-static int inetAddressToSocketAddress(JNIEnv *env,
-        jobject inetaddress, int port, struct sockaddr_storage *sockaddress) {
-
-    // Get the byte array that stores the IP address bytes in the InetAddress.
-    jbyteArray addressByteArray;
-    addressByteArray = (jbyteArray)env->GetObjectField(inetaddress,
-            gCachedFields.iaddr_ipaddress);
+static int byteArrayToSocketAddress(JNIEnv *env,
+        jbyteArray addressByteArray, int port, sockaddr_storage *sockaddress) {
     if (addressByteArray == NULL) {
       throwNullPointerException(env);
-      return -1;
+      return EFAULT;
     }
-
-    // Get the raw IP address bytes.
-    jbyte *addressBytes = env->GetByteArrayElements(addressByteArray, NULL);
-    if (addressBytes == NULL) {
-      throwNullPointerException(env);
-      return -1;
-    }
-
     // Convert the IP address bytes to the proper IP address type.
     size_t addressLength = env->GetArrayLength(addressByteArray);
-    int result = 0;
     if (addressLength == 4) {
         // IPv4 address.
-        struct sockaddr_in *sin = (struct sockaddr_in *) sockaddress;
-        memset(sin, 0, sizeof(struct sockaddr_in));
+        sockaddr_in *sin = (sockaddr_in *) sockaddress;
+        memset(sin, 0, sizeof(sockaddr_in));
         sin->sin_family = AF_INET;
         sin->sin_port = htons(port);
-        memcpy(&sin->sin_addr.s_addr, addressBytes, 4);
+        jbyte *rawBytes = (jbyte *) &sin->sin_addr.s_addr;
+        env->GetByteArrayRegion(addressByteArray, 0, 4, rawBytes);
     } else if (addressLength == 16) {
         // IPv6 address.
-        struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sockaddress;
-        memset(sin6, 0, sizeof(struct sockaddr_in6));
+        sockaddr_in6 *sin6 = (sockaddr_in6 *) sockaddress;
+        memset(sin6, 0, sizeof(sockaddr_in6));
         sin6->sin6_family = AF_INET6;
         sin6->sin6_port = htons(port);
-        memcpy(&sin6->sin6_addr.s6_addr, addressBytes, 16);
+        jbyte *rawBytes = (jbyte *) &sin6->sin6_addr.s6_addr;
+        env->GetByteArrayRegion(addressByteArray, 0, 16, rawBytes);
     } else {
         // Unknown address family.
         throwSocketException(env, SOCKERR_BADAF);
-        result = -1;
+        return EAFNOSUPPORT;
     }
-    env->ReleaseByteArrayElements(addressByteArray, addressBytes, 0);
-    return result;
+    return 0;
+}
+
+/**
+ * Converts an InetAddress object and port number to a native address structure.
+ * Throws a NullPointerException or a SocketException in case of
+ * error. This is signaled by a return value of -1. The normal
+ * return value is 0.
+ *
+ * @param inetaddress the InetAddress object to convert
+ * @param port the port number
+ * @param sockaddress the sockaddr_storage structure to write to
+ *
+ * @return 0 on success, -1 on failure
+ * @throw UnknownHostException if any error occurs
+ *
+ * @exception SocketError if the address family is unknown
+ */
+static int inetAddressToSocketAddress(JNIEnv *env,
+        jobject inetaddress, int port, sockaddr_storage *sockaddress) {
+
+    // Get the byte array that stores the IP address bytes in the InetAddress.
+    jbyteArray addressByteArray;
+    addressByteArray = (jbyteArray)env->GetObjectField(inetaddress,
+            gCachedFields.iaddr_ipaddress);
+
+    return byteArrayToSocketAddress(env, addressByteArray, port, sockaddress);
+}
+
+/**
+ * Convert a sockaddr_storage structure to a Java string.
+ *
+ * @param address pointer to sockaddr_storage structure to convert.
+ * @param withPort whether to include the port number in the output as well.
+ *
+ * @return 0 on success, a getnameinfo return code on failure.
+ *
+ * @throws SocketException the address family was unknown.
+ */
+static int socketAddressToString(sockaddr_storage *address, char *ipString,
+        int len, bool withPort) {
+    // TODO: getnameinfo seems to want its length parameter to be exactly
+    // sizeof(sockaddr_in) for an IPv4 address and sizeof (sockaddr_in6) for an
+    // IPv6 address. Fix getnameinfo so it accepts sizeof(sockaddr_storage), and
+    // then remove this hack.
+    int size;
+    if (address->ss_family == AF_INET) {
+        size = sizeof(sockaddr_in);
+    } else if (address->ss_family == AF_INET6) {
+        size = sizeof(sockaddr_in6);
+    } else {
+        errno = EAFNOSUPPORT;
+        return EAI_SYSTEM;
+    }
+
+    char tmp[INET6_ADDRSTRLEN];
+    int result = getnameinfo((sockaddr *)address, size, tmp, sizeof(tmp), NULL,
+            0, NI_NUMERICHOST);
+    if (result != 0) {
+        return result;
+    }
+
+    int port;
+    if (withPort) {
+        if (address->ss_family == AF_INET6) {
+            sockaddr_in6 *sin6 = (sockaddr_in6 *) address;
+            port = ntohs(sin6->sin6_port);
+            snprintf(ipString, len, "[%s]:%d", tmp, port);
+        } else {
+            sockaddr_in *sin = (sockaddr_in *) address;
+            port = ntohs(sin->sin_port);
+            snprintf(ipString, len, "%s:%d", tmp, port);
+        }
+    } else {
+        strncpy(ipString, tmp, len);
+    }
+    return 0;
+}
+
+/**
+ * Convert a Java byte array representing an IP address to a Java string.
+ *
+ * @param addressByteArray the byte array to convert.
+ *
+ * @return a string with the textual representation of the address.
+ *
+ * @throws SocketException the address family was unknown.
+ */
+static jstring osNetworkSystem_byteArrayToIpString(JNIEnv *env, jclass clazz,
+        jbyteArray byteArray) {
+    // For compatibility, ensure that an UnknownHostException is thrown if the
+    // address is null.
+    if (byteArray == NULL) {
+        jniThrowException(env, "java/net/UnknownHostException",
+                strerror(EFAULT));
+        return NULL;
+    }
+    struct sockaddr_storage ss;
+    int ret = byteArrayToSocketAddress(env, byteArray, 0, &ss);
+    if (ret) {
+        jniThrowException(env, "java/net/UnknownHostException", strerror(ret));
+        return NULL;
+    }
+    char ipString[INET6_ADDRSTRLEN];
+    ret = socketAddressToString(&ss, ipString, sizeof(ipString), false);
+    if (ret) {
+        env->ExceptionClear();
+        jniThrowException(env, "java/net/UnknownHostException",
+                gai_strerror(ret));
+        return NULL;
+    }
+    return env->NewStringUTF(ipString);
 }
 
 /**
@@ -511,49 +605,6 @@ static bool useAdbNetworkingForAddress(struct sockaddr_storage *address) {
 }
 
 /**
- * Convert a sockaddr_storage structure to a string for logging purposes.
- *
- * @param address pointer to sockaddr_storage structure to print
- *
- * @return a string with the textual representation of the address.
- *
- * @note Returns a statically allocated buffer, so is not thread-safe.
- */
-static char *socketAddressToString(struct sockaddr_storage *address) {
-    static char invalidString[] = "<invalid>";
-    static char ipString[INET6_ADDRSTRLEN + sizeof("[]:65535")];
-
-    char tmp[INET6_ADDRSTRLEN];
-    int port;
-    // TODO: getnameinfo seems to want its length parameter to be exactly
-    // sizeof(sockaddr_in) for an IPv4 address and sizeof (sockaddr_in6) for an
-    // IPv6 address. Fix getnameinfo so it accepts sizeof(sockaddr_storage), and
-    // then remove this hack.
-    int size = (address->ss_family == AF_INET) ?
-            sizeof(sockaddr_in) : sizeof(sockaddr_in6);
-    int result = getnameinfo((struct sockaddr *)address,
-            size, tmp, sizeof(tmp), NULL, 0,
-            NI_NUMERICHOST);
-
-    if (result != 0)
-        return invalidString;
-
-    if (address->ss_family == AF_INET6) {
-        struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) address;
-        port = ntohs(sin6->sin6_port);
-        sprintf(ipString, "[%s]:%d", tmp, port);
-        return ipString;
-    } else if (address->ss_family == AF_INET) {
-        struct sockaddr_in *sin = (struct sockaddr_in *) address;
-        port = ntohs(sin->sin_port);
-        sprintf(ipString, "%s:%d", tmp, port);
-        return ipString;
-    } else {
-        return invalidString;
-    }
-}
-
-/**
  * Answer the errorString corresponding to the errorNumber, if available.
  * This function will answer a default error string, if the errorNumber is not
  * recognized.
@@ -934,6 +985,23 @@ unsigned short ip_checksum(unsigned short* buffer, int size) {
 }
 
 /**
+ * Converts an IPv4-mapped IPv6 address to an IPv4 address. Performs no error
+ * checking.
+ *
+ * @param address the address to convert. Must contain an IPv4-mapped address.
+ * @param outputAddress the converted address. Will contain an IPv4 address.
+ */
+static void convertMappedToIpv4(sockaddr_storage *address,
+        sockaddr_storage *outputAddress) {
+  memset(outputAddress, 0, sizeof(sockaddr_in));
+  const sockaddr_in6 *sin6 = ((sockaddr_in6 *) address);
+  sockaddr_in *sin = ((sockaddr_in *) outputAddress);
+  sin->sin_family = AF_INET;
+  sin->sin_addr.s_addr = sin6->sin6_addr.s6_addr32[3];
+  sin->sin_port = sin6->sin6_port;
+}
+
+/**
  * Converts an IPv4 address to an IPv4-mapped IPv6 address. Performs no error
  * checking.
  *
@@ -941,9 +1009,9 @@ unsigned short ip_checksum(unsigned short* buffer, int size) {
  * @param outputAddress the converted address. Will contain an IPv6 address.
  * @param mapUnspecified if true, convert 0.0.0.0 to ::ffff:0:0; if false, to ::
  */
-static void ipv4ToMappedAddress(struct sockaddr_storage *address,
+static void convertIpv4ToMapped(struct sockaddr_storage *address,
         struct sockaddr_storage *outputAddress, bool mapUnspecified) {
-  memset(outputAddress, 0, sizeof(struct sockaddr_storage));
+  memset(outputAddress, 0, sizeof(struct sockaddr_in6));
   const struct sockaddr_in *sin = ((struct sockaddr_in *) address);
   struct sockaddr_in6 *sin6 = ((struct sockaddr_in6 *) outputAddress);
   sin6->sin6_family = AF_INET6;
@@ -966,7 +1034,7 @@ static int doConnect(int socket, struct sockaddr_storage *socketAddress) {
     struct sockaddr_storage *realAddress;
     if (socketAddress->ss_family == AF_INET &&
         getSocketAddressFamily(socket) == AF_INET6) {
-        ipv4ToMappedAddress(socketAddress, &mappedAddress, true);
+        convertIpv4ToMapped(socketAddress, &mappedAddress, true);
         realAddress = &mappedAddress;
     } else {
         realAddress = socketAddress;
@@ -991,7 +1059,7 @@ static int doBind(int socket, struct sockaddr_storage *socketAddress) {
     struct sockaddr_storage *realAddress;
     if (socketAddress->ss_family == AF_INET &&
         getSocketAddressFamily(socket) == AF_INET6) {
-        ipv4ToMappedAddress(socketAddress, &mappedAddress, false);
+        convertIpv4ToMapped(socketAddress, &mappedAddress, false);
         realAddress = &mappedAddress;
     } else {
         realAddress = socketAddress;
@@ -1057,7 +1125,7 @@ static int sockConnectWithTimeout(int handle, struct sockaddr_storage addr,
 
             // LOGD("+connect to address 0x%08x (via normal) on handle %d",
             //         addr.sin_addr.s_addr, handle);
-            doConnect(handle, &addr);
+            rc = doConnect(handle, &addr);
             // LOGD("-connect to address 0x%08x (via normal) returned %d",
             //         addr.sin_addr.s_addr, (int) rc);
 
@@ -1368,7 +1436,7 @@ static void mcastAddDropMembership (JNIEnv * env, int handle, jobject optVal,
                 memset(&ipv6Request, 0, requestLength);
                 ipv6Request.ipv6mr_multiaddr =
                         ((struct sockaddr_in6 *) &sockaddrP)->sin6_addr;
-                ipv6Request.ipv6mr_ifindex = interfaceIndex;
+                ipv6Request.ipv6mr_interface = interfaceIndex;
                 multicastRequest = &ipv6Request;
                 level = IPPROTO_IPV6;
                 break;
@@ -1403,229 +1471,77 @@ static void osNetworkSystem_oneTimeInitializationImpl(JNIEnv* env, jobject obj,
     }
 
     memset(&gCachedFields, 0, sizeof(gCachedFields));
-
-    // initializing InetAddress
-
-    jclass iaddrclass = env->FindClass("java/net/InetAddress");
-
-    if (iaddrclass == NULL) {
-        jniThrowException(env, "java/lang/ClassNotFoundException",
-                "java.net.InetAddress");
-        return;
-    }
-
-    gCachedFields.iaddr_class = (jclass) env->NewGlobalRef(iaddrclass);
-
-    jmethodID iaddrclassinit = env->GetMethodID(iaddrclass, "<init>", "()V");
-
-    if (iaddrclassinit == NULL) {
-        jniThrowException(env, "java/lang/NoSuchMethodError", "InetAddress.<init>()");
-        return;
-    }
-
-    gCachedFields.iaddr_class_init = iaddrclassinit;
-
-    jmethodID iaddrgetbyaddress = env->GetStaticMethodID(iaddrclass,
-            "getByAddress", "([B)Ljava/net/InetAddress;");
-
-    if (iaddrgetbyaddress == NULL) {
-        jniThrowException(env, "java/lang/NoSuchMethodError",
-                "InetAddress.getByAddress(byte[] val)");
-        return;
-    }
-
-    gCachedFields.iaddr_getbyaddress = iaddrgetbyaddress;
-
-    jfieldID iaddripaddress = env->GetFieldID(iaddrclass, "ipaddress", "[B");
-
-    if (iaddripaddress == NULL) {
-        jniThrowException(env, "java/lang/NoSuchFieldError",
-                "Can't find field InetAddress.ipaddress");
-        return;
-    }
-
-    gCachedFields.iaddr_ipaddress = iaddripaddress;
-
-    // get the GenericIPMreq class
-
-    jclass genericipmreqclass = env->FindClass("org/apache/harmony/luni/net/GenericIPMreq");
-
-    if (genericipmreqclass == NULL) {
-        jniThrowException(env, "java/lang/ClassNotFoundException",
-                "org.apache.harmony.luni.net.GenericIPMreq");
-        return;
-    }
-
-    gCachedFields.genericipmreq_class = (jclass) env->NewGlobalRef(genericipmreqclass);
-
-    // initializing Integer
-
-    jclass integerclass = env->FindClass("java/lang/Integer");
-
-    if (integerclass == NULL) {
-        jniThrowException(env, "java/lang/ClassNotFoundException",
-                "java.lang.Integer");
-        return;
-    }
-
-    jmethodID integerclassinit = env->GetMethodID(integerclass, "<init>", "(I)V");
-
-    if (integerclassinit == NULL) {
-        jniThrowException(env, "java/lang/NoSuchMethodError",
-                "Integer.<init>(int val)");
-        return;
-    }
-
-    jfieldID integerclassvalue = env->GetFieldID(integerclass, "value", "I");
-
-    if (integerclassvalue == NULL) {
-        jniThrowException(env, "java/lang/NoSuchMethodError", "Integer.value");
-        return;
-    }
-
-    gCachedFields.integer_class = (jclass) env->NewGlobalRef(integerclass);
-    gCachedFields.integer_class_init = integerclassinit;
-    gCachedFields.integer_class_value = integerclassvalue;
-
-    // initializing Boolean
-
-    jclass booleanclass = env->FindClass("java/lang/Boolean");
-
-    if (booleanclass == NULL) {
-        jniThrowException(env, "java/lang/ClassNotFoundException",
-                "java.lang.Boolean");
-        return;
-    }
-
-    jmethodID booleanclassinit = env->GetMethodID(booleanclass, "<init>", "(Z)V");
-
-    if (booleanclassinit == NULL) {
-        jniThrowException(env, "java/lang/NoSuchMethodError",
-                "Boolean.<init>(boolean val)");
-        return;
-    }
-
-    jfieldID booleanclassvalue = env->GetFieldID(booleanclass, "value", "Z");
-
-    if (booleanclassvalue == NULL) {
-        jniThrowException(env, "java/lang/NoSuchMethodError", "Boolean.value");
-        return;
-    }
-
-    gCachedFields.boolean_class = (jclass) env->NewGlobalRef(booleanclass);
-    gCachedFields.boolean_class_init = booleanclassinit;
-    gCachedFields.boolean_class_value = booleanclassvalue;
-
-    // initializing Byte
-
-    jclass byteclass = env->FindClass("java/lang/Byte");
-
-    if (byteclass == NULL) {
-        jniThrowException(env, "java/lang/ClassNotFoundException",
-                "java.lang.Byte");
-        return;
-    }
-
-    jmethodID byteclassinit = env->GetMethodID(byteclass, "<init>", "(B)V");
-
-    if (byteclassinit == NULL) {
-        jniThrowException(env, "java/lang/NoSuchMethodError",
-                "Byte.<init>(byte val)");
-        return;
-    }
-
-    jfieldID byteclassvalue = env->GetFieldID(byteclass, "value", "B");
-
-    if (byteclassvalue == NULL) {
-        jniThrowException(env, "java/lang/NoSuchMethodError", "Byte.value");
-        return;
-    }
-
-    gCachedFields.byte_class = (jclass) env->NewGlobalRef(byteclass);
-    gCachedFields.byte_class_init = byteclassinit;
-    gCachedFields.byte_class_value = byteclassvalue;
-
-    // initializing String
-
-    jclass stringclass = env->FindClass("java/lang/String");
-
-    if (stringclass == NULL) {
-        jniThrowException(env, "java/lang/ClassNotFoundException",
-                "java.lang.String");
-        return;
-    }
-
-    jmethodID stringclassinit = env->GetMethodID(stringclass, "<init>", "([B)V");
-
-    if (stringclassinit == NULL) {
-        jniThrowException(env, "java/lang/NoSuchMethodError",
-                "String.<init>(byte[] val)");
-        return;
-    }
-
-    gCachedFields.string_class = (jclass) env->NewGlobalRef(stringclass);
-    gCachedFields.string_class_init = stringclassinit;
-
-    // initializing ScoketImpl
-
-    jclass socketimplclass = env->FindClass("java/net/SocketImpl");
-
-    if (socketimplclass == NULL) {
-        jniThrowException(env, "java/lang/ClassNotFoundException",
-                "java.net.SocketImpl");
-        return;
-    }
-
-    jfieldID socketimplport = env->GetFieldID(socketimplclass, "port", "I");
-
-    if (socketimplport == NULL) {
-        jniThrowException(env, "java/lang/NoSuchFieldError", "SocketImpl.port");
-        return;
-    }
-
-    jfieldID socketimpladdress = env->GetFieldID(socketimplclass, "address",
-            "Ljava/net/InetAddress;");
-
-    if (socketimpladdress == NULL) {
-        jniThrowException(env, "java/lang/NoSuchFieldError",
-                "SocketImpl.address");
-        return;
-    }
-
-    gCachedFields.socketimpl_address = socketimpladdress;
-    gCachedFields.socketimpl_port = socketimplport;
-
-    gCachedFields.dpack_class = env->FindClass("java/net/DatagramPacket");
-    if (gCachedFields.dpack_class == NULL) {
-        jniThrowException(env, "java/lang/ClassNotFoundException",
-                "java.net.DatagramPacket");
-        return;
-    }
-
-    gCachedFields.dpack_address = env->GetFieldID(gCachedFields.dpack_class,
-            "address", "Ljava/net/InetAddress;");
-    if (gCachedFields.dpack_address == NULL) {
-        jniThrowException(env, "java/lang/NoSuchFieldError",
-                "DatagramPacket.address");
-        return;
-    }
-
-    gCachedFields.dpack_port = env->GetFieldID(gCachedFields.dpack_class,
-            "port", "I");
-    if (gCachedFields.dpack_port == NULL) {
-        jniThrowException(env, "java/lang/NoSuchFieldError",
-                "DatagramPacket.port");
-        return;
-    }
-
-    gCachedFields.dpack_length = env->GetFieldID(gCachedFields.dpack_class,
-            "length", "I");
-    if (gCachedFields.dpack_length == NULL) {
-        jniThrowException(env, "java/lang/NoSuchFieldError",
-                "DatagramPacket.length");
-        return;
+    struct CachedFields *c = &gCachedFields;
+
+    struct classInfo {
+        jclass *clazz;
+        const char *name;
+    } classes[] = {
+        {&c->iaddr_class, "java/net/InetAddress"},
+        {&c->i4addr_class, "java/net/Inet4Address"},
+        {&c->genericipmreq_class, "org/apache/harmony/luni/net/GenericIPMreq"},
+        {&c->integer_class, "java/lang/Integer"},
+        {&c->boolean_class, "java/lang/Boolean"},
+        {&c->byte_class, "java/lang/Byte"},
+        {&c->string_class, "java/lang/String"},
+        {&c->socketimpl_class, "java/net/SocketImpl"},
+        {&c->dpack_class, "java/net/DatagramPacket"}
+    };
+    for (unsigned i = 0; i < sizeof(classes) / sizeof(classes[0]); i++) {
+        classInfo c = classes[i];
+        jclass tempClass = env->FindClass(c.name);
+        if (tempClass == NULL) return;
+        *c.clazz = (jclass) env->NewGlobalRef(tempClass);
+    }
+
+    struct methodInfo {
+        jmethodID *method;
+        jclass clazz;
+        const char *name;
+        const char *signature;
+        bool isStatic;
+    } methods[] = {
+        {&c->i4addr_class_init, c->i4addr_class, "<init>", "([B)V", false},
+        {&c->integer_class_init, c->integer_class, "<init>", "(I)V", false},
+        {&c->boolean_class_init, c->boolean_class, "<init>", "(Z)V", false},
+        {&c->byte_class_init, c->byte_class, "<init>", "(B)V", false},
+        {&c->string_class_init, c->string_class, "<init>", "([B)V", false},
+        {&c->iaddr_getbyaddress, c->iaddr_class, "getByAddress",
+                    "([B)Ljava/net/InetAddress;", true}
+    };
+    for (unsigned i = 0; i < sizeof(methods) / sizeof(methods[0]); i++) {
+        methodInfo m = methods[i];
+        if (m.isStatic) {
+            *m.method = env->GetStaticMethodID(m.clazz, m.name, m.signature);
+        } else {
+            *m.method = env->GetMethodID(m.clazz, m.name, m.signature);
+        }
+        if (*m.method == NULL) return;
+    }
+
+    struct fieldInfo {
+        jfieldID *field;
+        jclass clazz;
+        const char *name;
+        const char *type;
+    } fields[] = {
+        {&c->iaddr_ipaddress, c->iaddr_class, "ipaddress", "[B"},
+        {&c->integer_class_value, c->integer_class, "value", "I"},
+        {&c->boolean_class_value, c->boolean_class, "value", "Z"},
+        {&c->byte_class_value, c->byte_class, "value", "B"},
+        {&c->socketimpl_port, c->socketimpl_class, "port", "I"},
+        {&c->socketimpl_address, c->socketimpl_class, "address",
+                "Ljava/net/InetAddress;"},
+        {&c->dpack_address, c->dpack_class, "address",
+                "Ljava/net/InetAddress;"},
+        {&c->dpack_port, c->dpack_class, "port", "I"},
+        {&c->dpack_length, c->dpack_class, "length", "I"}
+    };
+    for (unsigned i = 0; i < sizeof(fields) / sizeof(fields[0]); i++) {
+        fieldInfo f = fields[i];
+        *f.field = env->GetFieldID(f.clazz, f.name, f.type);
+        if (*f.field == NULL) return;
     }
-
 }
 
 /**
@@ -1634,8 +1550,10 @@ static void osNetworkSystem_oneTimeInitializationImpl(JNIEnv* env, jobject obj,
  *
  * @param fileDescriptor the file descriptor to bind the socket to
  * @param type the socket type to create, e.g., SOCK_STREAM
+ * @throws SocketException an error occurred when creating the socket
  *
- * @return the socket file descriptor, or -1 on failure
+ * @return the socket file descriptor. On failure, an exception is thrown and
+ *         a negative value is returned.
  *
  */
 static int createSocketFileDescriptor(JNIEnv* env, jobject fileDescriptor,
@@ -1654,13 +1572,14 @@ static int createSocketFileDescriptor(JNIEnv* env, jobject fileDescriptor,
     if (sock < 0) {
         int err = convertError(errno);
         throwSocketException(env, err);
+        return sock;
     }
     jniSetFileDescriptorOfFD(env, fileDescriptor, sock);
     return sock;
 }
 
 
-static void osNetworkSystem_createSocketImpl(JNIEnv* env, jclass clazz,
+static void osNetworkSystem_createStreamSocketImpl(JNIEnv* env, jclass clazz,
         jobject fileDescriptor, jboolean preferIPv4Stack) {
     // LOGD("ENTER createSocketImpl");
     createSocketFileDescriptor(env, fileDescriptor, SOCK_STREAM);
@@ -2346,35 +2265,6 @@ static void osNetworkSystem_disconnectDatagramImpl(JNIEnv* env, jclass clazz,
     }
 }
 
-static jboolean osNetworkSystem_socketBindImpl2(JNIEnv* env, jclass clazz,
-        jobject fileDescriptor, jint port, jboolean bindToDevice,
-        jobject inetAddress) {
-    // LOGD("ENTER socketBindImpl2");
-
-    struct sockaddr_storage sockaddress;
-    int ret;
-    int handle;
-
-    ret = inetAddressToSocketAddress(env, inetAddress, port, &sockaddress);
-    if (ret < 0)  // Exception has already been thrown.
-        return 0;
-
-    handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
-    if (handle == 0 || handle == -1) {
-        throwSocketException(env, SOCKERR_BADDESC);
-        return 0;
-    }
-
-    ret = doBind(handle, &sockaddress);
-    if (ret < 0) {
-        int err = convertError(errno);
-        jniThrowException(env, "java/net/BindException", netLookupErrorString(err));
-        return 0;
-    }
-
-    return 0;
-}
-
 static jint osNetworkSystem_peekDatagramImpl(JNIEnv* env, jclass clazz,
         jobject fd, jobject sender, jint receiveTimeout) {
     // LOGD("ENTER peekDatagramImpl");
@@ -2645,19 +2535,6 @@ static void osNetworkSystem_createServerStreamSocketImpl(JNIEnv* env,
     setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(int));
 }
 
-static void osNetworkSystem_createMulticastSocketImpl(JNIEnv* env,
-        jclass clazz, jobject fileDescriptor, jboolean preferIPv4Stack) {
-    // LOGD("ENTER createMulticastSocketImpl");
-
-    int handle = createSocketFileDescriptor(env, fileDescriptor, SOCK_DGRAM);
-    if (handle < 0)
-        return;
-
-    int value = 1;
-    // setsockopt(handle, SOL_SOCKET, SO_REUSEPORT, &value, sizeof(jbyte));
-    setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(int));
-}
-
 /*
  * @param timeout in milliseconds.  If zero, block until data received
  */
@@ -3488,88 +3365,6 @@ static void osNetworkSystem_socketCloseImpl(JNIEnv* env, jclass clazz,
     close(handle);
 }
 
-static jobject osNetworkSystem_getHostByAddrImpl(JNIEnv* env, jclass clazz,
-        jbyteArray addrStr) {
-    // LOGD("ENTER getHostByAddrImpl");
-
-    if (addrStr == NULL) {
-        throwNullPointerException(env);
-        return JNI_FALSE;
-    }
-
-    jstring address = (jstring)newJavaLangString(env, addrStr);
-    jstring result;
-    const char* addr = env->GetStringUTFChars(address, NULL);
-
-    struct hostent* ent = gethostbyaddr(addr, strlen(addr), AF_INET);
-
-    if (ent != NULL  && ent->h_name != NULL) {
-        result = env->NewStringUTF(ent->h_name);
-    } else {
-        result = NULL;
-    }
-
-    env->ReleaseStringUTFChars(address, addr);
-
-    return result;
-}
-
-static jobject osNetworkSystem_getHostByNameImpl(JNIEnv* env, jclass clazz,
-        jstring nameStr, jboolean preferIPv6Addresses) {
-    // LOGD("ENTER getHostByNameImpl");
-
-    if (nameStr == NULL) {
-        throwNullPointerException(env);
-        return NULL;
-    }
-
-    const char* name = env->GetStringUTFChars(nameStr, NULL);
-
-    if (useAdbNetworking) {
-
-        union {
-            struct in_addr a;
-            jbyte j[4];
-        } outaddr;
-
-        // LOGD("ADB networking: +gethostbyname '%s'", name);
-        int err;
-        err = adb_networking_gethostbyname(name, &(outaddr.a));
-
-        env->ReleaseStringUTFChars(nameStr, name);
-#if 0
-        LOGD("ADB networking: -gethostbyname err %d addr 0x%08x %u.%u.%u.%u",
-                err, (unsigned int)outaddr.a.s_addr,
-                outaddr.j[0],outaddr.j[1],
-                outaddr.j[2],outaddr.j[3]);
-#endif
-
-        if (err < 0) {
-            return NULL;
-        } else {
-            jbyteArray addr = env->NewByteArray(4);
-            env->SetByteArrayRegion(addr, 0, 4, outaddr.j);
-            return addr;
-        }
-    } else {
-
-        // normal case...no adb networking
-        struct hostent* ent = gethostbyname(name);
-
-        env->ReleaseStringUTFChars(nameStr, name);
-
-        if (ent != NULL  && ent->h_length > 0) {
-            jbyteArray addr = env->NewByteArray(4);
-            jbyte v[4];
-            memcpy(v, ent->h_addr, 4);
-            env->SetByteArrayRegion(addr, 0, 4, v);
-            return addr;
-        } else {
-            return NULL;
-        }
-    }
-}
-
 static void osNetworkSystem_setInetAddressImpl(JNIEnv* env, jobject obj,
         jobject sender, jbyteArray address) {
     // LOGD("ENTER setInetAddressImpl");
@@ -3669,8 +3464,10 @@ static jobject osNetworkSystem_inheritedChannelImpl(JNIEnv* env, jobject obj) {
                     ntohs(local_addr.sin_port));
 
             // new and set remote addr
-            addr_object = env->NewObject(gCachedFields.iaddr_class,
-                    gCachedFields.iaddr_class_init);
+            addr_array = env->NewByteArray((jsize)4);
+            env->SetByteArrayRegion(addr_array, (jsize)0, (jsize)4, address);
+            addr_object = env->NewObject(gCachedFields.i4addr_class,
+                    gCachedFields.i4addr_class_init, addr_array);
             if (NULL == addr_object) {
                 goto clean;
             }
@@ -3682,13 +3479,6 @@ static jobject osNetworkSystem_inheritedChannelImpl(JNIEnv* env, jobject obj) {
             if (NULL == socketaddr_object) {
                 goto clean;
             }
-            addr_field = env->GetFieldID(socketaddr_class, "addr",
-                    "Ljava/net/InetAddress;");
-            env->SetObjectField(socketaddr_object, addr_field, addr_object);
-            addr_array = env->NewByteArray((jsize)4);
-            env->SetByteArrayRegion(addr_array, (jsize)0, (jsize)4, address);
-            env->SetObjectField(addr_object, gCachedFields.iaddr_ipaddress,
-                     addr_array);
 
             // localAddr
             socketaddr_class = env->FindClass("java/net/InetSocketAddress");
@@ -3698,9 +3488,11 @@ static jobject osNetworkSystem_inheritedChannelImpl(JNIEnv* env, jobject obj) {
                      socketaddr_field);
 
             localAddr_field = env->GetFieldID(channel_class, "localAddress",
-                     "Ljava/net/InetAddress;");
-            localAddr_object = env->NewObject(gCachedFields.iaddr_class,
-                     gCachedFields.iaddr_class_init);
+                     "Ljava/net/Inet4Address;");
+            addr_array = env->NewByteArray((jsize)4);
+            env->SetByteArrayRegion(addr_array, (jsize)0, (jsize)4, localAddr);
+            localAddr_object = env->NewObject(gCachedFields.i4addr_class,
+                     gCachedFields.i4addr_class_init, addr_array);
             jfieldID socketaddr_field = env->GetFieldID(channel_class,
                      "connectAddress", "Ljava/net/InetSocketAddress;");
             jobject socketaddr_object = env->GetObjectField(channel_object,
@@ -3710,10 +3502,6 @@ static jobject osNetworkSystem_inheritedChannelImpl(JNIEnv* env, jobject obj) {
             if (NULL == localAddr_object) {
                 goto clean;
             }
-            addr_array = env->NewByteArray((jsize)4);
-            env->SetByteArrayRegion(addr_array, (jsize)0, (jsize)4, localAddr);
-            env->SetObjectField(localAddr_object, gCachedFields.iaddr_ipaddress,
-                    addr_array);
 
 
             // set port
@@ -3766,10 +3554,13 @@ static jobject osNetworkSystem_inheritedChannelImpl(JNIEnv* env, jobject obj) {
                  goto clean;
             }
 
+            addr_array = env->NewByteArray((jsize)4);
             localAddr_field = env->GetFieldID(channel_class, "localAddress",
                     "Ljava/net/InetAddress;");
-            localAddr_object = env->NewObject(gCachedFields.iaddr_class,
-                    gCachedFields.iaddr_class_init);
+            memset(address, 0, 4);
+            env->SetByteArrayRegion(addr_array, (jsize)0, (jsize)4, address);
+            localAddr_object = env->NewObject(gCachedFields.i4addr_class,
+                    gCachedFields.i4addr_class_init, addr_array);
             if (NULL == localAddr_object) {
                  goto clean;
             }
@@ -3816,8 +3607,10 @@ static jobject osNetworkSystem_inheritedChannelImpl(JNIEnv* env, jobject obj) {
         env->SetIntField(channel_object, port_field, ntohs(local_addr.sin_port));
 
         // new and set remote addr
+        addr_array = env->NewByteArray((jsize)4);
+        env->SetByteArrayRegion(addr_array, (jsize)0, (jsize)4, address);
         addr_object = env->NewObject(gCachedFields.iaddr_class,
-                gCachedFields.iaddr_class_init);
+                gCachedFields.i4addr_class_init, addr_array);
         if (NULL == addr_object) {
             goto clean;
         }
@@ -3828,12 +3621,6 @@ static jobject osNetworkSystem_inheritedChannelImpl(JNIEnv* env, jobject obj) {
         if (NULL == socketaddr_object) {
             goto clean;
         }
-        addr_field = env->GetFieldID(socketaddr_class, "addr",
-                "Ljava/net/InetAddress;");
-        env->SetObjectField(socketaddr_object, addr_field, addr_object);
-        addr_array = env->NewByteArray((jsize)4);
-        env->SetByteArrayRegion(addr_array, (jsize)0, (jsize)4, address);
-        env->SetObjectField(addr_object, gCachedFields.iaddr_ipaddress, addr_array);
 
         // set bound
         if (0 != local_addr.sin_port) {
@@ -3853,7 +3640,7 @@ clean:
 static JNINativeMethod gMethods[] = {
     /* name, signature, funcPtr */
     { "oneTimeInitializationImpl",         "(Z)V",                                                                     (void*) osNetworkSystem_oneTimeInitializationImpl          },
-    { "createSocketImpl",                  "(Ljava/io/FileDescriptor;Z)V",                                             (void*) osNetworkSystem_createSocketImpl                   },
+    { "createStreamSocketImpl",            "(Ljava/io/FileDescriptor;Z)V",                                             (void*) osNetworkSystem_createStreamSocketImpl             },
     { "createDatagramSocketImpl",          "(Ljava/io/FileDescriptor;Z)V",                                             (void*) osNetworkSystem_createDatagramSocketImpl           },
     { "readSocketImpl",                    "(Ljava/io/FileDescriptor;[BIII)I",                                         (void*) osNetworkSystem_readSocketImpl                     },
     { "readSocketDirectImpl",              "(Ljava/io/FileDescriptor;IIII)I",                                          (void*) osNetworkSystem_readSocketDirectImpl               },
@@ -3871,7 +3658,6 @@ static JNINativeMethod gMethods[] = {
     { "sendUrgentDataImpl",                "(Ljava/io/FileDescriptor;B)V",                                             (void*) osNetworkSystem_sendUrgentDataImpl                 },
     { "connectDatagramImpl2",              "(Ljava/io/FileDescriptor;IILjava/net/InetAddress;)V",                      (void*) osNetworkSystem_connectDatagramImpl2               },
     { "disconnectDatagramImpl",            "(Ljava/io/FileDescriptor;)V",                                              (void*) osNetworkSystem_disconnectDatagramImpl             },
-    { "socketBindImpl2",                   "(Ljava/io/FileDescriptor;IZLjava/net/InetAddress;)Z",                      (void*) osNetworkSystem_socketBindImpl2                    },
     { "peekDatagramImpl",                  "(Ljava/io/FileDescriptor;Ljava/net/InetAddress;I)I",                       (void*) osNetworkSystem_peekDatagramImpl                   },
     { "receiveDatagramImpl",               "(Ljava/io/FileDescriptor;Ljava/net/DatagramPacket;[BIIIZ)I",               (void*) osNetworkSystem_receiveDatagramImpl                },
     { "receiveDatagramDirectImpl",         "(Ljava/io/FileDescriptor;Ljava/net/DatagramPacket;IIIIZ)I",                (void*) osNetworkSystem_receiveDatagramDirectImpl          },
@@ -3882,7 +3668,6 @@ static JNINativeMethod gMethods[] = {
     { "sendConnectedDatagramImpl",         "(Ljava/io/FileDescriptor;[BIIZ)I",                                         (void*) osNetworkSystem_sendConnectedDatagramImpl          },
     { "sendConnectedDatagramDirectImpl",   "(Ljava/io/FileDescriptor;IIIZ)I",                                          (void*) osNetworkSystem_sendConnectedDatagramDirectImpl    },
     { "createServerStreamSocketImpl",      "(Ljava/io/FileDescriptor;Z)V",                                             (void*) osNetworkSystem_createServerStreamSocketImpl       },
-    { "createMulticastSocketImpl",         "(Ljava/io/FileDescriptor;Z)V",                                             (void*) osNetworkSystem_createMulticastSocketImpl          },
     { "receiveStreamImpl",                 "(Ljava/io/FileDescriptor;[BIII)I",                                         (void*) osNetworkSystem_receiveStreamImpl                  },
     { "sendStreamImpl",                    "(Ljava/io/FileDescriptor;[BII)I",                                          (void*) osNetworkSystem_sendStreamImpl                     },
     { "shutdownInputImpl",                 "(Ljava/io/FileDescriptor;)V",                                              (void*) osNetworkSystem_shutdownInputImpl                  },
@@ -3895,10 +3680,9 @@ static JNINativeMethod gMethods[] = {
     { "setSocketOptionImpl",               "(Ljava/io/FileDescriptor;ILjava/lang/Object;)V",                           (void*) osNetworkSystem_setSocketOptionImpl                },
     { "getSocketFlagsImpl",                "()I",                                                                      (void*) osNetworkSystem_getSocketFlagsImpl                 },
     { "socketCloseImpl",                   "(Ljava/io/FileDescriptor;)V",                                              (void*) osNetworkSystem_socketCloseImpl                    },
-    { "getHostByAddrImpl",                 "([B)Ljava/net/InetAddress;",                                               (void*) osNetworkSystem_getHostByAddrImpl                  },
-    { "getHostByNameImpl",                 "(Ljava/lang/String;Z)Ljava/net/InetAddress;",                              (void*) osNetworkSystem_getHostByNameImpl                  },
     { "setInetAddressImpl",                "(Ljava/net/InetAddress;[B)V",                                              (void*) osNetworkSystem_setInetAddressImpl                 },
     { "inheritedChannelImpl",              "()Ljava/nio/channels/Channel;",                                            (void*) osNetworkSystem_inheritedChannelImpl               },
+    { "byteArrayToIpString",               "([B)Ljava/lang/String;",                                                   (void*) osNetworkSystem_byteArrayToIpString                },
 };
 
 int register_org_apache_harmony_luni_platform_OSNetworkSystem(JNIEnv* env) {