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
162struct 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 */
189struct selectFDSet {
190  int nfds;
191  int sock;
192  fd_set writeSet;
193  fd_set readSet;
194  fd_set exceptionSet;
195};
196
197static 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 */
205static void throwSocketException(JNIEnv *env, int errorCode) {
206    jniThrowException(env, "java/net/SocketException",
207        netLookupErrorString(errorCode));
208}
209
210// TODO(enh): move to JNIHelp.h
211static 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
218static void jniThrowBindException(JNIEnv* env, int error) {
219    jniThrowExceptionWithErrno(env, "java/net/BindException", error);
220}
221
222static void jniThrowSocketException(JNIEnv* env, int error) {
223    jniThrowExceptionWithErrno(env, "java/net/SocketException", error);
224}
225
226static 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.
234static void jniThrowBadAddressFamily(JNIEnv* env) {
235    jniThrowException(env, "java/lang/IllegalArgumentException", "Bad address family");
236}
237
238static 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 */
250static 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 */
284static 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 */
301static 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
312jobject 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 */
329jobject 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 */
343static 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 */
372static 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 */
406static 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 */
427static 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 */
481static 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 */
558static 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 */
575static 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 */
592static 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.
597static 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.
605static 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
622static 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
642static 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
753static 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
807static 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.
837static 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 */
928static 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?
956static 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 */
1088static 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 */
1116static 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 */
1173static 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 */
1221static 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
1351static 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 */
1437static 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
1458static void osNetworkSystem_createStreamSocketImpl(JNIEnv* env, jclass clazz,
1459        jobject fileDescriptor, jboolean preferIPv4Stack) {
1460    // LOGD("ENTER createSocketImpl");
1461    createSocketFileDescriptor(env, fileDescriptor, SOCK_STREAM);
1462}
1463
1464static void osNetworkSystem_createDatagramSocketImpl(JNIEnv* env, jclass clazz,
1465        jobject fileDescriptor, jboolean preferIPv4Stack) {
1466    // LOGD("ENTER createDatagramSocketImpl");
1467    createSocketFileDescriptor(env, fileDescriptor, SOCK_DGRAM);
1468}
1469
1470static 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
1504static 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
1521static 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
1549static 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
1564static 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
1580static 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
1629static 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
1755bail:
1756
1757    /* free the memory for the FD set */
1758    if (context != NULL)  {
1759        free(context);
1760    }
1761}
1762
1763static 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
1785static 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
1801static 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
1835static 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
1886static 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
1895static 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
1910static 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
1930static 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
1949static 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
1956static 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
1990static 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
2034static 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
2058static 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
2088static 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
2113static 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
2144static 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
2158static 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
2182static 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
2195static 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
2208static 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
2219static void osNetworkSystem_shutdownInputImpl(JNIEnv* env, jobject,
2220        jobject fileDescriptor) {
2221    doShutdown(env, fileDescriptor, SHUT_RD);
2222}
2223
2224static void osNetworkSystem_shutdownOutputImpl(JNIEnv* env, jobject,
2225        jobject fileDescriptor) {
2226    doShutdown(env, fileDescriptor, SHUT_WR);
2227}
2228
2229static 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
2274static 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 */
2302static 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
2321static 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
2372static 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
2395static 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
2418static 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
2633static 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
2891static jint osNetworkSystem_getSocketFlagsImpl(JNIEnv* env, jclass clazz) {
2892    // LOGD("ENTER getSocketFlagsImpl");
2893
2894    // Not implemented by harmony
2895    return 0;
2896}
2897
2898static 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
2912static 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 */
2920static 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
2965int 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