Home | History | Annotate | Download | only in native
      1 /*
      2  * Copyright (C) 2007 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *     http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 // BEGIN android-changed
     18 //
     19 // This file has been substantially reworked in order to provide more IPv6
     20 // support and to move functionality from Java to native code where it made
     21 // sense (e.g. when converting between IP addresses, socket structures, and
     22 // strings, for which there exist fast and robust native implementations).
     23 
     24 #define LOG_TAG "OSNetworkSystem"
     25 
     26 #include "AndroidSystemNatives.h"
     27 #include "JNIHelp.h"
     28 #include "LocalArray.h"
     29 #include "jni.h"
     30 
     31 #include <arpa/inet.h>
     32 #include <assert.h>
     33 #include <errno.h>
     34 #include <netdb.h>
     35 #include <netinet/in.h>
     36 #include <netinet/tcp.h>
     37 #include <stdio.h>
     38 #include <stdlib.h>
     39 #include <string.h>
     40 #include <sys/ioctl.h>
     41 #include <sys/socket.h>
     42 #include <sys/time.h>
     43 #include <sys/un.h>
     44 #include <unistd.h>
     45 
     46 // Temporary hack to build on systems that don't have up-to-date libc headers.
     47 #ifndef IPV6_TCLASS
     48 #ifdef __linux__
     49 #define IPV6_TCLASS 67 // Linux
     50 #else
     51 #define IPV6_TCLASS -1 // BSD(-like); TODO: Something better than this!
     52 #endif
     53 #endif
     54 
     55 /*
     56  * TODO: The multicast code is highly platform-dependent, and for now
     57  * we just punt on anything but Linux.
     58  */
     59 #ifdef __linux__
     60 #define ENABLE_MULTICAST
     61 #endif
     62 
     63 /**
     64  * @name Socket Errors
     65  * Error codes for socket operations
     66  *
     67  * @internal SOCKERR* range from -200 to -299 avoid overlap
     68  */
     69 #define SOCKERR_NOTINITIALIZED     -201 /* socket library uninitialized */
     70 #define SOCKERR_BADAF              -202 /* bad address family */
     71 #define SOCKERR_BADPROTO           -203 /* bad protocol */
     72 #define SOCKERR_BADTYPE            -204 /* bad type */
     73 #define SOCKERR_SYSTEMBUSY         -205 /* system busy handling requests */
     74 #define SOCKERR_SYSTEMFULL         -206 /* too many sockets */
     75 #define SOCKERR_NOTCONNECTED       -207 /* socket is not connected */
     76 #define SOCKERR_INTERRUPTED        -208 /* the call was cancelled */
     77 #define SOCKERR_TIMEOUT            -209 /* the operation timed out */
     78 #define SOCKERR_CONNRESET          -210 /* the connection was reset */
     79 #define SOCKERR_WOULDBLOCK         -211 /* the socket is marked as nonblocking operation would block */
     80 #define SOCKERR_ADDRNOTAVAIL       -212 /* address not available */
     81 #define SOCKERR_ADDRINUSE          -213 /* address already in use */
     82 #define SOCKERR_NOTBOUND           -214 /* the socket is not bound */
     83 #define SOCKERR_INVALIDTIMEOUT     -216 /* the specified timeout is invalid */
     84 #define SOCKERR_FDSETFULL          -217 /* Unable to create an FDSET */
     85 #define SOCKERR_TIMEVALFULL        -218 /* Unable to create a TIMEVAL */
     86 #define SOCKERR_REMSOCKSHUTDOWN    -219 /* The remote socket has shutdown gracefully */
     87 #define SOCKERR_NOTLISTENING       -220 /* listen() was not invoked prior to accept() */
     88 #define SOCKERR_NOTSTREAMSOCK      -221 /* The socket does not support connection-oriented service */
     89 #define SOCKERR_ALREADYBOUND       -222 /* The socket is already bound to an address */
     90 #define SOCKERR_NBWITHLINGER       -223 /* The socket is marked non-blocking & SO_LINGER is non-zero */
     91 #define SOCKERR_ISCONNECTED        -224 /* The socket is already connected */
     92 #define SOCKERR_NOBUFFERS          -225 /* No buffer space is available */
     93 #define SOCKERR_HOSTNOTFOUND       -226 /* Authoritative Answer Host not found */
     94 #define SOCKERR_NODATA             -227 /* Valid name, no data record of requested type */
     95 #define SOCKERR_BOUNDORCONN        -228 /* The socket has not been bound or is already connected */
     96 #define SOCKERR_OPNOTSUPP          -229 /* The socket does not support the operation */
     97 #define SOCKERR_OPTUNSUPP          -230 /* The socket option is not supported */
     98 #define SOCKERR_OPTARGSINVALID     -231 /* The socket option arguments are invalid */
     99 #define SOCKERR_SOCKLEVELINVALID   -232 /* The socket level is invalid */
    100 #define SOCKERR_TIMEOUTFAILURE     -233
    101 #define SOCKERR_SOCKADDRALLOCFAIL  -234 /* Unable to allocate the sockaddr structure */
    102 #define SOCKERR_FDSET_SIZEBAD      -235 /* The calculated maximum size of the file descriptor set is bad */
    103 #define SOCKERR_UNKNOWNFLAG        -236 /* The flag is unknown */
    104 #define SOCKERR_MSGSIZE            -237 /* The datagram was too big to fit the specified buffer & was truncated. */
    105 #define SOCKERR_NORECOVERY         -238 /* The operation failed with no recovery possible */
    106 #define SOCKERR_ARGSINVALID        -239 /* The arguments are invalid */
    107 #define SOCKERR_BADDESC            -240 /* The socket argument is not a valid file descriptor */
    108 #define SOCKERR_NOTSOCK            -241 /* The socket argument is not a socket */
    109 #define SOCKERR_HOSTENTALLOCFAIL   -242 /* Unable to allocate the hostent structure */
    110 #define SOCKERR_TIMEVALALLOCFAIL   -243 /* Unable to allocate the timeval structure */
    111 #define SOCKERR_LINGERALLOCFAIL    -244 /* Unable to allocate the linger structure */
    112 #define SOCKERR_IPMREQALLOCFAIL    -245 /* Unable to allocate the ipmreq structure */
    113 #define SOCKERR_FDSETALLOCFAIL     -246 /* Unable to allocate the fdset structure */
    114 #define SOCKERR_OPFAILED           -247 /* Operation failed */
    115 #define SOCKERR_VALUE_NULL         -248 /* The value indexed was NULL */
    116 #define SOCKERR_CONNECTION_REFUSED -249 /* connection was refused */
    117 #define SOCKERR_ENETUNREACH        -250 /* network is not reachable */
    118 #define SOCKERR_EACCES             -251 /* permissions do not allow action on socket */
    119 #define SOCKERR_EHOSTUNREACH       -252 /* no route to host */
    120 #define SOCKERR_EPIPE              -253 /* broken pipe */
    121 
    122 #define JAVASOCKOPT_TCP_NODELAY 1
    123 #define JAVASOCKOPT_IP_TOS 3
    124 #define JAVASOCKOPT_SO_REUSEADDR 4
    125 #define JAVASOCKOPT_SO_KEEPALIVE 8
    126 #define JAVASOCKOPT_IP_MULTICAST_IF 16
    127 #define JAVASOCKOPT_MCAST_TTL 17
    128 #define JAVASOCKOPT_IP_MULTICAST_LOOP 18
    129 #define JAVASOCKOPT_MCAST_ADD_MEMBERSHIP 19
    130 #define JAVASOCKOPT_MCAST_DROP_MEMBERSHIP 20
    131 #define JAVASOCKOPT_IP_MULTICAST_IF2 31
    132 #define JAVASOCKOPT_SO_BROADCAST 32
    133 #define JAVASOCKOPT_SO_LINGER 128
    134 #define JAVASOCKOPT_REUSEADDR_AND_REUSEPORT  10001
    135 #define JAVASOCKOPT_SO_SNDBUF 4097
    136 #define JAVASOCKOPT_SO_RCVBUF 4098
    137 #define JAVASOCKOPT_SO_RCVTIMEOUT  4102
    138 #define JAVASOCKOPT_SO_OOBINLINE  4099
    139 
    140 /* constants for calling multi-call functions */
    141 #define SOCKET_STEP_START 10
    142 #define SOCKET_STEP_CHECK 20
    143 #define SOCKET_STEP_DONE 30
    144 
    145 #define BROKEN_MULTICAST_IF 1
    146 #define BROKEN_MULTICAST_TTL 2
    147 #define BROKEN_TCP_NODELAY 4
    148 
    149 #define SOCKET_CONNECT_STEP_START 0
    150 #define SOCKET_CONNECT_STEP_CHECK 1
    151 
    152 #define SOCKET_OP_NONE 0
    153 #define SOCKET_OP_READ 1
    154 #define SOCKET_OP_WRITE 2
    155 
    156 #define SOCKET_NOFLAGS 0
    157 
    158 // Local constants for getOrSetSocketOption
    159 #define SOCKOPT_GET 1
    160 #define SOCKOPT_SET 2
    161 
    162 struct CachedFields {
    163     jfieldID fd_descriptor;
    164     jclass iaddr_class;
    165     jmethodID iaddr_getbyaddress;
    166     jclass i4addr_class;
    167     jmethodID i4addr_class_init;
    168     jfieldID iaddr_ipaddress;
    169     jclass genericipmreq_class;
    170     jclass integer_class;
    171     jmethodID integer_class_init;
    172     jfieldID integer_class_value;
    173     jclass boolean_class;
    174     jmethodID boolean_class_init;
    175     jfieldID boolean_class_value;
    176     jclass byte_class;
    177     jmethodID byte_class_init;
    178     jfieldID byte_class_value;
    179     jclass socketimpl_class;
    180     jfieldID socketimpl_address;
    181     jfieldID socketimpl_port;
    182     jclass dpack_class;
    183     jfieldID dpack_address;
    184     jfieldID dpack_port;
    185     jfieldID dpack_length;
    186 } gCachedFields;
    187 
    188 /* needed for connecting with timeout */
    189 struct selectFDSet {
    190   int nfds;
    191   int sock;
    192   fd_set writeSet;
    193   fd_set readSet;
    194   fd_set exceptionSet;
    195 };
    196 
    197 static const char * netLookupErrorString(int anErrorNum);
    198 
    199 /**
    200  * Throws an SocketException with the message affiliated with the errorCode.
    201  *
    202  * @deprecated: 'errorCode' is one of the bogus SOCKERR_ values, *not* errno.
    203  * jniThrowSocketException is the better choice.
    204  */
    205 static void throwSocketException(JNIEnv *env, int errorCode) {
    206     jniThrowException(env, "java/net/SocketException",
    207         netLookupErrorString(errorCode));
    208 }
    209 
    210 // TODO(enh): move to JNIHelp.h
    211 static void jniThrowExceptionWithErrno(JNIEnv* env,
    212         const char* exceptionClassName, int error) {
    213     char buf[BUFSIZ];
    214     jniThrowException(env, exceptionClassName,
    215             jniStrError(error, buf, sizeof(buf)));
    216 }
    217 
    218 static void jniThrowBindException(JNIEnv* env, int error) {
    219     jniThrowExceptionWithErrno(env, "java/net/BindException", error);
    220 }
    221 
    222 static void jniThrowSocketException(JNIEnv* env, int error) {
    223     jniThrowExceptionWithErrno(env, "java/net/SocketException", error);
    224 }
    225 
    226 static void jniThrowSocketTimeoutException(JNIEnv* env, int error) {
    227     jniThrowExceptionWithErrno(env, "java/net/SocketTimeoutException", error);
    228 }
    229 
    230 // Used by functions that shouldn't throw SocketException. (These functions
    231 // aren't meant to see bad addresses, so seeing one really does imply an
    232 // internal error.)
    233 // TODO: fix the code (native and Java) so we don't paint ourselves into this corner.
    234 static void jniThrowBadAddressFamily(JNIEnv* env) {
    235     jniThrowException(env, "java/lang/IllegalArgumentException", "Bad address family");
    236 }
    237 
    238 static bool jniGetFd(JNIEnv* env, jobject fileDescriptor, int& fd) {
    239     fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
    240     if (fd == -1) {
    241         jniThrowSocketException(env, EBADF);
    242         return false;
    243     }
    244     return true;
    245 }
    246 
    247 /**
    248  * Converts a native address structure to a Java byte array.
    249  */
    250 static jbyteArray socketAddressToByteArray(JNIEnv *env,
    251         struct sockaddr_storage *address) {
    252 
    253     void *rawAddress;
    254     size_t addressLength;
    255     if (address->ss_family == AF_INET) {
    256         struct sockaddr_in *sin = (struct sockaddr_in *) address;
    257         rawAddress = &sin->sin_addr.s_addr;
    258         addressLength = 4;
    259     } else if (address->ss_family == AF_INET6) {
    260         struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) address;
    261         rawAddress = &sin6->sin6_addr.s6_addr;
    262         addressLength = 16;
    263     } else {
    264         jniThrowBadAddressFamily(env);
    265         return NULL;
    266     }
    267 
    268     jbyteArray byteArray = env->NewByteArray(addressLength);
    269     if (byteArray == NULL) {
    270         return NULL;
    271     }
    272     env->SetByteArrayRegion(byteArray, 0, addressLength, (jbyte *) rawAddress);
    273 
    274     return byteArray;
    275 }
    276 
    277 /**
    278  * Returns the port number in a sockaddr_storage structure.
    279  *
    280  * @param address the sockaddr_storage structure to get the port from
    281  *
    282  * @return the port number, or -1 if the address family is unknown.
    283  */
    284 static int getSocketAddressPort(struct sockaddr_storage *address) {
    285     switch (address->ss_family) {
    286         case AF_INET:
    287             return ntohs(((struct sockaddr_in *) address)->sin_port);
    288         case AF_INET6:
    289             return ntohs(((struct sockaddr_in6 *) address)->sin6_port);
    290         default:
    291             return -1;
    292     }
    293 }
    294 
    295 /**
    296  * Obtain the socket address family from an existing socket.
    297  *
    298  * @param socket the file descriptor of the socket to examine
    299  * @return an integer, the address family of the socket
    300  */
    301 static int getSocketAddressFamily(int socket) {
    302     sockaddr_storage ss;
    303     socklen_t namelen = sizeof(ss);
    304     int ret = getsockname(socket, (sockaddr*) &ss, &namelen);
    305     if (ret != 0) {
    306         return AF_UNSPEC;
    307     } else {
    308         return ss.ss_family;
    309     }
    310 }
    311 
    312 jobject byteArrayToInetAddress(JNIEnv* env, jbyteArray byteArray) {
    313     if (byteArray == NULL) {
    314         return NULL;
    315     }
    316     return env->CallStaticObjectMethod(gCachedFields.iaddr_class,
    317             gCachedFields.iaddr_getbyaddress, byteArray);
    318 }
    319 
    320 /**
    321  * Converts a native address structure to an InetAddress object.
    322  * Throws a NullPointerException or an IOException in case of
    323  * error.
    324  *
    325  * @param sockAddress the sockaddr_storage structure to convert
    326  *
    327  * @return a jobject representing an InetAddress
    328  */
    329 jobject socketAddressToInetAddress(JNIEnv* env, sockaddr_storage* sockAddress) {
    330     jbyteArray byteArray = socketAddressToByteArray(env, sockAddress);
    331     return byteArrayToInetAddress(env, byteArray);
    332 }
    333 
    334 /**
    335  * Converts an IPv4 address to an IPv4-mapped IPv6 address if fd is an IPv6
    336  * socket.
    337  * @param fd the socket.
    338  * @param sin_ss the address.
    339  * @param sin6_ss scratch space where we can store the mapped address if necessary.
    340  * @param mapUnspecified if true, convert 0.0.0.0 to ::ffff:0:0; if false, to ::
    341  * @return either sin_ss or sin6_ss, depending on which the caller should use.
    342  */
    343 static const sockaddr* convertIpv4ToMapped(int fd,
    344         const sockaddr_storage* sin_ss, sockaddr_storage* sin6_ss, bool mapUnspecified) {
    345     // We need to map if we have an IPv4 address but an IPv6 socket.
    346     bool needsMapping = (sin_ss->ss_family == AF_INET && getSocketAddressFamily(fd) == AF_INET6);
    347     if (!needsMapping) {
    348         return reinterpret_cast<const sockaddr*>(sin_ss);
    349     }
    350     // Map the IPv4 address in sin_ss into an IPv6 address in sin6_ss.
    351     const sockaddr_in* sin = reinterpret_cast<const sockaddr_in*>(sin_ss);
    352     sockaddr_in6* sin6 = reinterpret_cast<sockaddr_in6*>(sin6_ss);
    353     memset(sin6, 0, sizeof(*sin6));
    354     sin6->sin6_family = AF_INET6;
    355     sin6->sin6_port = sin->sin_port;
    356     // TODO: mapUnspecified was introduced because kernels < 2.6.31 don't allow
    357     // you to bind to ::ffff:0.0.0.0. When we move to something >= 2.6.31, we
    358     // should make the code behave as if mapUnspecified were always true, and
    359     // remove the parameter.
    360     if (sin->sin_addr.s_addr != 0 || mapUnspecified) {
    361         memset(&(sin6->sin6_addr.s6_addr[10]), 0xff, 2);
    362     }
    363     memcpy(&sin6->sin6_addr.s6_addr[12], &sin->sin_addr.s_addr, 4);
    364     return reinterpret_cast<const sockaddr*>(sin6_ss);
    365 }
    366 
    367 /**
    368  * Converts an InetAddress object and port number to a native address structure.
    369  * Throws a NullPointerException or a SocketException in case of
    370  * error.
    371  */
    372 static bool byteArrayToSocketAddress(JNIEnv *env,
    373         jbyteArray addressBytes, int port, sockaddr_storage *sockaddress) {
    374     if (addressBytes == NULL) {
    375         jniThrowNullPointerException(env, NULL);
    376         return false;
    377     }
    378 
    379     // Convert the IP address bytes to the proper IP address type.
    380     size_t addressLength = env->GetArrayLength(addressBytes);
    381     memset(sockaddress, 0, sizeof(*sockaddress));
    382     if (addressLength == 4) {
    383         // IPv4 address.
    384         sockaddr_in *sin = reinterpret_cast<sockaddr_in*>(sockaddress);
    385         sin->sin_family = AF_INET;
    386         sin->sin_port = htons(port);
    387         jbyte* dst = reinterpret_cast<jbyte*>(&sin->sin_addr.s_addr);
    388         env->GetByteArrayRegion(addressBytes, 0, 4, dst);
    389     } else if (addressLength == 16) {
    390         // IPv6 address.
    391         sockaddr_in6 *sin6 = reinterpret_cast<sockaddr_in6*>(sockaddress);
    392         sin6->sin6_family = AF_INET6;
    393         sin6->sin6_port = htons(port);
    394         jbyte* dst = reinterpret_cast<jbyte*>(&sin6->sin6_addr.s6_addr);
    395         env->GetByteArrayRegion(addressBytes, 0, 16, dst);
    396     } else {
    397         jniThrowBadAddressFamily(env);
    398         return false;
    399     }
    400     return true;
    401 }
    402 
    403 /**
    404  * Converts an InetAddress object and port number to a native address structure.
    405  */
    406 static bool inetAddressToSocketAddress(JNIEnv *env, jobject inetaddress,
    407         int port, sockaddr_storage *sockaddress) {
    408     // Get the byte array that stores the IP address bytes in the InetAddress.
    409     if (inetaddress == NULL) {
    410         jniThrowNullPointerException(env, NULL);
    411         return false;
    412     }
    413     jbyteArray addressBytes =
    414         reinterpret_cast<jbyteArray>(env->GetObjectField(inetaddress,
    415             gCachedFields.iaddr_ipaddress));
    416 
    417     return byteArrayToSocketAddress(env, addressBytes, port, sockaddress);
    418 }
    419 
    420 /**
    421  * Convert a Java byte array representing an IP address to a Java string.
    422  *
    423  * @param addressByteArray the byte array to convert.
    424  *
    425  * @return a string with the textual representation of the address.
    426  */
    427 static jstring osNetworkSystem_byteArrayToIpString(JNIEnv* env, jclass,
    428         jbyteArray byteArray) {
    429     if (byteArray == NULL) {
    430         jniThrowNullPointerException(env, NULL);
    431         return NULL;
    432     }
    433     sockaddr_storage ss;
    434     if (!byteArrayToSocketAddress(env, byteArray, 0, &ss)) {
    435         return NULL;
    436     }
    437     // TODO: getnameinfo seems to want its length parameter to be exactly
    438     // sizeof(sockaddr_in) for an IPv4 address and sizeof (sockaddr_in6) for an
    439     // IPv6 address. Fix getnameinfo so it accepts sizeof(sockaddr_storage), and
    440     // then remove this hack.
    441     int sa_size;
    442     if (ss.ss_family == AF_INET) {
    443         sa_size = sizeof(sockaddr_in);
    444     } else if (ss.ss_family == AF_INET6) {
    445         sa_size = sizeof(sockaddr_in6);
    446     } else {
    447         jniThrowBadAddressFamily(env);
    448         return NULL;
    449     }
    450     char ipString[INET6_ADDRSTRLEN];
    451     int rc = getnameinfo(reinterpret_cast<sockaddr*>(&ss), sa_size,
    452             ipString, sizeof(ipString), NULL, 0, NI_NUMERICHOST);
    453     if (rc != 0) {
    454         jniThrowException(env, "java/net/UnknownHostException", gai_strerror(rc));
    455         return NULL;
    456     }
    457     return env->NewStringUTF(ipString);
    458 }
    459 
    460 /**
    461  * Convert a Java string representing an IP address to a Java byte array.
    462  * The formats accepted are:
    463  * - IPv4:
    464  *   - 1.2.3.4
    465  *   - 1.2.4
    466  *   - 1.4
    467  *   - 4
    468  * - IPv6
    469  *   - Compressed form (2001:db8::1)
    470  *   - Uncompressed form (2001:db8:0:0:0:0:0:1)
    471  *   - IPv4-compatible (::192.0.2.0)
    472  *   - With an embedded IPv4 address (2001:db8::192.0.2.0).
    473  * IPv6 addresses may appear in square brackets.
    474  *
    475  * @param addressByteArray the byte array to convert.
    476  *
    477  * @return a string with the textual representation of the address.
    478  *
    479  * @throws UnknownHostException the IP address was invalid.
    480  */
    481 static jbyteArray osNetworkSystem_ipStringToByteArray(JNIEnv* env, jclass,
    482         jstring javaString) {
    483     if (javaString == NULL) {
    484         jniThrowNullPointerException(env, NULL);
    485         return NULL;
    486     }
    487 
    488     // Convert the String to UTF bytes.
    489     size_t byteCount = env->GetStringUTFLength(javaString);
    490     LocalArray<INET6_ADDRSTRLEN> bytes(byteCount + 1);
    491     char* ipString = &bytes[0];
    492     env->GetStringUTFRegion(javaString, 0, env->GetStringLength(javaString), ipString);
    493 
    494     // Accept IPv6 addresses (only) in square brackets for compatibility.
    495     if (ipString[0] == '[' && ipString[byteCount - 1] == ']' &&
    496             strchr(ipString, ':') != NULL) {
    497         memmove(ipString, ipString + 1, byteCount - 2);
    498         ipString[byteCount - 2] = '\0';
    499     }
    500 
    501     jbyteArray result = NULL;
    502     addrinfo hints;
    503     memset(&hints, 0, sizeof(hints));
    504     hints.ai_flags = AI_NUMERICHOST;
    505 
    506     sockaddr_storage ss;
    507     memset(&ss, 0, sizeof(ss));
    508 
    509     addrinfo* res = NULL;
    510     int ret = getaddrinfo(ipString, NULL, &hints, &res);
    511     if (ret == 0 && res) {
    512         // Convert IPv4-mapped addresses to IPv4 addresses.
    513         // The RI states "Java will never return an IPv4-mapped address".
    514         sockaddr_in6* sin6 = reinterpret_cast<sockaddr_in6*>(res->ai_addr);
    515         if (res->ai_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
    516             sockaddr_in* sin = reinterpret_cast<sockaddr_in*>(&ss);
    517             sin->sin_family = AF_INET;
    518             sin->sin_port = sin6->sin6_port;
    519             memcpy(&sin->sin_addr.s_addr, &sin6->sin6_addr.s6_addr[12], 4);
    520             result = socketAddressToByteArray(env, &ss);
    521         } else {
    522             result = socketAddressToByteArray(env, reinterpret_cast<sockaddr_storage*>(res->ai_addr));
    523         }
    524     } else {
    525         // For backwards compatibility, deal with address formats that
    526         // getaddrinfo does not support. For example, 1.2.3, 1.3, and even 3 are
    527         // valid IPv4 addresses according to the Java API. If getaddrinfo fails,
    528         // try to use inet_aton.
    529         sockaddr_in* sin = reinterpret_cast<sockaddr_in*>(&ss);
    530         if (inet_aton(ipString, &sin->sin_addr)) {
    531             sin->sin_family = AF_INET;
    532             sin->sin_port = 0;
    533             result = socketAddressToByteArray(env, &ss);
    534         }
    535     }
    536 
    537     if (res) {
    538         freeaddrinfo(res);
    539     }
    540 
    541     if (! result) {
    542         env->ExceptionClear();
    543         jniThrowException(env, "java/net/UnknownHostException",
    544                 gai_strerror(ret));
    545     }
    546 
    547     return result;
    548 }
    549 
    550 /**
    551  * Answer a new java.lang.Boolean object.
    552  *
    553  * @param env   pointer to the JNI library
    554  * @param anInt the Boolean constructor argument
    555  *
    556  * @return  the new Boolean
    557  */
    558 static jobject newJavaLangBoolean(JNIEnv * env, jint anInt) {
    559     jclass tempClass;
    560     jmethodID tempMethod;
    561 
    562     tempClass = gCachedFields.boolean_class;
    563     tempMethod = gCachedFields.boolean_class_init;
    564     return env->NewObject(tempClass, tempMethod, (jboolean) (anInt != 0));
    565 }
    566 
    567 /**
    568  * Answer a new java.lang.Byte object.
    569  *
    570  * @param env   pointer to the JNI library
    571  * @param anInt the Byte constructor argument
    572  *
    573  * @return  the new Byte
    574  */
    575 static jobject newJavaLangByte(JNIEnv * env, jbyte val) {
    576     jclass tempClass;
    577     jmethodID tempMethod;
    578 
    579     tempClass = gCachedFields.byte_class;
    580     tempMethod = gCachedFields.byte_class_init;
    581     return env->NewObject(tempClass, tempMethod, val);
    582 }
    583 
    584 /**
    585  * Answer a new java.lang.Integer object.
    586  *
    587  * @param env   pointer to the JNI library
    588  * @param anInt the Integer constructor argument
    589  *
    590  * @return  the new Integer
    591  */
    592 static jobject newJavaLangInteger(JNIEnv* env, jint anInt) {
    593     return env->NewObject(gCachedFields.integer_class, gCachedFields.integer_class_init, anInt);
    594 }
    595 
    596 // Converts a number of milliseconds to a timeval.
    597 static timeval toTimeval(long ms) {
    598     timeval tv;
    599     tv.tv_sec = ms / 1000;
    600     tv.tv_usec = (ms - tv.tv_sec*1000) * 1000;
    601     return tv;
    602 }
    603 
    604 // Converts a timeval to a number of milliseconds.
    605 static long toMs(const timeval& tv) {
    606     return tv.tv_sec * 1000 + tv.tv_usec / 1000;
    607 }
    608 
    609 /**
    610  * Query OS for timestamp.
    611  * Retrieve the current value of system clock and convert to milliseconds.
    612  *
    613  * @param[in] portLibrary The port library.
    614  *
    615  * @return 0 on failure, time value in milliseconds on success.
    616  * @deprecated Use @ref time_hires_clock and @ref time_hires_delta
    617  *
    618  * technically, this should return I_64 since both timeval.tv_sec and
    619  * timeval.tv_usec are long
    620  */
    621 
    622 static int time_msec_clock() {
    623     timeval tp;
    624     struct timezone tzp;
    625     gettimeofday(&tp, &tzp);
    626     return toMs(tp);
    627 }
    628 
    629 /**
    630  * Answer the errorString corresponding to the errorNumber, if available.
    631  * This function will answer a default error string, if the errorNumber is not
    632  * recognized.
    633  *
    634  * This function will have to be reworked to handle internationalization
    635  * properly, removing the explicit strings.
    636  *
    637  * @param anErrorNum    the error code to resolve to a human readable string
    638  *
    639  * @return  a human readable error string
    640  */
    641 
    642 static const char * netLookupErrorString(int anErrorNum) {
    643     switch (anErrorNum) {
    644         case SOCKERR_NOTINITIALIZED:
    645             return "Socket library uninitialized";
    646         case SOCKERR_BADAF:
    647             return "Bad address family";
    648         case SOCKERR_BADPROTO:
    649             return "Bad protocol";
    650         case SOCKERR_BADTYPE:
    651             return "Bad type";
    652         case SOCKERR_SYSTEMBUSY:
    653             return "System busy handling requests";
    654         case SOCKERR_SYSTEMFULL:
    655             return "Too many sockets allocated";
    656         case SOCKERR_NOTCONNECTED:
    657             return "Socket is not connected";
    658         case SOCKERR_INTERRUPTED:
    659             return "The system call was cancelled";
    660         case SOCKERR_TIMEOUT:
    661             return "The operation timed out";
    662         case SOCKERR_CONNRESET:
    663             return "The connection was reset";
    664         case SOCKERR_WOULDBLOCK:
    665             return "The nonblocking operation would block";
    666         case SOCKERR_ADDRNOTAVAIL:
    667             return "The address is not available";
    668         case SOCKERR_ADDRINUSE:
    669             return "The address is already in use";
    670         case SOCKERR_NOTBOUND:
    671             return "The socket is not bound";
    672         case SOCKERR_INVALIDTIMEOUT:
    673             return "The specified timeout is invalid";
    674         case SOCKERR_FDSETFULL:
    675             return "Unable to create an FDSET";
    676         case SOCKERR_TIMEVALFULL:
    677             return "Unable to create a TIMEVAL";
    678         case SOCKERR_REMSOCKSHUTDOWN:
    679             return "The remote socket has shutdown gracefully";
    680         case SOCKERR_NOTLISTENING:
    681             return "Listen() was not invoked prior to accept()";
    682         case SOCKERR_NOTSTREAMSOCK:
    683             return "The socket does not support connection-oriented service";
    684         case SOCKERR_ALREADYBOUND:
    685             return "The socket is already bound to an address";
    686         case SOCKERR_NBWITHLINGER:
    687             return "The socket is marked non-blocking & SO_LINGER is non-zero";
    688         case SOCKERR_ISCONNECTED:
    689             return "The socket is already connected";
    690         case SOCKERR_NOBUFFERS:
    691             return "No buffer space is available";
    692         case SOCKERR_HOSTNOTFOUND:
    693             return "Authoritative Answer Host not found";
    694         case SOCKERR_NODATA:
    695             return "Valid name, no data record of requested type";
    696         case SOCKERR_BOUNDORCONN:
    697             return "The socket has not been bound or is already connected";
    698         case SOCKERR_OPNOTSUPP:
    699             return "The socket does not support the operation";
    700         case SOCKERR_OPTUNSUPP:
    701             return "The socket option is not supported";
    702         case SOCKERR_OPTARGSINVALID:
    703             return "The socket option arguments are invalid";
    704         case SOCKERR_SOCKLEVELINVALID:
    705             return "The socket level is invalid";
    706         case SOCKERR_TIMEOUTFAILURE:
    707             return "The timeout operation failed";
    708         case SOCKERR_SOCKADDRALLOCFAIL:
    709             return "Failed to allocate address structure";
    710         case SOCKERR_FDSET_SIZEBAD:
    711             return "The calculated maximum size of the file descriptor set is bad";
    712         case SOCKERR_UNKNOWNFLAG:
    713             return "The flag is unknown";
    714         case SOCKERR_MSGSIZE:
    715             return "The datagram was too big to fit the specified buffer, so truncated";
    716         case SOCKERR_NORECOVERY:
    717             return "The operation failed with no recovery possible";
    718         case SOCKERR_ARGSINVALID:
    719             return "The arguments are invalid";
    720         case SOCKERR_BADDESC:
    721             return "The socket argument is not a valid file descriptor";
    722         case SOCKERR_NOTSOCK:
    723             return "The socket argument is not a socket";
    724         case SOCKERR_HOSTENTALLOCFAIL:
    725             return "Unable to allocate the hostent structure";
    726         case SOCKERR_TIMEVALALLOCFAIL:
    727             return "Unable to allocate the timeval structure";
    728         case SOCKERR_LINGERALLOCFAIL:
    729             return "Unable to allocate the linger structure";
    730         case SOCKERR_IPMREQALLOCFAIL:
    731             return "Unable to allocate the ipmreq structure";
    732         case SOCKERR_FDSETALLOCFAIL:
    733             return "Unable to allocate the fdset structure";
    734         case SOCKERR_OPFAILED:
    735             return "Operation failed";
    736         case SOCKERR_CONNECTION_REFUSED:
    737             return "Connection refused";
    738         case SOCKERR_ENETUNREACH:
    739             return "Network unreachable";
    740         case SOCKERR_EHOSTUNREACH:
    741             return "No route to host";
    742         case SOCKERR_EPIPE:
    743             return "Broken pipe";
    744         case SOCKERR_EACCES:
    745             return "Permission denied (maybe missing INTERNET permission)";
    746 
    747         default:
    748             LOGE("unknown socket error %d", anErrorNum);
    749             return "unknown error";
    750     }
    751 }
    752 
    753 static int convertError(int errorCode) {
    754     switch (errorCode) {
    755         case EBADF:
    756             return SOCKERR_BADDESC;
    757         case ENOBUFS:
    758             return SOCKERR_NOBUFFERS;
    759         case EOPNOTSUPP:
    760             return SOCKERR_OPNOTSUPP;
    761         case ENOPROTOOPT:
    762             return SOCKERR_OPTUNSUPP;
    763         case EINVAL:
    764             return SOCKERR_SOCKLEVELINVALID;
    765         case ENOTSOCK:
    766             return SOCKERR_NOTSOCK;
    767         case EINTR:
    768             return SOCKERR_INTERRUPTED;
    769         case ENOTCONN:
    770             return SOCKERR_NOTCONNECTED;
    771         case EAFNOSUPPORT:
    772             return SOCKERR_BADAF;
    773             /* note: CONNRESET not included because it has the same
    774              * value as ECONNRESET and they both map to SOCKERR_CONNRESET */
    775         case ECONNRESET:
    776             return SOCKERR_CONNRESET;
    777         case EAGAIN:
    778             return SOCKERR_WOULDBLOCK;
    779         case EPROTONOSUPPORT:
    780             return SOCKERR_BADPROTO;
    781         case EFAULT:
    782             return SOCKERR_ARGSINVALID;
    783         case ETIMEDOUT:
    784             return SOCKERR_TIMEOUT;
    785         case ECONNREFUSED:
    786             return SOCKERR_CONNECTION_REFUSED;
    787         case ENETUNREACH:
    788             return SOCKERR_ENETUNREACH;
    789         case EACCES:
    790             return SOCKERR_EACCES;
    791         case EPIPE:
    792             return SOCKERR_EPIPE;
    793         case EHOSTUNREACH:
    794             return SOCKERR_EHOSTUNREACH;
    795         case EADDRINUSE:
    796             return SOCKERR_ADDRINUSE;
    797         case EADDRNOTAVAIL:
    798             return SOCKERR_ADDRNOTAVAIL;
    799         case EMSGSIZE:
    800             return SOCKERR_MSGSIZE;
    801         default:
    802             LOGE("unclassified errno %d (%s)", errorCode, strerror(errorCode));
    803             return SOCKERR_OPFAILED;
    804     }
    805 }
    806 
    807 static int selectWait(int fd, int uSecTime) {
    808     timeval tv;
    809     timeval* tvp;
    810     if (uSecTime >= 0) {
    811         /* Use a timeout if uSecTime >= 0 */
    812         memset(&tv, 0, sizeof(tv));
    813         tv.tv_usec = uSecTime;
    814         tvp = &tv;
    815     } else {
    816         /* Infinite timeout if uSecTime < 0 */
    817         tvp = NULL;
    818     }
    819 
    820     fd_set readFds;
    821     FD_ZERO(&readFds);
    822     FD_SET(fd, &readFds);
    823     int result = select(fd + 1, &readFds, NULL, NULL, tvp);
    824     if (result == -1) {
    825         if (errno == EINTR) {
    826             result = SOCKERR_INTERRUPTED;
    827         } else {
    828             result = SOCKERR_OPFAILED;
    829         }
    830     } else if (result == 0) {
    831         result = SOCKERR_TIMEOUT;
    832     }
    833     return result;
    834 }
    835 
    836 // Returns 0 on success, not obviously meaningful negative values on error.
    837 static int pollSelectWait(JNIEnv *env, jobject fileDescriptor, int timeout) {
    838     /* now try reading the socket for the timeout.
    839      * if timeout is 0 try forever until the sockets gets ready or until an
    840      * exception occurs.
    841      */
    842     int pollTimeoutUSec = 100000, pollMsec = 100;
    843     int finishTime = 0;
    844     int timeLeft = timeout;
    845     int hasTimeout = timeout > 0 ? 1 : 0;
    846     int result = 0;
    847     int handle;
    848 
    849     if (hasTimeout) {
    850         finishTime = time_msec_clock() + timeout;
    851     }
    852 
    853     int poll = 1;
    854 
    855     while (poll) { /* begin polling loop */
    856 
    857         /*
    858          * Fetch the handle every time in case the socket is closed.
    859          */
    860         handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
    861         if (handle == -1) {
    862             jniThrowSocketException(env, EINTR);
    863             return -1;
    864         }
    865 
    866         if (hasTimeout) {
    867 
    868             if (timeLeft - 10 < pollMsec) {
    869                 pollTimeoutUSec = timeLeft <= 0 ? 0 : (timeLeft * 1000);
    870             }
    871 
    872             result = selectWait(handle, pollTimeoutUSec);
    873 
    874             /*
    875              * because we are polling at a time smaller than timeout
    876              * (presumably) lets treat an interrupt and timeout the same - go
    877              * see if we're done timewise, and then just try again if not.
    878              */
    879             if (SOCKERR_TIMEOUT == result ||
    880                 SOCKERR_INTERRUPTED == result) {
    881 
    882                 timeLeft = finishTime - time_msec_clock();
    883 
    884                 if (timeLeft <= 0) {
    885                     /*
    886                      * Always throw the "timeout" message because that is
    887                      * effectively what has happened, even if we happen to
    888                      * have been interrupted.
    889                      */
    890                     jniThrowSocketTimeoutException(env, ETIMEDOUT);
    891                 } else {
    892                     continue; // try again
    893                 }
    894 
    895             } else if (0 > result) {
    896                 throwSocketException(env, result);
    897             }
    898             poll = 0;
    899 
    900         } else { /* polling with no timeout (why would you do this?)*/
    901 
    902             result = selectWait(handle, pollTimeoutUSec);
    903 
    904             /*
    905              *  if interrupted (or a timeout) just retry
    906              */
    907             if (SOCKERR_TIMEOUT == result ||
    908                SOCKERR_INTERRUPTED == result) {
    909 
    910                 continue; // try again
    911             } else if (0 > result) {
    912                 throwSocketException(env, result);
    913             }
    914             poll = 0;
    915         }
    916     } /* end polling loop */
    917 
    918     return result;
    919 }
    920 
    921 /**
    922  * Wrapper for connect() that converts IPv4 addresses to IPv4-mapped IPv6
    923  * addresses if necessary.
    924  *
    925  * @param socket the file descriptor of the socket to connect
    926  * @param socketAddress the address to connect to
    927  */
    928 static int doConnect(int fd, const sockaddr_storage* socketAddress) {
    929     sockaddr_storage tmp;
    930     const sockaddr* realAddress = convertIpv4ToMapped(fd, socketAddress, &tmp, true);
    931     return TEMP_FAILURE_RETRY(connect(fd, realAddress, sizeof(sockaddr_storage)));
    932 }
    933 
    934 /**
    935  * Establish a connection to a peer with a timeout.  This function is called
    936  * repeatedly in order to carry out the connect and to allow other tasks to
    937  * proceed on certain platforms. The caller must first call with
    938  * step = SOCKET_STEP_START, if the result is SOCKERR_NOTCONNECTED it will then
    939  * call it with step = CHECK until either another error or 0 is returned to
    940  * indicate the connect is complete.  Each time the function should sleep for no
    941  * more than timeout milliseconds.  If the connect succeeds or an error occurs,
    942  * the caller must always end the process by calling the function with
    943  * step = SOCKET_STEP_DONE
    944  *
    945  * @param[in] portLibrary The port library.
    946  * @param[in] sock pointer to the unconnected local socket.
    947  * @param[in] addr pointer to the sockaddr, specifying remote host/port.
    948  * @param[in] timeout the timeout in milliseconds. If timeout is negative,
    949  *         perform a block operation.
    950  * @param[in,out] pointer to context pointer. Filled in on first call and then
    951  *         to be passed into each subsequent call.
    952  *
    953  * @return 0, if no errors occurred, otherwise the (negative) error code.
    954  */
    955 // TODO: do we really want to pass 'addr' by value?
    956 static int sockConnectWithTimeout(int handle, sockaddr_storage addr,
    957                                   int timeout, unsigned int step, jbyte *ctxt) {
    958     int rc = 0;
    959     int errorVal;
    960     socklen_t errorValLen = sizeof(int);
    961     selectFDSet* context = reinterpret_cast<selectFDSet*>(ctxt);
    962 
    963     if (SOCKET_STEP_START == step) {
    964         context->sock = handle;
    965         context->nfds = handle + 1;
    966 
    967         /* set the socket to non-blocking */
    968         int block = JNI_TRUE;
    969         rc = ioctl(handle, FIONBIO, &block);
    970         if (rc != 0) {
    971             return convertError(rc);
    972         }
    973 
    974         // LOGD("+connect to address 0x%08x (via normal) on handle %d",
    975         //         addr.sin_addr.s_addr, handle);
    976         rc = doConnect(handle, &addr);
    977         // LOGD("-connect to address 0x%08x (via normal) returned %d",
    978         //         addr.sin_addr.s_addr, (int) rc);
    979 
    980         if (rc == -1) {
    981             rc = errno;
    982             switch (rc) {
    983                 case EINTR:
    984                     return SOCKERR_ALREADYBOUND;
    985                 case EAGAIN:
    986                 case EINPROGRESS:
    987                     return SOCKERR_NOTCONNECTED;
    988                 default:
    989                     return convertError(rc);
    990             }
    991         }
    992 
    993         /* we connected right off the bat so just return */
    994         return rc;
    995 
    996     } else if (SOCKET_STEP_CHECK == step) {
    997         /* now check if we have connected yet */
    998 
    999         /*
   1000          * set the timeout value to be used. Because on some unix platforms we
   1001          * don't get notified when a socket is closed we only sleep for 100ms
   1002          * at a time
   1003          *
   1004          * TODO: is this relevant for Android?
   1005          */
   1006         if (timeout > 100) {
   1007             timeout = 100;
   1008         }
   1009         timeval passedTimeout(toTimeval(timeout));
   1010 
   1011         /* initialize the FD sets for the select */
   1012         FD_ZERO(&(context->exceptionSet));
   1013         FD_ZERO(&(context->writeSet));
   1014         FD_ZERO(&(context->readSet));
   1015         FD_SET(context->sock, &(context->writeSet));
   1016         FD_SET(context->sock, &(context->readSet));
   1017         FD_SET(context->sock, &(context->exceptionSet));
   1018 
   1019         rc = select(context->nfds,
   1020                    &(context->readSet),
   1021                    &(context->writeSet),
   1022                    &(context->exceptionSet),
   1023                    timeout >= 0 ? &passedTimeout : NULL);
   1024 
   1025         /* if there is at least one descriptor ready to be checked */
   1026         if (0 < rc) {
   1027             /* if the descriptor is in the write set we connected or failed */
   1028             if (FD_ISSET(context->sock, &(context->writeSet))) {
   1029 
   1030                 if (!FD_ISSET(context->sock, &(context->readSet))) {
   1031                     /* ok we have connected ok */
   1032                     return 0;
   1033                 } else {
   1034                     /* ok we have more work to do to figure it out */
   1035                     if (getsockopt(context->sock, SOL_SOCKET, SO_ERROR,
   1036                             &errorVal, &errorValLen) >= 0) {
   1037                         return errorVal ? convertError(errorVal) : 0;
   1038                     } else {
   1039                         return convertError(errno);
   1040                     }
   1041                 }
   1042             }
   1043 
   1044             /* if the descriptor is in the exception set the connect failed */
   1045             if (FD_ISSET(context->sock, &(context->exceptionSet))) {
   1046                 if (getsockopt(context->sock, SOL_SOCKET, SO_ERROR, &errorVal,
   1047                         &errorValLen) >= 0) {
   1048                     return errorVal ? convertError(errorVal) : 0;
   1049                 }
   1050                 rc = errno;
   1051                 return convertError(rc);
   1052             }
   1053 
   1054         } else if (rc < 0) {
   1055             /* something went wrong with the select call */
   1056             rc = errno;
   1057 
   1058             /* if it was EINTR we can just try again. Return not connected */
   1059             if (EINTR == rc) {
   1060                 return SOCKERR_NOTCONNECTED;
   1061             }
   1062 
   1063             /* some other error occured so look it up and return */
   1064             return convertError(rc);
   1065         }
   1066 
   1067         /*
   1068          * if we get here the timeout expired or the connect had not yet
   1069          * completed just indicate that the connect is not yet complete
   1070          */
   1071         return SOCKERR_NOTCONNECTED;
   1072     } else if (SOCKET_STEP_DONE == step) {
   1073         /* we are done the connect or an error occured so clean up  */
   1074         if (handle != -1) {
   1075             int block = JNI_FALSE;
   1076             ioctl(handle, FIONBIO, &block);
   1077         }
   1078         return 0;
   1079     }
   1080     return SOCKERR_ARGSINVALID;
   1081 }
   1082 
   1083 
   1084 #if LOG_SOCKOPT
   1085 /**
   1086  * Helper method to log getsockopt/getsockopt calls.
   1087  */
   1088 static const char *sockoptLevelToString(int level) {
   1089     switch(level) {
   1090         case SOL_SOCKET:
   1091             return "SOL_SOCKET";
   1092         case IPPROTO_IP:
   1093             return "IPPROTO_IP";
   1094         case IPPROTO_IPV6:
   1095             return "IPPROTO_IPV6";
   1096         default:
   1097             return "SOL_???";
   1098     }
   1099 }
   1100 #endif
   1101 
   1102 /**
   1103  * Helper method to get or set socket options
   1104  *
   1105  * @param action SOCKOPT_GET to get an option, SOCKOPT_SET to set it
   1106  * @param socket the file descriptor of the socket to use
   1107  * @param ipv4Option the option value to use for an IPv4 socket
   1108  * @param ipv6Option the option value to use for an IPv6 socket
   1109  * @param optionValue the value of the socket option to get or set
   1110  * @param optionLength the length of the socket option to get or set
   1111  *
   1112  * @return the value of the socket call, or -1 on failure inside this function
   1113  *
   1114  * @note on internal failure, the errno variable will be set appropriately
   1115  */
   1116 static int getOrSetSocketOption(int action, int socket, int ipv4Option,
   1117         int ipv6Option, void *optionValue, socklen_t *optionLength) {
   1118     int option;
   1119     int protocol;
   1120     int family = getSocketAddressFamily(socket);
   1121     switch (family) {
   1122         case AF_INET:
   1123             option = ipv4Option;
   1124             protocol = IPPROTO_IP;
   1125             break;
   1126         case AF_INET6:
   1127             option = ipv6Option;
   1128             protocol = IPPROTO_IPV6;
   1129             break;
   1130         default:
   1131             // TODO(enh): throw Java exceptions from this method instead of just
   1132             // returning error codes.
   1133             errno = EAFNOSUPPORT;
   1134             return -1;
   1135     }
   1136 
   1137     int ret;
   1138     if (action == SOCKOPT_GET) {
   1139         ret = getsockopt(socket, protocol, option, optionValue, optionLength);
   1140 #if LOG_SOCKOPT
   1141         LOGI("getsockopt(%d, %s, %d, %p, [%d]) = %d %s",
   1142                 socket, sockoptLevelToString(protocol), option, optionValue,
   1143                 *optionLength, ret, (ret == -1) ? strerror(errno) : "");
   1144 #endif
   1145     } else if (action == SOCKOPT_SET) {
   1146         ret = setsockopt(socket, protocol, option, optionValue, *optionLength);
   1147 #if LOG_SOCKOPT
   1148         LOGI("setsockopt(%d, %s, %d, [%d], %d) = %d %s",
   1149                 socket, sockoptLevelToString(protocol), option,
   1150                 // Note: this only works for integer options.
   1151                 // TODO: Use dvmPrintHexDump() to log non-integer options.
   1152                 *(int *)optionValue, *optionLength, ret,
   1153                 (ret == -1) ? strerror(errno) : "");
   1154 #endif
   1155     } else {
   1156         errno = EINVAL;
   1157         ret = -1;
   1158     }
   1159     return ret;
   1160 }
   1161 
   1162 #ifdef ENABLE_MULTICAST
   1163 /*
   1164  * Find the interface index that was set for this socket by the IP_MULTICAST_IF
   1165  * or IPV6_MULTICAST_IF socket option.
   1166  *
   1167  * @param socket the socket to examine
   1168  *
   1169  * @return the interface index, or -1 on failure
   1170  *
   1171  * @note on internal failure, the errno variable will be set appropriately
   1172  */
   1173 static int interfaceIndexFromMulticastSocket(int socket) {
   1174     int family = getSocketAddressFamily(socket);
   1175     int interfaceIndex;
   1176     int result;
   1177     if (family == AF_INET) {
   1178         // IP_MULTICAST_IF returns a pointer to a struct ip_mreqn.
   1179         struct ip_mreqn tempRequest;
   1180         socklen_t requestLength = sizeof(tempRequest);
   1181         result = getsockopt(socket, IPPROTO_IP, IP_MULTICAST_IF, &tempRequest,
   1182             &requestLength);
   1183         interfaceIndex = tempRequest.imr_ifindex;
   1184     } else if (family == AF_INET6) {
   1185         // IPV6_MULTICAST_IF returns a pointer to an integer.
   1186         socklen_t requestLength = sizeof(interfaceIndex);
   1187         result = getsockopt(socket, IPPROTO_IPV6, IPV6_MULTICAST_IF,
   1188                 &interfaceIndex, &requestLength);
   1189     } else {
   1190         errno = EAFNOSUPPORT;
   1191         return -1;
   1192     }
   1193 
   1194     if (result == 0)
   1195         return interfaceIndex;
   1196     else
   1197         return -1;
   1198 }
   1199 
   1200 /**
   1201  * Join/Leave the nominated multicast group on the specified socket.
   1202  * Implemented by setting the multicast 'add membership'/'drop membership'
   1203  * option at the HY_IPPROTO_IP level on the socket.
   1204  *
   1205  * Implementation note for multicast sockets in general:
   1206  *
   1207  * - This code is untested, because at the time of this writing multicast can't
   1208  * be properly tested on Android due to GSM routing restrictions. So it might
   1209  * or might not work.
   1210  *
   1211  * - The REUSEPORT socket option that Harmony employs is not supported on Linux
   1212  * and thus also not supported on Android. It's is not needed for multicast
   1213  * to work anyway (REUSEADDR should suffice).
   1214  *
   1215  * @param env pointer to the JNI library.
   1216  * @param socketP pointer to the hysocket to join/leave on.
   1217  * @param optVal pointer to the InetAddress, the multicast group to join/drop.
   1218  *
   1219  * @exception SocketException if an error occurs during the call
   1220  */
   1221 static void mcastAddDropMembership(JNIEnv *env, int handle, jobject optVal,
   1222         int ignoreIF, int setSockOptVal) {
   1223     struct sockaddr_storage sockaddrP;
   1224     int result;
   1225     // By default, let the system decide which interface to use.
   1226     int interfaceIndex = 0;
   1227 
   1228     /*
   1229      * Check whether we are getting an InetAddress or an Generic IPMreq. For now
   1230      * we support both so that we will not break the tests. If an InetAddress
   1231      * is passed in, only support IPv4 as obtaining an interface from an
   1232      * InetAddress is complex and should be done by the Java caller.
   1233      */
   1234     if (env->IsInstanceOf (optVal, gCachedFields.iaddr_class)) {
   1235         /*
   1236          * optVal is an InetAddress. Construct a multicast request structure
   1237          * from this address. Support IPv4 only.
   1238          */
   1239         struct ip_mreqn multicastRequest;
   1240         socklen_t length = sizeof(multicastRequest);
   1241         memset(&multicastRequest, 0, length);
   1242 
   1243         // If ignoreIF is false, determine the index of the interface to use.
   1244         if (!ignoreIF) {
   1245             interfaceIndex = interfaceIndexFromMulticastSocket(handle);
   1246             multicastRequest.imr_ifindex = interfaceIndex;
   1247             if (interfaceIndex == -1) {
   1248                 jniThrowSocketException(env, errno);
   1249                 return;
   1250             }
   1251         }
   1252 
   1253         // Convert the inetAddress to an IPv4 address structure.
   1254         if (!inetAddressToSocketAddress(env, optVal, 0, &sockaddrP)) {
   1255             return;
   1256         }
   1257         if (sockaddrP.ss_family != AF_INET) {
   1258             jniThrowSocketException(env, EAFNOSUPPORT);
   1259             return;
   1260         }
   1261         struct sockaddr_in *sin = (struct sockaddr_in *) &sockaddrP;
   1262         multicastRequest.imr_multiaddr = sin->sin_addr;
   1263 
   1264         result = setsockopt(handle, IPPROTO_IP, setSockOptVal,
   1265                             &multicastRequest, length);
   1266         if (0 != result) {
   1267             jniThrowSocketException(env, errno);
   1268             return;
   1269         }
   1270     } else {
   1271         /*
   1272          * optVal is a GenericIPMreq object. Extract the relevant fields from
   1273          * it and construct a multicast request structure from these. Support
   1274          * both IPv4 and IPv6.
   1275          */
   1276         jclass cls;
   1277         jfieldID multiaddrID;
   1278         jfieldID interfaceIdxID;
   1279         jobject multiaddr;
   1280 
   1281         // Get the multicast address to join or leave.
   1282         cls = env->GetObjectClass(optVal);
   1283         multiaddrID = env->GetFieldID(cls, "multiaddr", "Ljava/net/InetAddress;");
   1284         multiaddr = env->GetObjectField(optVal, multiaddrID);
   1285 
   1286         // Get the interface index to use.
   1287         if (! ignoreIF) {
   1288             interfaceIdxID = env->GetFieldID(cls, "interfaceIdx", "I");
   1289             interfaceIndex = env->GetIntField(optVal, interfaceIdxID);
   1290         }
   1291         LOGI("mcastAddDropMembership interfaceIndex=%i", interfaceIndex);
   1292 
   1293         if (!inetAddressToSocketAddress(env, multiaddr, 0, &sockaddrP)) {
   1294             return;
   1295         }
   1296 
   1297         int family = getSocketAddressFamily(handle);
   1298 
   1299         // Handle IPv4 multicast on an IPv6 socket.
   1300         if (family == AF_INET6 && sockaddrP.ss_family == AF_INET) {
   1301             family = AF_INET;
   1302         }
   1303 
   1304         struct ip_mreqn ipv4Request;
   1305         struct ipv6_mreq ipv6Request;
   1306         void *multicastRequest;
   1307         socklen_t requestLength;
   1308         int level;
   1309         switch (family) {
   1310             case AF_INET:
   1311                 requestLength = sizeof(ipv4Request);
   1312                 memset(&ipv4Request, 0, requestLength);
   1313                 ipv4Request.imr_multiaddr =
   1314                         ((struct sockaddr_in *) &sockaddrP)->sin_addr;
   1315                 ipv4Request.imr_ifindex = interfaceIndex;
   1316                 multicastRequest = &ipv4Request;
   1317                 level = IPPROTO_IP;
   1318                 break;
   1319             case AF_INET6:
   1320                 // setSockOptVal is passed in by the caller and may be IPv4-only
   1321                 if (setSockOptVal == IP_ADD_MEMBERSHIP) {
   1322                     setSockOptVal = IPV6_ADD_MEMBERSHIP;
   1323                 }
   1324                 if (setSockOptVal == IP_DROP_MEMBERSHIP) {
   1325                     setSockOptVal == IPV6_DROP_MEMBERSHIP;
   1326                 }
   1327                 requestLength = sizeof(ipv6Request);
   1328                 memset(&ipv6Request, 0, requestLength);
   1329                 ipv6Request.ipv6mr_multiaddr =
   1330                         ((struct sockaddr_in6 *) &sockaddrP)->sin6_addr;
   1331                 ipv6Request.ipv6mr_interface = interfaceIndex;
   1332                 multicastRequest = &ipv6Request;
   1333                 level = IPPROTO_IPV6;
   1334                 break;
   1335            default:
   1336                 jniThrowSocketException(env, EAFNOSUPPORT);
   1337                 return;
   1338         }
   1339 
   1340         /* join/drop the multicast address */
   1341         result = setsockopt(handle, level, setSockOptVal, multicastRequest,
   1342                             requestLength);
   1343         if (0 != result) {
   1344             jniThrowSocketException(env, errno);
   1345             return;
   1346         }
   1347     }
   1348 }
   1349 #endif // def ENABLE_MULTICAST
   1350 
   1351 static bool initCachedFields(JNIEnv* env) {
   1352     memset(&gCachedFields, 0, sizeof(gCachedFields));
   1353     struct CachedFields *c = &gCachedFields;
   1354 
   1355     struct classInfo {
   1356         jclass *clazz;
   1357         const char *name;
   1358     } classes[] = {
   1359         {&c->iaddr_class, "java/net/InetAddress"},
   1360         {&c->i4addr_class, "java/net/Inet4Address"},
   1361         {&c->genericipmreq_class, "org/apache/harmony/luni/net/GenericIPMreq"},
   1362         {&c->integer_class, "java/lang/Integer"},
   1363         {&c->boolean_class, "java/lang/Boolean"},
   1364         {&c->byte_class, "java/lang/Byte"},
   1365         {&c->socketimpl_class, "java/net/SocketImpl"},
   1366         {&c->dpack_class, "java/net/DatagramPacket"}
   1367     };
   1368     for (unsigned i = 0; i < sizeof(classes) / sizeof(classes[0]); i++) {
   1369         classInfo c = classes[i];
   1370         jclass tempClass = env->FindClass(c.name);
   1371         if (tempClass == NULL) return false;
   1372         *c.clazz = (jclass) env->NewGlobalRef(tempClass);
   1373     }
   1374 
   1375     struct methodInfo {
   1376         jmethodID *method;
   1377         jclass clazz;
   1378         const char *name;
   1379         const char *signature;
   1380         bool isStatic;
   1381     } methods[] = {
   1382         {&c->i4addr_class_init, c->i4addr_class, "<init>", "([B)V", false},
   1383         {&c->integer_class_init, c->integer_class, "<init>", "(I)V", false},
   1384         {&c->boolean_class_init, c->boolean_class, "<init>", "(Z)V", false},
   1385         {&c->byte_class_init, c->byte_class, "<init>", "(B)V", false},
   1386         {&c->iaddr_getbyaddress, c->iaddr_class, "getByAddress",
   1387                     "([B)Ljava/net/InetAddress;", true}
   1388     };
   1389     for (unsigned i = 0; i < sizeof(methods) / sizeof(methods[0]); i++) {
   1390         methodInfo m = methods[i];
   1391         if (m.isStatic) {
   1392             *m.method = env->GetStaticMethodID(m.clazz, m.name, m.signature);
   1393         } else {
   1394             *m.method = env->GetMethodID(m.clazz, m.name, m.signature);
   1395         }
   1396         if (*m.method == NULL) return false;
   1397     }
   1398 
   1399     struct fieldInfo {
   1400         jfieldID *field;
   1401         jclass clazz;
   1402         const char *name;
   1403         const char *type;
   1404     } fields[] = {
   1405         {&c->iaddr_ipaddress, c->iaddr_class, "ipaddress", "[B"},
   1406         {&c->integer_class_value, c->integer_class, "value", "I"},
   1407         {&c->boolean_class_value, c->boolean_class, "value", "Z"},
   1408         {&c->byte_class_value, c->byte_class, "value", "B"},
   1409         {&c->socketimpl_port, c->socketimpl_class, "port", "I"},
   1410         {&c->socketimpl_address, c->socketimpl_class, "address",
   1411                 "Ljava/net/InetAddress;"},
   1412         {&c->dpack_address, c->dpack_class, "address",
   1413                 "Ljava/net/InetAddress;"},
   1414         {&c->dpack_port, c->dpack_class, "port", "I"},
   1415         {&c->dpack_length, c->dpack_class, "length", "I"}
   1416     };
   1417     for (unsigned i = 0; i < sizeof(fields) / sizeof(fields[0]); i++) {
   1418         fieldInfo f = fields[i];
   1419         *f.field = env->GetFieldID(f.clazz, f.name, f.type);
   1420         if (*f.field == NULL) return false;
   1421     }
   1422     return true;
   1423 }
   1424 
   1425 /**
   1426  * Helper function to create a socket of the specified type and bind it to a
   1427  * Java file descriptor.
   1428  *
   1429  * @param fileDescriptor the file descriptor to bind the socket to
   1430  * @param type the socket type to create, e.g., SOCK_STREAM
   1431  * @throws SocketException an error occurred when creating the socket
   1432  *
   1433  * @return the socket file descriptor. On failure, an exception is thrown and
   1434  *         a negative value is returned.
   1435  *
   1436  */
   1437 static int createSocketFileDescriptor(JNIEnv* env, jobject fileDescriptor,
   1438                                       int type) {
   1439     if (fileDescriptor == NULL) {
   1440         jniThrowNullPointerException(env, NULL);
   1441         errno = EBADF;
   1442         return -1;
   1443     }
   1444 
   1445     int sock;
   1446     sock = socket(PF_INET6, type, 0);
   1447     if (sock < 0 && errno == EAFNOSUPPORT) {
   1448         sock = socket(PF_INET, type, 0);
   1449     }
   1450     if (sock < 0) {
   1451         jniThrowSocketException(env, errno);
   1452         return sock;
   1453     }
   1454     jniSetFileDescriptorOfFD(env, fileDescriptor, sock);
   1455     return sock;
   1456 }
   1457 
   1458 static void osNetworkSystem_createStreamSocketImpl(JNIEnv* env, jclass clazz,
   1459         jobject fileDescriptor, jboolean preferIPv4Stack) {
   1460     // LOGD("ENTER createSocketImpl");
   1461     createSocketFileDescriptor(env, fileDescriptor, SOCK_STREAM);
   1462 }
   1463 
   1464 static void osNetworkSystem_createDatagramSocketImpl(JNIEnv* env, jclass clazz,
   1465         jobject fileDescriptor, jboolean preferIPv4Stack) {
   1466     // LOGD("ENTER createDatagramSocketImpl");
   1467     createSocketFileDescriptor(env, fileDescriptor, SOCK_DGRAM);
   1468 }
   1469 
   1470 static jint osNetworkSystem_readSocketDirectImpl(JNIEnv* env, jclass clazz,
   1471         jobject fileDescriptor, jint address, jint count, jint timeout) {
   1472     // LOGD("ENTER readSocketDirectImpl");
   1473 
   1474     int fd;
   1475     if (!jniGetFd(env, fileDescriptor, fd)) {
   1476         return 0;
   1477     }
   1478 
   1479     if (timeout != 0) {
   1480         int result = selectWait(fd, timeout * 1000);
   1481         if (result < 0) {
   1482             return 0;
   1483         }
   1484     }
   1485 
   1486     jbyte* dst = reinterpret_cast<jbyte*>(static_cast<uintptr_t>(address));
   1487     ssize_t bytesReceived =
   1488             TEMP_FAILURE_RETRY(recv(fd, dst, count, SOCKET_NOFLAGS));
   1489     if (bytesReceived == 0) {
   1490         return -1;
   1491     } else if (bytesReceived == -1) {
   1492         if (errno == EAGAIN || errno == EWOULDBLOCK) {
   1493             // We were asked to read a non-blocking socket with no data
   1494             // available, so report "no bytes read".
   1495             return 0;
   1496         } else {
   1497             jniThrowSocketException(env, errno);
   1498             return 0;
   1499         }
   1500     }
   1501     return bytesReceived;
   1502 }
   1503 
   1504 static jint osNetworkSystem_readSocketImpl(JNIEnv* env, jclass clazz,
   1505         jobject fileDescriptor, jbyteArray byteArray, jint offset, jint count,
   1506         jint timeout) {
   1507     // LOGD("ENTER readSocketImpl");
   1508 
   1509     jbyte* bytes = env->GetByteArrayElements(byteArray, NULL);
   1510     if (bytes == NULL) {
   1511         return -1;
   1512     }
   1513     jint address =
   1514             static_cast<jint>(reinterpret_cast<uintptr_t>(bytes + offset));
   1515     int result = osNetworkSystem_readSocketDirectImpl(env, clazz,
   1516             fileDescriptor, address, count, timeout);
   1517     env->ReleaseByteArrayElements(byteArray, bytes, 0);
   1518     return result;
   1519 }
   1520 
   1521 static jint osNetworkSystem_writeSocketDirectImpl(JNIEnv* env, jclass clazz,
   1522         jobject fileDescriptor, jint address, jint offset, jint count) {
   1523     // LOGD("ENTER writeSocketDirectImpl");
   1524 
   1525     if (count <= 0) {
   1526         return 0;
   1527     }
   1528 
   1529     int fd;
   1530     if (!jniGetFd(env, fileDescriptor, fd)) {
   1531         return 0;
   1532     }
   1533 
   1534     jbyte* message = reinterpret_cast<jbyte*>(static_cast<uintptr_t>(address + offset));
   1535     int bytesSent = send(fd, message, count, SOCKET_NOFLAGS);
   1536     if (bytesSent == -1) {
   1537         if (errno == EAGAIN || errno == EWOULDBLOCK) {
   1538             // We were asked to write to a non-blocking socket, but were told
   1539             // it would block, so report "no bytes written".
   1540             return 0;
   1541         } else {
   1542             jniThrowSocketException(env, errno);
   1543             return 0;
   1544         }
   1545     }
   1546     return bytesSent;
   1547 }
   1548 
   1549 static jint osNetworkSystem_writeSocketImpl(JNIEnv* env, jclass clazz,
   1550         jobject fileDescriptor, jbyteArray byteArray, jint offset, jint count) {
   1551     // LOGD("ENTER writeSocketImpl");
   1552 
   1553     jbyte* bytes = env->GetByteArrayElements(byteArray, NULL);
   1554     if (bytes == NULL) {
   1555         return -1;
   1556     }
   1557     jint address = static_cast<jint>(reinterpret_cast<uintptr_t>(bytes));
   1558     int result = osNetworkSystem_writeSocketDirectImpl(env, clazz,
   1559             fileDescriptor, address, offset, count);
   1560     env->ReleaseByteArrayElements(byteArray, bytes, 0);
   1561     return result;
   1562 }
   1563 
   1564 static void osNetworkSystem_setNonBlockingImpl(JNIEnv* env, jclass clazz,
   1565         jobject fileDescriptor, jboolean nonblocking) {
   1566     // LOGD("ENTER setNonBlockingImpl");
   1567 
   1568     int handle;
   1569     if (!jniGetFd(env, fileDescriptor, handle)) {
   1570         return;
   1571     }
   1572 
   1573     int block = nonblocking;
   1574     int rc = ioctl(handle, FIONBIO, &block);
   1575     if (rc == -1) {
   1576         jniThrowSocketException(env, errno);
   1577     }
   1578 }
   1579 
   1580 static jint osNetworkSystem_connectWithTimeoutSocketImpl(JNIEnv* env,
   1581         jclass clazz, jobject fileDescriptor, jint timeout, jint trafficClass,
   1582         jobject inetAddr, jint port, jint step, jbyteArray passContext) {
   1583     // LOGD("ENTER connectWithTimeoutSocketImpl");
   1584 
   1585     sockaddr_storage address;
   1586     if (!inetAddressToSocketAddress(env, inetAddr, port, &address)) {
   1587         return -1;
   1588     }
   1589 
   1590     int handle;
   1591     if (!jniGetFd(env, fileDescriptor, handle)) {
   1592         return -1;
   1593     }
   1594 
   1595     jbyte* context = env->GetByteArrayElements(passContext, NULL);
   1596     int result = 0;
   1597     switch (step) {
   1598     case SOCKET_CONNECT_STEP_START:
   1599         result = sockConnectWithTimeout(handle, address, 0,
   1600                 SOCKET_STEP_START, context);
   1601         break;
   1602     case SOCKET_CONNECT_STEP_CHECK:
   1603         result = sockConnectWithTimeout(handle, address, timeout,
   1604                 SOCKET_STEP_CHECK, context);
   1605         break;
   1606     default:
   1607         assert(false);
   1608     }
   1609     env->ReleaseByteArrayElements(passContext, context, 0);
   1610 
   1611     if (result == 0) {
   1612         /* connected , so stop here */
   1613         sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_DONE, NULL);
   1614     } else if (result != SOCKERR_NOTCONNECTED) {
   1615         /* can not connect... */
   1616         sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_DONE, NULL);
   1617         if (result == SOCKERR_EACCES) {
   1618             jniThrowException(env, "java/lang/SecurityException",
   1619                               netLookupErrorString(result));
   1620         } else {
   1621             jniThrowException(env, "java/net/ConnectException",
   1622                               netLookupErrorString(result));
   1623         }
   1624     }
   1625 
   1626     return result;
   1627 }
   1628 
   1629 static void osNetworkSystem_connectStreamWithTimeoutSocketImpl(JNIEnv* env,
   1630         jclass clazz, jobject fileDescriptor, jint remotePort, jint timeout,
   1631         jint trafficClass, jobject inetAddr) {
   1632     // LOGD("ENTER connectStreamWithTimeoutSocketImpl");
   1633 
   1634     int result = 0;
   1635     struct sockaddr_storage address;
   1636     jbyte *context = NULL;
   1637     int remainingTimeout = timeout;
   1638     int passedTimeout = 0;
   1639     int finishTime = 0;
   1640     int blocking = 0;
   1641     char hasTimeout = timeout > 0;
   1642 
   1643     /* if a timeout was specified calculate the finish time value */
   1644     if (hasTimeout)  {
   1645         finishTime = time_msec_clock() + (int) timeout;
   1646     }
   1647 
   1648     int handle;
   1649     if (!jniGetFd(env, fileDescriptor, handle)) {
   1650         return;
   1651     }
   1652 
   1653     if (!inetAddressToSocketAddress(env, inetAddr, remotePort, &address)) {
   1654         return;
   1655     }
   1656 
   1657     /*
   1658      * we will be looping checking for when we are connected so allocate
   1659      * the descriptor sets that we will use
   1660      */
   1661     context =(jbyte *) malloc(sizeof(struct selectFDSet));
   1662     if (context == NULL) {
   1663         jniThrowException(env, "java/lang/OutOfMemoryError", "native heap");
   1664         return;
   1665     }
   1666 
   1667     result = sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_START, context);
   1668     if (0 == result) {
   1669         /* ok we connected right away so we are done */
   1670         sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_DONE, context);
   1671         goto bail;
   1672     } else if (result != SOCKERR_NOTCONNECTED) {
   1673         sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_DONE,
   1674                                context);
   1675         /* we got an error other than NOTCONNECTED so we cannot continue */
   1676         if (SOCKERR_EACCES == result) {
   1677             jniThrowException(env, "java/lang/SecurityException",
   1678                               netLookupErrorString(result));
   1679         } else {
   1680             throwSocketException(env, result);
   1681         }
   1682         goto bail;
   1683     }
   1684 
   1685     while (SOCKERR_NOTCONNECTED == result) {
   1686         passedTimeout = remainingTimeout;
   1687 
   1688         /*
   1689          * ok now try and connect. Depending on the platform this may sleep
   1690          * for up to passedTimeout milliseconds
   1691          */
   1692         result = sockConnectWithTimeout(handle, address, passedTimeout,
   1693                 SOCKET_STEP_CHECK, context);
   1694 
   1695         /*
   1696          * now check if the socket is still connected.
   1697          * Do it here as some platforms seem to think they
   1698          * are connected if the socket is closed on them.
   1699          */
   1700         handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
   1701         if (handle == -1) {
   1702             sockConnectWithTimeout(handle, address, 0,
   1703                     SOCKET_STEP_DONE, context);
   1704             jniThrowSocketException(env, EBADF);
   1705             goto bail;
   1706         }
   1707 
   1708         /*
   1709          * check if we are now connected,
   1710          * if so we can finish the process and return
   1711          */
   1712         if (0 == result) {
   1713             sockConnectWithTimeout(handle, address, 0,
   1714                     SOCKET_STEP_DONE, context);
   1715             goto bail;
   1716         }
   1717 
   1718         /*
   1719          * if the error is SOCKERR_NOTCONNECTED then we have not yet
   1720          * connected and we may not be done yet
   1721          */
   1722         if (SOCKERR_NOTCONNECTED == result) {
   1723             /* check if the timeout has expired */
   1724             if (hasTimeout) {
   1725                 remainingTimeout = finishTime - time_msec_clock();
   1726                 if (remainingTimeout <= 0) {
   1727                     sockConnectWithTimeout(handle, address, 0,
   1728                             SOCKET_STEP_DONE, context);
   1729                     jniThrowSocketTimeoutException(env, ENOTCONN);
   1730                     goto bail;
   1731                 }
   1732             } else {
   1733                 remainingTimeout = 100;
   1734             }
   1735         } else {
   1736             sockConnectWithTimeout(handle, address, remainingTimeout,
   1737                                    SOCKET_STEP_DONE, context);
   1738             if ((SOCKERR_CONNRESET == result) ||
   1739                 (SOCKERR_CONNECTION_REFUSED == result) ||
   1740                 (SOCKERR_ADDRNOTAVAIL == result) ||
   1741                 (SOCKERR_ADDRINUSE == result) ||
   1742                 (SOCKERR_ENETUNREACH == result)) {
   1743                 jniThrowException(env, "java/net/ConnectException",
   1744                                   netLookupErrorString(result));
   1745             } else if (SOCKERR_EACCES == result) {
   1746                 jniThrowException(env, "java/lang/SecurityException",
   1747                                   netLookupErrorString(result));
   1748             } else {
   1749                 throwSocketException(env, result);
   1750             }
   1751             goto bail;
   1752         }
   1753     }
   1754 
   1755 bail:
   1756 
   1757     /* free the memory for the FD set */
   1758     if (context != NULL)  {
   1759         free(context);
   1760     }
   1761 }
   1762 
   1763 static void osNetworkSystem_socketBindImpl(JNIEnv* env, jclass clazz,
   1764         jobject fileDescriptor, jint port, jobject inetAddress) {
   1765     // LOGD("ENTER socketBindImpl");
   1766 
   1767     sockaddr_storage socketAddress;
   1768     if (!inetAddressToSocketAddress(env, inetAddress, port, &socketAddress)) {
   1769         return;
   1770     }
   1771 
   1772     int fd;
   1773     if (!jniGetFd(env, fileDescriptor, fd)) {
   1774         return;
   1775     }
   1776 
   1777     sockaddr_storage tmp;
   1778     const sockaddr* realAddress = convertIpv4ToMapped(fd, &socketAddress, &tmp, false);
   1779     int rc = TEMP_FAILURE_RETRY(bind(fd, realAddress, sizeof(sockaddr_storage)));
   1780     if (rc == -1) {
   1781         jniThrowBindException(env, errno);
   1782     }
   1783 }
   1784 
   1785 static void osNetworkSystem_listenStreamSocketImpl(JNIEnv* env, jclass clazz,
   1786         jobject fileDescriptor, jint backlog) {
   1787     // LOGD("ENTER listenStreamSocketImpl");
   1788 
   1789     int handle;
   1790     if (!jniGetFd(env, fileDescriptor, handle)) {
   1791         return;
   1792     }
   1793 
   1794     int rc = listen(handle, backlog);
   1795     if (rc == -1) {
   1796         jniThrowSocketException(env, errno);
   1797         return;
   1798     }
   1799 }
   1800 
   1801 static jint osNetworkSystem_availableStreamImpl(JNIEnv* env, jclass clazz,
   1802         jobject fileDescriptor) {
   1803     // LOGD("ENTER availableStreamImpl");
   1804 
   1805     int handle;
   1806     if (!jniGetFd(env, fileDescriptor, handle)) {
   1807         return 0;
   1808     }
   1809 
   1810     int result;
   1811     do {
   1812         result = selectWait(handle, 1);
   1813 
   1814         if (SOCKERR_TIMEOUT == result) {
   1815             // The read operation timed out, so answer 0 bytes available
   1816             return 0;
   1817         } else if (SOCKERR_INTERRUPTED == result) {
   1818             continue;
   1819         } else if (0 > result) {
   1820             throwSocketException(env, result);
   1821             return 0;
   1822         }
   1823     } while (SOCKERR_INTERRUPTED == result);
   1824 
   1825     char message[2048];
   1826     result = recv(handle, (jbyte *) message, sizeof(message), MSG_PEEK);
   1827 
   1828     if (0 > result) {
   1829         jniThrowSocketException(env, errno);
   1830         return 0;
   1831     }
   1832     return result;
   1833 }
   1834 
   1835 static void osNetworkSystem_acceptSocketImpl(JNIEnv* env, jclass,
   1836         jobject serverFileDescriptor,
   1837         jobject newSocket, jobject clientFileDescriptor, jint timeout) {
   1838     // LOGD("ENTER acceptSocketImpl");
   1839 
   1840     if (newSocket == NULL) {
   1841         jniThrowNullPointerException(env, NULL);
   1842         return;
   1843     }
   1844 
   1845     int rc = pollSelectWait(env, serverFileDescriptor, timeout);
   1846     if (rc < 0) {
   1847         return;
   1848     }
   1849 
   1850     int serverFd;
   1851     if (!jniGetFd(env, serverFileDescriptor, serverFd)) {
   1852         return;
   1853     }
   1854 
   1855     sockaddr_storage sa;
   1856     socklen_t addrlen = sizeof(sa);
   1857     int clientFd = TEMP_FAILURE_RETRY(accept(serverFd,
   1858             reinterpret_cast<sockaddr*>(&sa), &addrlen));
   1859     if (clientFd == -1) {
   1860         jniThrowSocketException(env, errno);
   1861         return;
   1862     }
   1863 
   1864     /*
   1865      * For network sockets, put the peer address and port in instance variables.
   1866      * We don't bother to do this for UNIX domain sockets, since most peers are
   1867      * anonymous anyway.
   1868      */
   1869     if (sa.ss_family == AF_INET || sa.ss_family == AF_INET6) {
   1870         jobject inetAddress = socketAddressToInetAddress(env, &sa);
   1871         if (inetAddress == NULL) {
   1872             close(clientFd);
   1873             return;
   1874         }
   1875 
   1876         env->SetObjectField(newSocket,
   1877                 gCachedFields.socketimpl_address, inetAddress);
   1878 
   1879         int port = getSocketAddressPort(&sa);
   1880         env->SetIntField(newSocket, gCachedFields.socketimpl_port, port);
   1881     }
   1882 
   1883     jniSetFileDescriptorOfFD(env, clientFileDescriptor, clientFd);
   1884 }
   1885 
   1886 static jboolean osNetworkSystem_supportsUrgentDataImpl(JNIEnv* env,
   1887         jclass clazz, jobject fileDescriptor) {
   1888     // LOGD("ENTER supportsUrgentDataImpl");
   1889 
   1890     // TODO(enh): do we really need to exclude the invalid file descriptor case?
   1891     int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
   1892     return (fd == -1) ? JNI_FALSE : JNI_TRUE;
   1893 }
   1894 
   1895 static void osNetworkSystem_sendUrgentDataImpl(JNIEnv* env, jclass clazz,
   1896         jobject fileDescriptor, jbyte value) {
   1897     // LOGD("ENTER sendUrgentDataImpl");
   1898 
   1899     int handle;
   1900     if (!jniGetFd(env, fileDescriptor, handle)) {
   1901         return;
   1902     }
   1903 
   1904     int rc = send(handle, &value, 1, MSG_OOB);
   1905     if (rc == -1) {
   1906         jniThrowSocketException(env, errno);
   1907     }
   1908 }
   1909 
   1910 static void osNetworkSystem_connectDatagramImpl2(JNIEnv* env, jclass,
   1911         jobject fileDescriptor, jint port, jint trafficClass, jobject inetAddress) {
   1912     // LOGD("ENTER connectDatagramImpl2");
   1913 
   1914     sockaddr_storage sockAddr;
   1915     if (!inetAddressToSocketAddress(env, inetAddress, port, &sockAddr)) {
   1916         return;
   1917     }
   1918 
   1919     int fd;
   1920     if (!jniGetFd(env, fileDescriptor, fd)) {
   1921         return;
   1922     }
   1923 
   1924     int ret = doConnect(fd, &sockAddr);
   1925     if (ret < 0) {
   1926         jniThrowSocketException(env, errno);
   1927     }
   1928 }
   1929 
   1930 static void osNetworkSystem_disconnectDatagramImpl(JNIEnv* env, jclass,
   1931         jobject fileDescriptor) {
   1932     // LOGD("ENTER disconnectDatagramImpl");
   1933 
   1934     int fd;
   1935     if (!jniGetFd(env, fileDescriptor, fd)) {
   1936         return;
   1937     }
   1938 
   1939     sockaddr_storage sockAddr;
   1940     memset(&sockAddr, 0, sizeof(sockAddr));
   1941     sockAddr.ss_family = AF_UNSPEC;
   1942 
   1943     int result = doConnect(fd, &sockAddr);
   1944     if (result < 0) {
   1945         jniThrowSocketException(env, errno);
   1946     }
   1947 }
   1948 
   1949 static void osNetworkSystem_setInetAddressImpl(JNIEnv* env, jobject,
   1950         jobject sender, jbyteArray address) {
   1951     // LOGD("ENTER setInetAddressImpl");
   1952 
   1953     env->SetObjectField(sender, gCachedFields.iaddr_ipaddress, address);
   1954 }
   1955 
   1956 static jint osNetworkSystem_peekDatagramImpl(JNIEnv* env, jclass clazz,
   1957         jobject fileDescriptor, jobject sender, jint receiveTimeout) {
   1958     // LOGD("ENTER peekDatagramImpl");
   1959 
   1960     int result = pollSelectWait(env, fileDescriptor, receiveTimeout);
   1961     if (result < 0) {
   1962         return 0;
   1963     }
   1964 
   1965     int fd;
   1966     if (!jniGetFd(env, fileDescriptor, fd)) {
   1967         return 0;
   1968     }
   1969 
   1970     sockaddr_storage sockAddr;
   1971     socklen_t sockAddrLen = sizeof(sockAddr);
   1972     ssize_t length = TEMP_FAILURE_RETRY(recvfrom(fd, NULL, 0, MSG_PEEK,
   1973             reinterpret_cast<sockaddr*>(&sockAddr), &sockAddrLen));
   1974     if (length == -1) {
   1975         jniThrowSocketException(env, errno);
   1976         return 0;
   1977     }
   1978 
   1979     // We update the byte[] in the 'sender' InetAddress, and return the port.
   1980     // This awful API is public in the RI, so there's no point returning
   1981     // InetSocketAddress here instead.
   1982     jbyteArray senderAddressArray = socketAddressToByteArray(env, &sockAddr);
   1983     if (sender == NULL) {
   1984         return -1;
   1985     }
   1986     osNetworkSystem_setInetAddressImpl(env, NULL, sender, senderAddressArray);
   1987     return getSocketAddressPort(&sockAddr);
   1988 }
   1989 
   1990 static jint osNetworkSystem_receiveDatagramDirectImpl(JNIEnv* env, jclass clazz,
   1991         jobject fileDescriptor, jobject packet, jint address, jint offset,
   1992         jint length, jint receiveTimeout, jboolean peek) {
   1993     // LOGD("ENTER receiveDatagramDirectImpl");
   1994 
   1995     int result = pollSelectWait(env, fileDescriptor, receiveTimeout);
   1996     if (result < 0) {
   1997         return 0;
   1998     }
   1999 
   2000     int fd;
   2001     if (!jniGetFd(env, fileDescriptor, fd)) {
   2002         return 0;
   2003     }
   2004 
   2005     char* buf =
   2006             reinterpret_cast<char*>(static_cast<uintptr_t>(address + offset));
   2007     const int mode = peek ? MSG_PEEK : 0;
   2008     sockaddr_storage sockAddr;
   2009     socklen_t sockAddrLen = sizeof(sockAddr);
   2010     ssize_t actualLength = TEMP_FAILURE_RETRY(recvfrom(fd, buf, length, mode,
   2011             reinterpret_cast<sockaddr*>(&sockAddr), &sockAddrLen));
   2012     if (actualLength == -1) {
   2013         jniThrowSocketException(env, errno);
   2014         return 0;
   2015     }
   2016 
   2017     if (packet != NULL) {
   2018         jbyteArray addr = socketAddressToByteArray(env, &sockAddr);
   2019         if (addr == NULL) {
   2020             return 0;
   2021         }
   2022         int port = getSocketAddressPort(&sockAddr);
   2023         jobject sender = env->CallStaticObjectMethod(
   2024                 gCachedFields.iaddr_class, gCachedFields.iaddr_getbyaddress,
   2025                 addr);
   2026         env->SetObjectField(packet, gCachedFields.dpack_address, sender);
   2027         env->SetIntField(packet, gCachedFields.dpack_port, port);
   2028         env->SetIntField(packet, gCachedFields.dpack_length,
   2029                 (jint) actualLength);
   2030     }
   2031     return (jint) actualLength;
   2032 }
   2033 
   2034 static jint osNetworkSystem_receiveDatagramImpl(JNIEnv* env, jclass clazz,
   2035         jobject fd, jobject packet, jbyteArray data, jint offset, jint length,
   2036         jint receiveTimeout, jboolean peek) {
   2037     // LOGD("ENTER receiveDatagramImpl");
   2038 
   2039     int localLength = (length < 65536) ? length : 65536;
   2040     jbyte *bytes = (jbyte*) malloc(localLength);
   2041     if (bytes == NULL) {
   2042         jniThrowException(env, "java/lang/OutOfMemoryError",
   2043                 "couldn't allocate enough memory for receiveDatagram");
   2044         return 0;
   2045     }
   2046 
   2047     int actualLength = osNetworkSystem_receiveDatagramDirectImpl(env, clazz, fd,
   2048             packet, (jint)bytes, 0, localLength, receiveTimeout, peek);
   2049 
   2050     if (actualLength > 0) {
   2051         env->SetByteArrayRegion(data, offset, actualLength, bytes);
   2052     }
   2053     free(bytes);
   2054 
   2055     return actualLength;
   2056 }
   2057 
   2058 static jint osNetworkSystem_recvConnectedDatagramDirectImpl(JNIEnv* env,
   2059         jclass clazz, jobject fileDescriptor, jobject packet,
   2060         jint address, jint offset, jint length,
   2061         jint receiveTimeout, jboolean peek) {
   2062     // LOGD("ENTER receiveConnectedDatagramDirectImpl");
   2063 
   2064     int result = pollSelectWait(env, fileDescriptor, receiveTimeout);
   2065     if (result < 0) {
   2066         return 0;
   2067     }
   2068 
   2069     int fd;
   2070     if (!jniGetFd(env, fileDescriptor, fd)) {
   2071         return 0;
   2072     }
   2073 
   2074     char* buf = reinterpret_cast<char*>(static_cast<uintptr_t>(address + offset));
   2075     int mode = peek ? MSG_PEEK : 0;
   2076     int actualLength = recvfrom(fd, buf, length, mode, NULL, NULL);
   2077     if (actualLength < 0) {
   2078         jniThrowException(env, "java/net/PortUnreachableException", "");
   2079         return 0;
   2080     }
   2081 
   2082     if (packet != NULL) {
   2083         env->SetIntField(packet, gCachedFields.dpack_length, actualLength);
   2084     }
   2085     return actualLength;
   2086 }
   2087 
   2088 static jint osNetworkSystem_recvConnectedDatagramImpl(JNIEnv* env, jclass clazz,
   2089         jobject fd, jobject packet, jbyteArray data, jint offset, jint length,
   2090         jint receiveTimeout, jboolean peek) {
   2091     // LOGD("ENTER receiveConnectedDatagramImpl");
   2092 
   2093     int localLength = (length < 65536) ? length : 65536;
   2094     jbyte *bytes = (jbyte*) malloc(localLength);
   2095     if (bytes == NULL) {
   2096         jniThrowException(env, "java/lang/OutOfMemoryError",
   2097                 "couldn't allocate enough memory for recvConnectedDatagram");
   2098         return 0;
   2099     }
   2100 
   2101     int actualLength = osNetworkSystem_recvConnectedDatagramDirectImpl(env,
   2102             clazz, fd, packet, (jint)bytes, 0, localLength,
   2103             receiveTimeout, peek);
   2104 
   2105     if (actualLength > 0) {
   2106         env->SetByteArrayRegion(data, offset, actualLength, bytes);
   2107     }
   2108     free(bytes);
   2109 
   2110     return actualLength;
   2111 }
   2112 
   2113 static jint osNetworkSystem_sendDatagramDirectImpl(JNIEnv* env, jclass clazz,
   2114         jobject fileDescriptor, jint address, jint offset, jint length,
   2115         jint port,
   2116         jboolean bindToDevice, jint trafficClass, jobject inetAddress) {
   2117     // LOGD("ENTER sendDatagramDirectImpl");
   2118 
   2119     int fd;
   2120     if (!jniGetFd(env, fileDescriptor, fd)) {
   2121         return -1;
   2122     }
   2123 
   2124     sockaddr_storage receiver;
   2125     if (!inetAddressToSocketAddress(env, inetAddress, port, &receiver)) {
   2126         return -1;
   2127     }
   2128 
   2129     char* buf =
   2130             reinterpret_cast<char*>(static_cast<uintptr_t>(address + offset));
   2131     ssize_t bytesSent = TEMP_FAILURE_RETRY(sendto(fd, buf, length,
   2132             SOCKET_NOFLAGS,
   2133             reinterpret_cast<sockaddr*>(&receiver), sizeof(receiver)));
   2134     if (bytesSent == -1) {
   2135         if (errno == ECONNRESET || errno == ECONNREFUSED) {
   2136             return 0;
   2137         } else {
   2138             jniThrowSocketException(env, errno);
   2139         }
   2140     }
   2141     return bytesSent;
   2142 }
   2143 
   2144 static jint osNetworkSystem_sendDatagramImpl(JNIEnv* env, jclass clazz,
   2145         jobject fd, jbyteArray data, jint offset, jint length, jint port,
   2146         jboolean bindToDevice, jint trafficClass, jobject inetAddress) {
   2147     // LOGD("ENTER sendDatagramImpl");
   2148 
   2149     jbyte *bytes = env->GetByteArrayElements(data, NULL);
   2150     int actualLength = osNetworkSystem_sendDatagramDirectImpl(env, clazz, fd,
   2151             (jint)bytes, offset, length, port, bindToDevice, trafficClass,
   2152             inetAddress);
   2153     env->ReleaseByteArrayElements(data, bytes, JNI_ABORT);
   2154 
   2155     return actualLength;
   2156 }
   2157 
   2158 static jint osNetworkSystem_sendConnectedDatagramDirectImpl(JNIEnv* env,
   2159         jclass clazz, jobject fileDescriptor,
   2160         jint address, jint offset, jint length,
   2161         jboolean bindToDevice) {
   2162     // LOGD("ENTER sendConnectedDatagramDirectImpl");
   2163 
   2164     int fd;
   2165     if (!jniGetFd(env, fileDescriptor, fd)) {
   2166         return 0;
   2167     }
   2168 
   2169     char* buf =
   2170             reinterpret_cast<char*>(static_cast<uintptr_t>(address + offset));
   2171     ssize_t bytesSent = TEMP_FAILURE_RETRY(send(fd, buf, length, 0));
   2172     if (bytesSent == -1) {
   2173         if (errno == ECONNRESET || errno == ECONNREFUSED) {
   2174             return 0;
   2175         } else {
   2176             jniThrowSocketException(env, errno);
   2177         }
   2178     }
   2179     return bytesSent;
   2180 }
   2181 
   2182 static jint osNetworkSystem_sendConnectedDatagramImpl(JNIEnv* env, jclass clazz,
   2183         jobject fd, jbyteArray data, jint offset, jint length,
   2184         jboolean bindToDevice) {
   2185     // LOGD("ENTER sendConnectedDatagramImpl");
   2186 
   2187     jbyte *bytes = env->GetByteArrayElements(data, NULL);
   2188     int actualLength = osNetworkSystem_sendConnectedDatagramDirectImpl(env,
   2189             clazz, fd, (jint)bytes, offset, length, bindToDevice);
   2190     env->ReleaseByteArrayElements(data, bytes, JNI_ABORT);
   2191 
   2192     return actualLength;
   2193 }
   2194 
   2195 static void osNetworkSystem_createServerStreamSocketImpl(JNIEnv* env,
   2196         jclass clazz, jobject fileDescriptor, jboolean preferIPv4Stack) {
   2197     // LOGD("ENTER createServerStreamSocketImpl");
   2198 
   2199     int handle = createSocketFileDescriptor(env, fileDescriptor, SOCK_STREAM);
   2200     if (handle < 0) {
   2201         return;
   2202     }
   2203 
   2204     int value = 1;
   2205     setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(int));
   2206 }
   2207 
   2208 static void doShutdown(JNIEnv* env, jobject fileDescriptor, int how) {
   2209     int fd;
   2210     if (!jniGetFd(env, fileDescriptor, fd)) {
   2211         return;
   2212     }
   2213     int rc = shutdown(fd, how);
   2214     if (rc == -1) {
   2215         jniThrowSocketException(env, errno);
   2216     }
   2217 }
   2218 
   2219 static void osNetworkSystem_shutdownInputImpl(JNIEnv* env, jobject,
   2220         jobject fileDescriptor) {
   2221     doShutdown(env, fileDescriptor, SHUT_RD);
   2222 }
   2223 
   2224 static void osNetworkSystem_shutdownOutputImpl(JNIEnv* env, jobject,
   2225         jobject fileDescriptor) {
   2226     doShutdown(env, fileDescriptor, SHUT_WR);
   2227 }
   2228 
   2229 static jint osNetworkSystem_sendDatagramImpl2(JNIEnv* env, jclass clazz,
   2230         jobject fileDescriptor, jbyteArray data, jint offset, jint length,
   2231         jint port, jobject inetAddress) {
   2232     // LOGD("ENTER sendDatagramImpl2");
   2233 
   2234     sockaddr_storage sockAddr;
   2235     if (inetAddress != NULL) {
   2236         if (!inetAddressToSocketAddress(env, inetAddress, port, &sockAddr)) {
   2237             return -1;
   2238         }
   2239     }
   2240 
   2241     int fd;
   2242     if (!jniGetFd(env, fileDescriptor, fd)) {
   2243         return 0;
   2244     }
   2245 
   2246     jbyte* message = (jbyte*) malloc(length * sizeof(jbyte));
   2247     if (message == NULL) {
   2248         jniThrowException(env, "java/lang/OutOfMemoryError",
   2249                 "couldn't allocate enough memory for readSocket");
   2250         return 0;
   2251     }
   2252 
   2253     env->GetByteArrayRegion(data, offset, length, message);
   2254 
   2255     int totalBytesSent = 0;
   2256     while (totalBytesSent < length) {
   2257         ssize_t bytesSent = TEMP_FAILURE_RETRY(sendto(fd,
   2258                 message + totalBytesSent, length - totalBytesSent,
   2259                 SOCKET_NOFLAGS,
   2260                 reinterpret_cast<sockaddr*>(&sockAddr), sizeof(sockAddr)));
   2261         if (bytesSent == -1) {
   2262             jniThrowSocketException(env, errno);
   2263             free(message);
   2264             return 0;
   2265         }
   2266 
   2267         totalBytesSent += bytesSent;
   2268     }
   2269 
   2270     free(message);
   2271     return totalBytesSent;
   2272 }
   2273 
   2274 static bool initFdSet(JNIEnv* env, jobjectArray fdArray, jint count, fd_set* fdSet, int* maxFd) {
   2275     for (int i = 0; i < count; ++i) {
   2276         jobject fileDescriptor = env->GetObjectArrayElement(fdArray, i);
   2277         if (fileDescriptor == NULL) {
   2278             return false;
   2279         }
   2280 
   2281         const int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
   2282         if (fd < 0 || fd > 1024) {
   2283             LOGE("selectImpl: ignoring invalid fd %i", fd);
   2284             continue;
   2285         }
   2286 
   2287         FD_SET(fd, fdSet);
   2288 
   2289         if (fd > *maxFd) {
   2290             *maxFd = fd;
   2291         }
   2292     }
   2293     return true;
   2294 }
   2295 
   2296 /*
   2297  * Note: fdSet has to be non-const because although on Linux FD_ISSET() is sane
   2298  * and takes a const fd_set*, it takes fd_set* on Mac OS. POSIX is not on our
   2299  * side here:
   2300  *   http://www.opengroup.org/onlinepubs/000095399/functions/select.html
   2301  */
   2302 static bool translateFdSet(JNIEnv* env, jobjectArray fdArray, jint count, fd_set& fdSet, jint* flagArray, size_t offset, jint op) {
   2303     for (int i = 0; i < count; ++i) {
   2304         jobject fileDescriptor = env->GetObjectArrayElement(fdArray, i);
   2305         if (fileDescriptor == NULL) {
   2306             return false;
   2307         }
   2308 
   2309         const int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
   2310         const bool valid = fd >= 0 && fd < 1024;
   2311 
   2312         if (valid && FD_ISSET(fd, &fdSet)) {
   2313             flagArray[i + offset] = op;
   2314         } else {
   2315             flagArray[i + offset] = SOCKET_OP_NONE;
   2316         }
   2317     }
   2318     return true;
   2319 }
   2320 
   2321 static jboolean osNetworkSystem_selectImpl(JNIEnv* env, jclass clazz,
   2322         jobjectArray readFDArray, jobjectArray writeFDArray, jint countReadC,
   2323         jint countWriteC, jintArray outFlags, jlong timeoutMs) {
   2324     // LOGD("ENTER selectImpl");
   2325 
   2326     // Initialize the fd_sets.
   2327     int maxFd = -1;
   2328     fd_set readFds;
   2329     fd_set writeFds;
   2330     FD_ZERO(&readFds);
   2331     FD_ZERO(&writeFds);
   2332     bool initialized = initFdSet(env, readFDArray, countReadC, &readFds, &maxFd) &&
   2333                        initFdSet(env, writeFDArray, countWriteC, &writeFds, &maxFd);
   2334     if (!initialized) {
   2335         return -1;
   2336     }
   2337 
   2338     // Initialize the timeout, if any.
   2339     timeval tv;
   2340     timeval* tvp = NULL;
   2341     if (timeoutMs >= 0) {
   2342         tv = toTimeval(timeoutMs);
   2343         tvp = &tv;
   2344     }
   2345 
   2346     // Perform the select.
   2347     int result = select(maxFd + 1, &readFds, &writeFds, NULL, tvp);
   2348     if (result == 0) {
   2349         // Timeout.
   2350         return JNI_FALSE;
   2351     } else if (result == -1) {
   2352         // Error.
   2353         if (errno == EINTR) {
   2354             return JNI_FALSE;
   2355         } else {
   2356             jniThrowSocketException(env, errno);
   2357             return JNI_FALSE;
   2358         }
   2359     }
   2360 
   2361     // Translate the result into the int[] we're supposed to fill in.
   2362     jint* flagArray = env->GetIntArrayElements(outFlags, NULL);
   2363     if (flagArray == NULL) {
   2364         return JNI_FALSE;
   2365     }
   2366     bool okay = translateFdSet(env, readFDArray, countReadC, readFds, flagArray, 0, SOCKET_OP_READ) &&
   2367                 translateFdSet(env, writeFDArray, countWriteC, writeFds, flagArray, countReadC, SOCKET_OP_WRITE);
   2368     env->ReleaseIntArrayElements(outFlags, flagArray, 0);
   2369     return okay;
   2370 }
   2371 
   2372 static jobject osNetworkSystem_getSocketLocalAddressImpl(JNIEnv* env,
   2373         jclass, jobject fileDescriptor) {
   2374     // LOGD("ENTER getSocketLocalAddressImpl");
   2375 
   2376     int fd;
   2377     if (!jniGetFd(env, fileDescriptor, fd)) {
   2378         return NULL;
   2379     }
   2380 
   2381     sockaddr_storage addr;
   2382     socklen_t addrLen = sizeof(addr);
   2383     memset(&addr, 0, addrLen);
   2384     int rc = getsockname(fd, (sockaddr*) &addr, &addrLen);
   2385     if (rc == -1) {
   2386         // TODO: the public API doesn't allow failure, so this whole method
   2387         // represents a broken design. In practice, though, getsockname can't
   2388         // fail unless we give it invalid arguments.
   2389         LOGE("getsockname failed: %s (errno=%i)", strerror(errno), errno);
   2390         return NULL;
   2391     }
   2392     return socketAddressToInetAddress(env, &addr);
   2393 }
   2394 
   2395 static jint osNetworkSystem_getSocketLocalPortImpl(JNIEnv* env, jclass,
   2396         jobject fileDescriptor) {
   2397     // LOGD("ENTER getSocketLocalPortImpl");
   2398 
   2399     int fd;
   2400     if (!jniGetFd(env, fileDescriptor, fd)) {
   2401         return 0;
   2402     }
   2403 
   2404     sockaddr_storage addr;
   2405     socklen_t addrLen = sizeof(addr);
   2406     memset(&addr, 0, addrLen);
   2407     int rc = getsockname(fd, (sockaddr*) &addr, &addrLen);
   2408     if (rc == -1) {
   2409         // TODO: the public API doesn't allow failure, so this whole method
   2410         // represents a broken design. In practice, though, getsockname can't
   2411         // fail unless we give it invalid arguments.
   2412         LOGE("getsockname failed: %s (errno=%i)", strerror(errno), errno);
   2413         return 0;
   2414     }
   2415     return getSocketAddressPort(&addr);
   2416 }
   2417 
   2418 static jobject osNetworkSystem_getSocketOptionImpl(JNIEnv* env, jclass clazz,
   2419         jobject fileDescriptor, jint anOption) {
   2420     // LOGD("ENTER getSocketOptionImpl");
   2421 
   2422     int intValue = 0;
   2423     socklen_t intSize = sizeof(int);
   2424     int result;
   2425     struct sockaddr_storage sockVal;
   2426     socklen_t sockSize = sizeof(sockVal);
   2427 
   2428     int handle;
   2429     if (!jniGetFd(env, fileDescriptor, handle)) {
   2430         return 0;
   2431     }
   2432 
   2433     switch ((int) anOption & 0xffff) {
   2434         case JAVASOCKOPT_SO_LINGER: {
   2435             struct linger lingr;
   2436             socklen_t size = sizeof(struct linger);
   2437             result = getsockopt(handle, SOL_SOCKET, SO_LINGER, &lingr, &size);
   2438             if (0 != result) {
   2439                 jniThrowSocketException(env, errno);
   2440                 return NULL;
   2441             }
   2442             if (!lingr.l_onoff) {
   2443                 intValue = -1;
   2444             } else {
   2445                 intValue = lingr.l_linger;
   2446             }
   2447             return newJavaLangInteger(env, intValue);
   2448         }
   2449 
   2450         case JAVASOCKOPT_TCP_NODELAY: {
   2451             if ((anOption >> 16) & BROKEN_TCP_NODELAY) {
   2452                 return NULL;
   2453             }
   2454             result = getsockopt(handle, IPPROTO_TCP, TCP_NODELAY, &intValue, &intSize);
   2455             if (0 != result) {
   2456                 jniThrowSocketException(env, errno);
   2457                 return NULL;
   2458             }
   2459             return newJavaLangBoolean(env, intValue);
   2460         }
   2461 
   2462         case JAVASOCKOPT_SO_SNDBUF: {
   2463             result = getsockopt(handle, SOL_SOCKET, SO_SNDBUF, &intValue, &intSize);
   2464             if (0 != result) {
   2465                 jniThrowSocketException(env, errno);
   2466                 return NULL;
   2467             }
   2468             return newJavaLangInteger(env, intValue);
   2469         }
   2470 
   2471         case JAVASOCKOPT_SO_RCVBUF: {
   2472             result = getsockopt(handle, SOL_SOCKET, SO_RCVBUF, &intValue, &intSize);
   2473             if (0 != result) {
   2474                 jniThrowSocketException(env, errno);
   2475                 return NULL;
   2476             }
   2477             return newJavaLangInteger(env, intValue);
   2478         }
   2479 
   2480         case JAVASOCKOPT_SO_BROADCAST: {
   2481             result = getsockopt(handle, SOL_SOCKET, SO_BROADCAST, &intValue, &intSize);
   2482             if (0 != result) {
   2483                 jniThrowSocketException(env, errno);
   2484                 return NULL;
   2485             }
   2486             return newJavaLangBoolean(env, intValue);
   2487         }
   2488 
   2489         case JAVASOCKOPT_SO_REUSEADDR: {
   2490             result = getsockopt(handle, SOL_SOCKET, SO_REUSEADDR, &intValue, &intSize);
   2491             if (0 != result) {
   2492                 jniThrowSocketException(env, errno);
   2493                 return NULL;
   2494             }
   2495             return newJavaLangBoolean(env, intValue);
   2496         }
   2497 
   2498         case JAVASOCKOPT_SO_KEEPALIVE: {
   2499             result = getsockopt(handle, SOL_SOCKET, SO_KEEPALIVE, &intValue, &intSize);
   2500             if (0 != result) {
   2501                 jniThrowSocketException(env, errno);
   2502                 return NULL;
   2503             }
   2504             return newJavaLangBoolean(env, intValue);
   2505         }
   2506 
   2507         case JAVASOCKOPT_SO_OOBINLINE: {
   2508             result = getsockopt(handle, SOL_SOCKET, SO_OOBINLINE, &intValue, &intSize);
   2509             if (0 != result) {
   2510                 jniThrowSocketException(env, errno);
   2511                 return NULL;
   2512             }
   2513             return newJavaLangBoolean(env, intValue);
   2514         }
   2515 
   2516         case JAVASOCKOPT_IP_TOS: {
   2517             result = getOrSetSocketOption(SOCKOPT_GET, handle, IP_TOS,
   2518                                           IPV6_TCLASS, &intValue, &intSize);
   2519             if (0 != result) {
   2520                 jniThrowSocketException(env, errno);
   2521                 return NULL;
   2522             }
   2523             return newJavaLangInteger(env, intValue);
   2524         }
   2525 
   2526         case JAVASOCKOPT_SO_RCVTIMEOUT: {
   2527             struct timeval timeout;
   2528             socklen_t size = sizeof(timeout);
   2529             result = getsockopt(handle, SOL_SOCKET, SO_RCVTIMEO, &timeout, &size);
   2530             if (0 != result) {
   2531                 jniThrowSocketException(env, errno);
   2532                 return NULL;
   2533             }
   2534             return newJavaLangInteger(env, toMs(timeout));
   2535         }
   2536 
   2537 #ifdef ENABLE_MULTICAST
   2538         case JAVASOCKOPT_MCAST_TTL: {
   2539             if ((anOption >> 16) & BROKEN_MULTICAST_TTL) {
   2540                 return newJavaLangByte(env, 0);
   2541             }
   2542             // Java uses a byte to store the TTL, but the kernel uses an int.
   2543             result = getOrSetSocketOption(SOCKOPT_GET, handle, IP_MULTICAST_TTL,
   2544                                           IPV6_MULTICAST_HOPS, &intValue,
   2545                                           &intSize);
   2546             if (0 != result) {
   2547                 jniThrowSocketException(env, errno);
   2548                 return NULL;
   2549             }
   2550             return newJavaLangByte(env, (jbyte)(intValue & 0xFF));
   2551         }
   2552 
   2553         case JAVASOCKOPT_IP_MULTICAST_IF: {
   2554             if ((anOption >> 16) & BROKEN_MULTICAST_IF) {
   2555                 return NULL;
   2556             }
   2557             result = getsockopt(handle, IPPROTO_IP, IP_MULTICAST_IF,
   2558                 &sockVal, &sockSize);
   2559             if (result == -1) {
   2560                 jniThrowSocketException(env, errno);
   2561                 return NULL;
   2562             }
   2563             if (sockVal.ss_family != AF_INET) {
   2564                 // Java expects an AF_INET INADDR_ANY, but Linux just returns AF_UNSPEC.
   2565                 jbyteArray inAddrAny = env->NewByteArray(4); // { 0, 0, 0, 0 }
   2566                 return byteArrayToInetAddress(env, inAddrAny);
   2567             }
   2568             return socketAddressToInetAddress(env, &sockVal);
   2569         }
   2570 
   2571         case JAVASOCKOPT_IP_MULTICAST_IF2: {
   2572             if ((anOption >> 16) & BROKEN_MULTICAST_IF) {
   2573                 return NULL;
   2574             }
   2575             struct ip_mreqn multicastRequest;
   2576             int interfaceIndex = 0;
   2577             socklen_t optionLength;
   2578             int addressFamily = getSocketAddressFamily(handle);
   2579             switch (addressFamily) {
   2580                 case AF_INET:
   2581                     optionLength = sizeof(multicastRequest);
   2582                     result = getsockopt(handle, IPPROTO_IP, IP_MULTICAST_IF,
   2583                                         &multicastRequest, &optionLength);
   2584                     if (result == 0)
   2585                         interfaceIndex = multicastRequest.imr_ifindex;
   2586                     break;
   2587                 case AF_INET6:
   2588                     optionLength = sizeof(interfaceIndex);
   2589                     result = getsockopt(handle, IPPROTO_IPV6, IPV6_MULTICAST_IF,
   2590                                         &interfaceIndex, &optionLength);
   2591                     break;
   2592                 default:
   2593                     jniThrowSocketException(env, EAFNOSUPPORT);
   2594                     return NULL;
   2595             }
   2596 
   2597             if (0 != result) {
   2598                 jniThrowSocketException(env, errno);
   2599                 return NULL;
   2600             }
   2601             return newJavaLangInteger(env, interfaceIndex);
   2602         }
   2603 
   2604         case JAVASOCKOPT_IP_MULTICAST_LOOP: {
   2605             result = getOrSetSocketOption(SOCKOPT_GET, handle,
   2606                                           IP_MULTICAST_LOOP,
   2607                                           IPV6_MULTICAST_LOOP, &intValue,
   2608                                           &intSize);
   2609             if (0 != result) {
   2610                 jniThrowSocketException(env, errno);
   2611                 return NULL;
   2612             }
   2613             return newJavaLangBoolean(env, intValue);
   2614         }
   2615 #else
   2616         case JAVASOCKOPT_MCAST_TTL:
   2617         case JAVASOCKOPT_IP_MULTICAST_IF:
   2618         case JAVASOCKOPT_IP_MULTICAST_IF2:
   2619         case JAVASOCKOPT_IP_MULTICAST_LOOP: {
   2620             jniThrowException(env, "java/lang/UnsupportedOperationException", NULL);
   2621             return NULL;
   2622         }
   2623 #endif // def ENABLE_MULTICAST
   2624 
   2625         default: {
   2626             jniThrowSocketException(env, ENOPROTOOPT);
   2627             return NULL;
   2628         }
   2629     }
   2630 
   2631 }
   2632 
   2633 static void osNetworkSystem_setSocketOptionImpl(JNIEnv* env, jclass clazz,
   2634         jobject fileDescriptor, jint anOption, jobject optVal) {
   2635     // LOGD("ENTER setSocketOptionImpl");
   2636 
   2637     int result;
   2638     int intVal;
   2639     socklen_t intSize = sizeof(int);
   2640     struct sockaddr_storage sockVal;
   2641     int sockSize = sizeof(sockVal);
   2642 
   2643     if (env->IsInstanceOf(optVal, gCachedFields.integer_class)) {
   2644         intVal = (int) env->GetIntField(optVal, gCachedFields.integer_class_value);
   2645     } else if (env->IsInstanceOf(optVal, gCachedFields.boolean_class)) {
   2646         intVal = (int) env->GetBooleanField(optVal, gCachedFields.boolean_class_value);
   2647     } else if (env->IsInstanceOf(optVal, gCachedFields.byte_class)) {
   2648         // TTL uses a byte in Java, but the kernel still wants an int.
   2649         intVal = (int) env->GetByteField(optVal, gCachedFields.byte_class_value);
   2650     } else if (env->IsInstanceOf(optVal, gCachedFields.iaddr_class)) {
   2651         if (!inetAddressToSocketAddress(env, optVal, 0, &sockVal)) {
   2652             return;
   2653         }
   2654     } else if (env->IsInstanceOf(optVal, gCachedFields.genericipmreq_class)) {
   2655         // we'll use optVal directly
   2656     } else {
   2657         jniThrowSocketException(env, ENOPROTOOPT);
   2658         return;
   2659     }
   2660 
   2661     int handle;
   2662     if (!jniGetFd(env, fileDescriptor, handle)) {
   2663         return;
   2664     }
   2665 
   2666     switch ((int) anOption & 0xffff) {
   2667         case JAVASOCKOPT_SO_LINGER: {
   2668             struct linger lingr;
   2669             lingr.l_onoff = intVal > 0 ? 1 : 0;
   2670             lingr.l_linger = intVal;
   2671             result = setsockopt(handle, SOL_SOCKET, SO_LINGER, &lingr,
   2672                     sizeof(struct linger));
   2673             if (0 != result) {
   2674                 jniThrowSocketException(env, errno);
   2675                 return;
   2676             }
   2677             break;
   2678         }
   2679 
   2680         case JAVASOCKOPT_TCP_NODELAY: {
   2681             if ((anOption >> 16) & BROKEN_TCP_NODELAY) {
   2682                 return;
   2683             }
   2684             result = setsockopt(handle, IPPROTO_TCP, TCP_NODELAY, &intVal, intSize);
   2685             if (0 != result) {
   2686                 jniThrowSocketException(env, errno);
   2687                 return;
   2688             }
   2689             break;
   2690         }
   2691 
   2692         case JAVASOCKOPT_SO_SNDBUF: {
   2693             result = setsockopt(handle, SOL_SOCKET, SO_SNDBUF, &intVal, intSize);
   2694             if (0 != result) {
   2695                 jniThrowSocketException(env, errno);
   2696                 return;
   2697             }
   2698             break;
   2699         }
   2700 
   2701         case JAVASOCKOPT_SO_RCVBUF: {
   2702             result = setsockopt(handle, SOL_SOCKET, SO_RCVBUF, &intVal, intSize);
   2703             if (0 != result) {
   2704                 jniThrowSocketException(env, errno);
   2705                 return;
   2706             }
   2707             break;
   2708         }
   2709 
   2710         case JAVASOCKOPT_SO_BROADCAST: {
   2711             result = setsockopt(handle, SOL_SOCKET, SO_BROADCAST, &intVal, intSize);
   2712             if (0 != result) {
   2713                 jniThrowSocketException(env, errno);
   2714                 return;
   2715             }
   2716             break;
   2717         }
   2718 
   2719         case JAVASOCKOPT_SO_REUSEADDR: {
   2720             result = setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, &intVal, intSize);
   2721             if (0 != result) {
   2722                 jniThrowSocketException(env, errno);
   2723                 return;
   2724             }
   2725             break;
   2726         }
   2727         case JAVASOCKOPT_SO_KEEPALIVE: {
   2728             result = setsockopt(handle, SOL_SOCKET, SO_KEEPALIVE, &intVal, intSize);
   2729             if (0 != result) {
   2730                 jniThrowSocketException(env, errno);
   2731                 return;
   2732             }
   2733             break;
   2734         }
   2735 
   2736         case JAVASOCKOPT_SO_OOBINLINE: {
   2737             result = setsockopt(handle, SOL_SOCKET, SO_OOBINLINE, &intVal, intSize);
   2738             if (0 != result) {
   2739                 jniThrowSocketException(env, errno);
   2740                 return;
   2741             }
   2742             break;
   2743         }
   2744 
   2745         case JAVASOCKOPT_IP_TOS: {
   2746             result = getOrSetSocketOption(SOCKOPT_SET, handle, IP_TOS,
   2747                                           IPV6_TCLASS, &intVal, &intSize);
   2748             if (0 != result) {
   2749                 jniThrowSocketException(env, errno);
   2750                 return;
   2751             }
   2752             break;
   2753         }
   2754 
   2755         case JAVASOCKOPT_REUSEADDR_AND_REUSEPORT: {
   2756             // SO_REUSEPORT doesn't need to get set on this System
   2757             result = setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, &intVal, intSize);
   2758             if (0 != result) {
   2759                 jniThrowSocketException(env, errno);
   2760                 return;
   2761             }
   2762             break;
   2763         }
   2764 
   2765         case JAVASOCKOPT_SO_RCVTIMEOUT: {
   2766             timeval timeout(toTimeval(intVal));
   2767             result = setsockopt(handle, SOL_SOCKET, SO_RCVTIMEO, &timeout,
   2768                     sizeof(struct timeval));
   2769             if (0 != result) {
   2770                 jniThrowSocketException(env, errno);
   2771                 return;
   2772             }
   2773             break;
   2774         }
   2775 
   2776 #ifdef ENABLE_MULTICAST
   2777         case JAVASOCKOPT_MCAST_TTL: {
   2778             if ((anOption >> 16) & BROKEN_MULTICAST_TTL) {
   2779                 return;
   2780             }
   2781             result = getOrSetSocketOption(SOCKOPT_SET, handle, IP_MULTICAST_TTL,
   2782                                           IPV6_MULTICAST_HOPS, &intVal,
   2783                                           &intSize);
   2784             if (0 != result) {
   2785                 jniThrowSocketException(env, errno);
   2786                 return;
   2787             }
   2788             break;
   2789         }
   2790 
   2791         case JAVASOCKOPT_MCAST_ADD_MEMBERSHIP: {
   2792             mcastAddDropMembership(env, handle, optVal,
   2793                     (anOption >> 16) & BROKEN_MULTICAST_IF, IP_ADD_MEMBERSHIP);
   2794             break;
   2795         }
   2796 
   2797         case JAVASOCKOPT_MCAST_DROP_MEMBERSHIP: {
   2798             mcastAddDropMembership(env, handle, optVal,
   2799                     (anOption >> 16) & BROKEN_MULTICAST_IF, IP_DROP_MEMBERSHIP);
   2800             break;
   2801         }
   2802 
   2803         case JAVASOCKOPT_IP_MULTICAST_IF: {
   2804             if ((anOption >> 16) & BROKEN_MULTICAST_IF) {
   2805                 return;
   2806             }
   2807             // This call is IPv4 only. The socket may be IPv6, but the address
   2808             // that identifies the interface to join must be an IPv4 address.
   2809             if (sockVal.ss_family != AF_INET) {
   2810                 jniThrowSocketException(env, EAFNOSUPPORT);
   2811                 return;
   2812             }
   2813             struct ip_mreqn mcast_req;
   2814             memset(&mcast_req, 0, sizeof(mcast_req));
   2815             struct sockaddr_in *sin = (struct sockaddr_in *) &sockVal;
   2816             mcast_req.imr_address = sin->sin_addr;
   2817             result = setsockopt(handle, IPPROTO_IP, IP_MULTICAST_IF,
   2818                                 &mcast_req, sizeof(mcast_req));
   2819             if (0 != result) {
   2820                 jniThrowSocketException(env, errno);
   2821                 return;
   2822             }
   2823             break;
   2824         }
   2825 
   2826         case JAVASOCKOPT_IP_MULTICAST_IF2: {
   2827             if ((anOption >> 16) & BROKEN_MULTICAST_IF) {
   2828                 return;
   2829             }
   2830             int addressFamily = getSocketAddressFamily(handle);
   2831             int interfaceIndex = intVal;
   2832             void *optionValue;
   2833             socklen_t optionLength;
   2834             struct ip_mreqn multicastRequest;
   2835             switch (addressFamily) {
   2836                 case AF_INET:
   2837                     // IP_MULTICAST_IF expects a pointer to a struct ip_mreqn.
   2838                     memset(&multicastRequest, 0, sizeof(multicastRequest));
   2839                     multicastRequest.imr_ifindex = interfaceIndex;
   2840                     optionValue = &multicastRequest;
   2841                     optionLength = sizeof(multicastRequest);
   2842                     break;
   2843                 case AF_INET6:
   2844                     // IPV6_MULTICAST_IF expects a pointer to an integer.
   2845                     optionValue = &interfaceIndex;
   2846                     optionLength = sizeof(interfaceIndex);
   2847                     break;
   2848                 default:
   2849                     jniThrowSocketException(env, EAFNOSUPPORT);
   2850                     return;
   2851             }
   2852             result = getOrSetSocketOption(SOCKOPT_SET, handle,
   2853                     IP_MULTICAST_IF, IPV6_MULTICAST_IF, optionValue,
   2854                     &optionLength);
   2855             if (0 != result) {
   2856                 jniThrowSocketException(env, errno);
   2857                 return;
   2858             }
   2859             break;
   2860         }
   2861 
   2862         case JAVASOCKOPT_IP_MULTICAST_LOOP: {
   2863             result = getOrSetSocketOption(SOCKOPT_SET, handle,
   2864                                           IP_MULTICAST_LOOP,
   2865                                           IPV6_MULTICAST_LOOP, &intVal,
   2866                                           &intSize);
   2867             if (0 != result) {
   2868                 jniThrowSocketException(env, errno);
   2869                 return;
   2870             }
   2871             break;
   2872         }
   2873 #else
   2874         case JAVASOCKOPT_MCAST_TTL:
   2875         case JAVASOCKOPT_MCAST_ADD_MEMBERSHIP:
   2876         case JAVASOCKOPT_MCAST_DROP_MEMBERSHIP:
   2877         case JAVASOCKOPT_IP_MULTICAST_IF:
   2878         case JAVASOCKOPT_IP_MULTICAST_IF2:
   2879         case JAVASOCKOPT_IP_MULTICAST_LOOP: {
   2880             jniThrowException(env, "java/lang/UnsupportedOperationException", NULL);
   2881             return;
   2882         }
   2883 #endif // def ENABLE_MULTICAST
   2884 
   2885         default: {
   2886             jniThrowSocketException(env, ENOPROTOOPT);
   2887         }
   2888     }
   2889 }
   2890 
   2891 static jint osNetworkSystem_getSocketFlagsImpl(JNIEnv* env, jclass clazz) {
   2892     // LOGD("ENTER getSocketFlagsImpl");
   2893 
   2894     // Not implemented by harmony
   2895     return 0;
   2896 }
   2897 
   2898 static void osNetworkSystem_socketCloseImpl(JNIEnv* env, jclass clazz,
   2899         jobject fileDescriptor) {
   2900     // LOGD("ENTER socketCloseImpl");
   2901 
   2902     int fd;
   2903     if (!jniGetFd(env, fileDescriptor, fd)) {
   2904         return;
   2905     }
   2906 
   2907     jniSetFileDescriptorOfFD(env, fileDescriptor, -1);
   2908 
   2909     close(fd);
   2910 }
   2911 
   2912 static jobject osNetworkSystem_inheritedChannel(JNIEnv* env, jobject obj) {
   2913     // Android never has stdin/stdout connected to a socket.
   2914     return NULL;
   2915 }
   2916 
   2917 /*
   2918  * JNI registration.
   2919  */
   2920 static JNINativeMethod gMethods[] = {
   2921     /* name, signature, funcPtr */
   2922     { "createStreamSocketImpl",            "(Ljava/io/FileDescriptor;Z)V",                                             (void*) osNetworkSystem_createStreamSocketImpl             },
   2923     { "createDatagramSocketImpl",          "(Ljava/io/FileDescriptor;Z)V",                                             (void*) osNetworkSystem_createDatagramSocketImpl           },
   2924     { "readSocketImpl",                    "(Ljava/io/FileDescriptor;[BIII)I",                                         (void*) osNetworkSystem_readSocketImpl                     },
   2925     { "readSocketDirectImpl",              "(Ljava/io/FileDescriptor;III)I",                                           (void*) osNetworkSystem_readSocketDirectImpl               },
   2926     { "writeSocketImpl",                   "(Ljava/io/FileDescriptor;[BII)I",                                          (void*) osNetworkSystem_writeSocketImpl                    },
   2927     { "writeSocketDirectImpl",             "(Ljava/io/FileDescriptor;III)I",                                           (void*) osNetworkSystem_writeSocketDirectImpl              },
   2928     { "setNonBlockingImpl",                "(Ljava/io/FileDescriptor;Z)V",                                             (void*) osNetworkSystem_setNonBlockingImpl                 },
   2929     { "connectWithTimeoutSocketImpl",      "(Ljava/io/FileDescriptor;IILjava/net/InetAddress;II[B)I",                  (void*) osNetworkSystem_connectWithTimeoutSocketImpl       },
   2930     { "connectStreamWithTimeoutSocketImpl","(Ljava/io/FileDescriptor;IIILjava/net/InetAddress;)V",                     (void*) osNetworkSystem_connectStreamWithTimeoutSocketImpl },
   2931     { "socketBindImpl",                    "(Ljava/io/FileDescriptor;ILjava/net/InetAddress;)V",                       (void*) osNetworkSystem_socketBindImpl                     },
   2932     { "listenStreamSocketImpl",            "(Ljava/io/FileDescriptor;I)V",                                             (void*) osNetworkSystem_listenStreamSocketImpl             },
   2933     { "availableStreamImpl",               "(Ljava/io/FileDescriptor;)I",                                              (void*) osNetworkSystem_availableStreamImpl                },
   2934     { "acceptSocketImpl",                  "(Ljava/io/FileDescriptor;Ljava/net/SocketImpl;Ljava/io/FileDescriptor;I)V",(void*) osNetworkSystem_acceptSocketImpl                   },
   2935     { "supportsUrgentDataImpl",            "(Ljava/io/FileDescriptor;)Z",                                              (void*) osNetworkSystem_supportsUrgentDataImpl             },
   2936     { "sendUrgentDataImpl",                "(Ljava/io/FileDescriptor;B)V",                                             (void*) osNetworkSystem_sendUrgentDataImpl                 },
   2937     { "connectDatagramImpl2",              "(Ljava/io/FileDescriptor;IILjava/net/InetAddress;)V",                      (void*) osNetworkSystem_connectDatagramImpl2               },
   2938     { "disconnectDatagramImpl",            "(Ljava/io/FileDescriptor;)V",                                              (void*) osNetworkSystem_disconnectDatagramImpl             },
   2939     { "peekDatagramImpl",                  "(Ljava/io/FileDescriptor;Ljava/net/InetAddress;I)I",                       (void*) osNetworkSystem_peekDatagramImpl                   },
   2940     { "receiveDatagramImpl",               "(Ljava/io/FileDescriptor;Ljava/net/DatagramPacket;[BIIIZ)I",               (void*) osNetworkSystem_receiveDatagramImpl                },
   2941     { "receiveDatagramDirectImpl",         "(Ljava/io/FileDescriptor;Ljava/net/DatagramPacket;IIIIZ)I",                (void*) osNetworkSystem_receiveDatagramDirectImpl          },
   2942     { "recvConnectedDatagramImpl",         "(Ljava/io/FileDescriptor;Ljava/net/DatagramPacket;[BIIIZ)I",               (void*) osNetworkSystem_recvConnectedDatagramImpl          },
   2943     { "recvConnectedDatagramDirectImpl",   "(Ljava/io/FileDescriptor;Ljava/net/DatagramPacket;IIIIZ)I",                (void*) osNetworkSystem_recvConnectedDatagramDirectImpl    },
   2944     { "sendDatagramImpl",                  "(Ljava/io/FileDescriptor;[BIIIZILjava/net/InetAddress;)I",                 (void*) osNetworkSystem_sendDatagramImpl                   },
   2945     { "sendDatagramDirectImpl",            "(Ljava/io/FileDescriptor;IIIIZILjava/net/InetAddress;)I",                  (void*) osNetworkSystem_sendDatagramDirectImpl             },
   2946     { "sendConnectedDatagramImpl",         "(Ljava/io/FileDescriptor;[BIIZ)I",                                         (void*) osNetworkSystem_sendConnectedDatagramImpl          },
   2947     { "sendConnectedDatagramDirectImpl",   "(Ljava/io/FileDescriptor;IIIZ)I",                                          (void*) osNetworkSystem_sendConnectedDatagramDirectImpl    },
   2948     { "createServerStreamSocketImpl",      "(Ljava/io/FileDescriptor;Z)V",                                             (void*) osNetworkSystem_createServerStreamSocketImpl       },
   2949     { "shutdownInputImpl",                 "(Ljava/io/FileDescriptor;)V",                                              (void*) osNetworkSystem_shutdownInputImpl                  },
   2950     { "shutdownOutputImpl",                "(Ljava/io/FileDescriptor;)V",                                              (void*) osNetworkSystem_shutdownOutputImpl                 },
   2951     { "sendDatagramImpl2",                 "(Ljava/io/FileDescriptor;[BIIILjava/net/InetAddress;)I",                   (void*) osNetworkSystem_sendDatagramImpl2                  },
   2952     { "selectImpl",                        "([Ljava/io/FileDescriptor;[Ljava/io/FileDescriptor;II[IJ)Z",               (void*) osNetworkSystem_selectImpl                         },
   2953     { "getSocketLocalAddressImpl",         "(Ljava/io/FileDescriptor;)Ljava/net/InetAddress;",                         (void*) osNetworkSystem_getSocketLocalAddressImpl          },
   2954     { "getSocketLocalPortImpl",            "(Ljava/io/FileDescriptor;)I",                                              (void*) osNetworkSystem_getSocketLocalPortImpl             },
   2955     { "getSocketOptionImpl",               "(Ljava/io/FileDescriptor;I)Ljava/lang/Object;",                            (void*) osNetworkSystem_getSocketOptionImpl                },
   2956     { "setSocketOptionImpl",               "(Ljava/io/FileDescriptor;ILjava/lang/Object;)V",                           (void*) osNetworkSystem_setSocketOptionImpl                },
   2957     { "getSocketFlagsImpl",                "()I",                                                                      (void*) osNetworkSystem_getSocketFlagsImpl                 },
   2958     { "socketCloseImpl",                   "(Ljava/io/FileDescriptor;)V",                                              (void*) osNetworkSystem_socketCloseImpl                    },
   2959     { "setInetAddressImpl",                "(Ljava/net/InetAddress;[B)V",                                              (void*) osNetworkSystem_setInetAddressImpl                 },
   2960     { "inheritedChannel",                  "()Ljava/nio/channels/Channel;",                                            (void*) osNetworkSystem_inheritedChannel                   },
   2961     { "byteArrayToIpString",               "([B)Ljava/lang/String;",                                                   (void*) osNetworkSystem_byteArrayToIpString                },
   2962     { "ipStringToByteArray",               "(Ljava/lang/String;)[B",                                                   (void*) osNetworkSystem_ipStringToByteArray                },
   2963 };
   2964 
   2965 int register_org_apache_harmony_luni_platform_OSNetworkSystem(JNIEnv* env) {
   2966     return initCachedFields(env) && jniRegisterNativeMethods(env,
   2967             "org/apache/harmony/luni/platform/OSNetworkSystem",
   2968             gMethods,
   2969             NELEM(gMethods));
   2970 }
   2971 // END android-changed
   2972