+ 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);