OSDN Git Service

Unbreak Dalvik VM initialization due to a native method that expects to be able
[android-x86/dalvik.git] / libcore / luni / src / main / native / org_apache_harmony_luni_platform_OSNetworkSystem.cpp
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 #define LOG_TAG "OSNetworkSystem"
18
19 #include "JNIHelp.h"
20 #include "jni.h"
21 #include "errno.h"
22
23 #include <unistd.h>
24 #include <stdio.h>
25 #include <sys/socket.h>
26 #include <netinet/in.h>
27 #include <netinet/tcp.h>
28 #include <netdb.h>
29 #include <sys/time.h>
30 #include <stdlib.h>
31 #include <sys/ioctl.h>
32 #include <sys/un.h>
33
34 #include <cutils/properties.h>
35 #include <cutils/adb_networking.h>
36 #include "AndroidSystemNatives.h"
37
38 // Temporary hack to build on systems that don't have up-to-date libc headers.
39 #ifndef IPV6_TCLASS
40 #define IPV6_TCLASS 67
41 #endif
42
43 /**
44  * @name Socket Errors
45  * Error codes for socket operations
46  *
47  * @internal SOCKERR* range from -200 to -299 avoid overlap
48  */
49 #define SOCKERR_BADSOCKET          -200 /* generic error */
50 #define SOCKERR_NOTINITIALIZED     -201 /* socket library uninitialized */
51 #define SOCKERR_BADAF              -202 /* bad address family */
52 #define SOCKERR_BADPROTO           -203 /* bad protocol */
53 #define SOCKERR_BADTYPE            -204 /* bad type */
54 #define SOCKERR_SYSTEMBUSY         -205 /* system busy handling requests */
55 #define SOCKERR_SYSTEMFULL         -206 /* too many sockets */
56 #define SOCKERR_NOTCONNECTED       -207 /* socket is not connected */
57 #define SOCKERR_INTERRUPTED        -208 /* the call was cancelled */
58 #define SOCKERR_TIMEOUT            -209 /* the operation timed out */
59 #define SOCKERR_CONNRESET          -210 /* the connection was reset */
60 #define SOCKERR_WOULDBLOCK         -211 /* the socket is marked as nonblocking operation would block */
61 #define SOCKERR_ADDRNOTAVAIL       -212 /* address not available */
62 #define SOCKERR_ADDRINUSE          -213 /* address already in use */
63 #define SOCKERR_NOTBOUND           -214 /* the socket is not bound */
64 #define SOCKERR_UNKNOWNSOCKET      -215 /* resolution of fileDescriptor to socket failed */
65 #define SOCKERR_INVALIDTIMEOUT     -216 /* the specified timeout is invalid */
66 #define SOCKERR_FDSETFULL          -217 /* Unable to create an FDSET */
67 #define SOCKERR_TIMEVALFULL        -218 /* Unable to create a TIMEVAL */
68 #define SOCKERR_REMSOCKSHUTDOWN    -219 /* The remote socket has shutdown gracefully */
69 #define SOCKERR_NOTLISTENING       -220 /* listen() was not invoked prior to accept() */
70 #define SOCKERR_NOTSTREAMSOCK      -221 /* The socket does not support connection-oriented service */
71 #define SOCKERR_ALREADYBOUND       -222 /* The socket is already bound to an address */
72 #define SOCKERR_NBWITHLINGER       -223 /* The socket is marked non-blocking & SO_LINGER is non-zero */
73 #define SOCKERR_ISCONNECTED        -224 /* The socket is already connected */
74 #define SOCKERR_NOBUFFERS          -225 /* No buffer space is available */
75 #define SOCKERR_HOSTNOTFOUND       -226 /* Authoritative Answer Host not found */
76 #define SOCKERR_NODATA             -227 /* Valid name, no data record of requested type */
77 #define SOCKERR_BOUNDORCONN        -228 /* The socket has not been bound or is already connected */
78 #define SOCKERR_OPNOTSUPP          -229 /* The socket does not support the operation */
79 #define SOCKERR_OPTUNSUPP          -230 /* The socket option is not supported */
80 #define SOCKERR_OPTARGSINVALID     -231 /* The socket option arguments are invalid */
81 #define SOCKERR_SOCKLEVELINVALID   -232 /* The socket level is invalid */
82 #define SOCKERR_TIMEOUTFAILURE     -233
83 #define SOCKERR_SOCKADDRALLOCFAIL  -234 /* Unable to allocate the sockaddr structure */
84 #define SOCKERR_FDSET_SIZEBAD      -235 /* The calculated maximum size of the file descriptor set is bad */
85 #define SOCKERR_UNKNOWNFLAG        -236 /* The flag is unknown */
86 #define SOCKERR_MSGSIZE            -237 /* The datagram was too big to fit the specified buffer & was truncated. */
87 #define SOCKERR_NORECOVERY         -238 /* The operation failed with no recovery possible */
88 #define SOCKERR_ARGSINVALID        -239 /* The arguments are invalid */
89 #define SOCKERR_BADDESC            -240 /* The socket argument is not a valid file descriptor */
90 #define SOCKERR_NOTSOCK            -241 /* The socket argument is not a socket */
91 #define SOCKERR_HOSTENTALLOCFAIL   -242 /* Unable to allocate the hostent structure */
92 #define SOCKERR_TIMEVALALLOCFAIL   -243 /* Unable to allocate the timeval structure */
93 #define SOCKERR_LINGERALLOCFAIL    -244 /* Unable to allocate the linger structure */
94 #define SOCKERR_IPMREQALLOCFAIL    -245 /* Unable to allocate the ipmreq structure */
95 #define SOCKERR_FDSETALLOCFAIL     -246 /* Unable to allocate the fdset structure */
96 #define SOCKERR_OPFAILED           -247 /* Operation failed */
97 #define SOCKERR_VALUE_NULL         -248 /* The value indexed was NULL */
98 #define SOCKERR_CONNECTION_REFUSED -249 /* connection was refused */
99 #define SOCKERR_ENETUNREACH        -250 /* network is not reachable */
100 #define SOCKERR_EACCES             -251 /* permissions do not allow action on socket */
101 #define SOCKERR_EHOSTUNREACH       -252 /* no route to host */
102 #define SOCKERR_EPIPE              -253 /* broken pipe */
103
104 #define JAVASOCKOPT_TCP_NODELAY 1
105 #define JAVASOCKOPT_IP_TOS 3
106 #define JAVASOCKOPT_SO_REUSEADDR 4
107 #define JAVASOCKOPT_SO_KEEPALIVE 8
108 #define JAVASOCKOPT_MCAST_TIME_TO_LIVE 10 /* Currently unused */
109 #define JAVASOCKOPT_SO_BINDADDR 15
110 #define JAVASOCKOPT_MCAST_INTERFACE 16
111 #define JAVASOCKOPT_MCAST_TTL 17
112 #define JAVASOCKOPT_IP_MULTICAST_LOOP 18
113 #define JAVASOCKOPT_MCAST_ADD_MEMBERSHIP 19
114 #define JAVASOCKOPT_MCAST_DROP_MEMBERSHIP 20
115 #define JAVASOCKOPT_IP_MULTICAST_IF2 31
116 #define JAVASOCKOPT_SO_BROADCAST 32
117 #define JAVASOCKOPT_SO_LINGER 128
118 #define JAVASOCKOPT_REUSEADDR_AND_REUSEPORT  10001
119 #define JAVASOCKOPT_SO_SNDBUF 4097
120 #define JAVASOCKOPT_SO_RCVBUF 4098
121 #define JAVASOCKOPT_SO_RCVTIMEOUT  4102
122 #define JAVASOCKOPT_SO_OOBINLINE  4099
123
124 /* constants for calling multi-call functions */
125 #define SOCKET_STEP_START 10
126 #define SOCKET_STEP_CHECK 20
127 #define SOCKET_STEP_DONE 30
128
129 #define BROKEN_MULTICAST_IF 1
130 #define BROKEN_MULTICAST_TTL 2
131 #define BROKEN_TCP_NODELAY 4
132
133 #define SOCKET_CONNECT_STEP_START 0
134 #define SOCKET_CONNECT_STEP_CHECK 1
135
136 #define SOCKET_OP_NONE 0
137 #define SOCKET_OP_READ 1
138 #define SOCKET_OP_WRITE 2
139 #define SOCKET_READ_WRITE 3
140
141 #define SOCKET_MSG_PEEK 1
142 #define SOCKET_MSG_OOB 2
143
144 #define SOCKET_NOFLAGS 0
145
146 #undef BUFFERSIZE
147 #define BUFFERSIZE 2048
148
149 // wait for 500000 usec = 0.5 second
150 #define SEND_RETRY_TIME 500000
151
152 // Local constants for getOrSetSocketOption
153 #define SOCKOPT_GET 1
154 #define SOCKOPT_SET 2
155
156 struct CachedFields {
157     jfieldID fd_descriptor;
158     jclass iaddr_class;
159     jmethodID iaddr_getbyaddress;
160     jclass i4addr_class;
161     jmethodID i4addr_class_init;
162     jfieldID iaddr_ipaddress;
163     jclass genericipmreq_class;
164     jclass integer_class;
165     jmethodID integer_class_init;
166     jfieldID integer_class_value;
167     jclass boolean_class;
168     jmethodID boolean_class_init;
169     jfieldID boolean_class_value;
170     jclass byte_class;
171     jmethodID byte_class_init;
172     jfieldID byte_class_value;
173     jclass string_class;
174     jmethodID string_class_init;
175     jfieldID socketimpl_address;
176     jfieldID socketimpl_port;
177     jclass dpack_class;
178     jfieldID dpack_address;
179     jfieldID dpack_port;
180     jfieldID dpack_length;
181 } gCachedFields;
182
183 static int useAdbNetworking = 0;
184
185 /* needed for connecting with timeout */
186 typedef struct selectFDSet {
187   int nfds;
188   int sock;
189   fd_set writeSet;
190   fd_set readSet;
191   fd_set exceptionSet;
192 } selectFDSet;
193
194 static const char * netLookupErrorString(int anErrorNum);
195
196 /**
197  * Throws an SocketException with the message affiliated with the errorCode.
198  */
199 static void throwSocketException(JNIEnv *env, int errorCode) {
200     jniThrowException(env, "java/net/SocketException",
201         netLookupErrorString(errorCode));
202 }
203
204 /**
205  * Throws an IOException with the given message.
206  */
207 static void throwIOExceptionStr(JNIEnv *env, const char *message) {
208     jniThrowException(env, "java/io/IOException", message);
209 }
210
211 /**
212  * Throws a NullPointerException.
213  */
214 static void throwNullPointerException(JNIEnv *env) {
215     jniThrowException(env, "java/lang/NullPointerException", NULL);
216 }
217
218 /**
219  * Converts a 4-byte array to a native address structure. Throws a
220  * NullPointerException or an IOException in case of error. This is
221  * signaled by a return value of -1. The normal return value is 0.
222  */
223 static int javaAddressToStructIn(
224         JNIEnv *env, jbyteArray java_address, struct in_addr *address) {
225
226     memset(address, 0, sizeof(address));
227
228     if (java_address == NULL) {
229         return -1;
230     }
231
232     if (env->GetArrayLength(java_address) != sizeof(address->s_addr)) {
233         return -1;
234     }
235
236     jbyte * java_address_bytes
237         =  env->GetByteArrayElements(java_address, NULL);
238
239     memcpy(&(address->s_addr),
240         java_address_bytes,
241         sizeof(address->s_addr));
242
243     env->ReleaseByteArrayElements(java_address, java_address_bytes, JNI_ABORT);
244
245     return 0;
246 }
247
248 /**
249  * Converts a native address structure to a Java byte array. Throws a
250  * NullPointerException or an IOException in case of error. This is
251  * signaled by a return value of -1. The normal return value is 0.
252  *
253  * @param address the sockaddr_storage structure to convert
254  *
255  * @exception SocketException the address family is unknown, or out of memory
256  *
257  */
258 static jbyteArray socketAddressToAddressBytes(JNIEnv *env,
259         struct sockaddr_storage *address) {
260
261     void *rawAddress;
262     size_t addressLength;
263     if (address->ss_family == AF_INET) {
264         struct sockaddr_in *sin = (struct sockaddr_in *) address;
265         rawAddress = &sin->sin_addr.s_addr;
266         addressLength = 4;
267     } else if (address->ss_family == AF_INET6) {
268         struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) address;
269         rawAddress = &sin6->sin6_addr.s6_addr;
270         addressLength = 16;
271     } else {
272         throwSocketException(env, SOCKERR_BADAF);
273         return NULL;
274     }
275
276     jbyteArray byteArray = env->NewByteArray(addressLength);
277     if (byteArray == NULL) {
278         throwSocketException(env, SOCKERR_NOBUFFERS);
279         return NULL;
280     }
281     env->SetByteArrayRegion(byteArray, 0, addressLength, (jbyte *) rawAddress);
282
283     return byteArray;
284 }
285
286 /**
287  * Returns the port number in a sockaddr_storage structure.
288  *
289  * @param address the sockaddr_storage structure to get the port from
290  *
291  * @return the port number, or -1 if the address family is unknown.
292  */
293 static int getSocketAddressPort(struct sockaddr_storage *address) {
294     switch (address->ss_family) {
295         case AF_INET:
296             return ntohs(((struct sockaddr_in *) address)->sin_port);
297         case AF_INET6:
298             return ntohs(((struct sockaddr_in6 *) address)->sin6_port);
299         default:
300             return -1;
301     }
302 }
303
304 /**
305  * Converts a native address structure to an InetAddress object.
306  * Throws a NullPointerException or an IOException in case of
307  * error. This is signaled by a return value of -1. The normal
308  * return value is 0.
309  *
310  * @param sockaddress the sockaddr_storage structure to convert
311  *
312  * @return a jobject representing an InetAddress
313  */
314 static jobject socketAddressToInetAddress(JNIEnv *env,
315         struct sockaddr_storage *sockaddress) {
316
317     jbyteArray byteArray = socketAddressToAddressBytes(env, sockaddress);
318     if (byteArray == NULL)  // Exception has already been thrown.
319         return NULL;
320
321     return env->CallStaticObjectMethod(gCachedFields.iaddr_class,
322             gCachedFields.iaddr_getbyaddress, byteArray);
323 }
324
325 /**
326  * Converts an InetAddress object and port number to a native address structure.
327  * Throws a NullPointerException or a SocketException in case of
328  * error. This is signaled by a return value of -1. The normal
329  * return value is 0.
330  *
331  * @param inetaddress the InetAddress object to convert
332  * @param port the port number
333  * @param sockaddress the sockaddr_storage structure to write to
334  *
335  * @return 0 on success, -1 on failure
336  *
337  * @exception SocketError if the address family is unknown
338  */
339 static int inetAddressToSocketAddress(JNIEnv *env,
340         jobject inetaddress, int port, struct sockaddr_storage *sockaddress) {
341
342     // Get the byte array that stores the IP address bytes in the InetAddress.
343     jbyteArray addressByteArray;
344     addressByteArray = (jbyteArray)env->GetObjectField(inetaddress,
345             gCachedFields.iaddr_ipaddress);
346     if (addressByteArray == NULL) {
347       throwNullPointerException(env);
348       return -1;
349     }
350
351     // Get the raw IP address bytes.
352     jbyte *addressBytes = env->GetByteArrayElements(addressByteArray, NULL);
353     if (addressBytes == NULL) {
354       throwNullPointerException(env);
355       return -1;
356     }
357
358     // Convert the IP address bytes to the proper IP address type.
359     size_t addressLength = env->GetArrayLength(addressByteArray);
360     int result = 0;
361     if (addressLength == 4) {
362         // IPv4 address.
363         struct sockaddr_in *sin = (struct sockaddr_in *) sockaddress;
364         memset(sin, 0, sizeof(struct sockaddr_in));
365         sin->sin_family = AF_INET;
366         sin->sin_port = htons(port);
367         memcpy(&sin->sin_addr.s_addr, addressBytes, 4);
368     } else if (addressLength == 16) {
369         // IPv6 address.
370         struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sockaddress;
371         memset(sin6, 0, sizeof(struct sockaddr_in6));
372         sin6->sin6_family = AF_INET6;
373         sin6->sin6_port = htons(port);
374         memcpy(&sin6->sin6_addr.s6_addr, addressBytes, 16);
375     } else {
376         // Unknown address family.
377         throwSocketException(env, SOCKERR_BADAF);
378         result = -1;
379     }
380     env->ReleaseByteArrayElements(addressByteArray, addressBytes, 0);
381     return result;
382 }
383
384 /**
385  * Answer a new java.lang.Boolean object.
386  *
387  * @param env   pointer to the JNI library
388  * @param anInt the Boolean constructor argument
389  *
390  * @return  the new Boolean
391  */
392
393 jobject newJavaLangBoolean(JNIEnv * env, jint anInt) {
394     jclass tempClass;
395     jmethodID tempMethod;
396
397     tempClass = gCachedFields.boolean_class;
398     tempMethod = gCachedFields.boolean_class_init;
399     return env->NewObject(tempClass, tempMethod, (jboolean) (anInt != 0));
400 }
401
402 /**
403  * Answer a new java.lang.Byte object.
404  *
405  * @param env   pointer to the JNI library
406  * @param anInt the Byte constructor argument
407  *
408  * @return  the new Byte
409  */
410
411 jobject newJavaLangByte(JNIEnv * env, jbyte val) {
412     jclass tempClass;
413     jmethodID tempMethod;
414
415     tempClass = gCachedFields.byte_class;
416     tempMethod = gCachedFields.byte_class_init;
417     return env->NewObject(tempClass, tempMethod, val);
418 }
419
420 /**
421  * Answer a new java.lang.Integer object.
422  *
423  * @param env   pointer to the JNI library
424  * @param anInt the Integer constructor argument
425  *
426  * @return  the new Integer
427  */
428
429 jobject newJavaLangInteger(JNIEnv * env, jint anInt) {
430     jclass tempClass;
431     jmethodID tempMethod;
432
433     tempClass = gCachedFields.integer_class;
434     tempMethod = gCachedFields.integer_class_init;
435     return env->NewObject(tempClass, tempMethod, anInt);
436 }
437
438 /**
439  * Answer a new java.lang.String object.
440  *
441  * @param env   pointer to the JNI library
442  * @param anInt the byte[] constructor argument
443  *
444  * @return  the new String
445  */
446
447 jobject newJavaLangString(JNIEnv * env, jbyteArray bytes) {
448     jclass tempClass;
449     jmethodID tempMethod;
450
451     tempClass = gCachedFields.string_class;
452     tempMethod = gCachedFields.string_class_init;
453     return env->NewObject(tempClass, tempMethod, (jbyteArray) bytes);
454 }
455
456 /**
457  * Query OS for timestamp.
458  * Retrieve the current value of system clock and convert to milliseconds.
459  *
460  * @param[in] portLibrary The port library.
461  *
462  * @return 0 on failure, time value in milliseconds on success.
463  * @deprecated Use @ref time_hires_clock and @ref time_hires_delta
464  *
465  * technically, this should return I_64 since both timeval.tv_sec and
466  * timeval.tv_usec are long
467  */
468
469 static int time_msec_clock() {
470     struct timeval tp;
471     struct timezone tzp;
472
473     gettimeofday(&tp, &tzp);
474     return (tp.tv_sec * 1000) + (tp.tv_usec / 1000);
475 }
476
477 /**
478  * Check if the passed sockaddr_storage struct contains a localhost address
479  *
480  * @param address address pointer to the address to check
481  *
482  * @return 0 if the passed address isn't a localhost address
483  */
484 static int isLocalHost(struct sockaddr_storage *address) {
485     if (address->ss_family == AF_INET) {
486         struct sockaddr_in *sin = (struct sockaddr_in *) address;
487         return (sin->sin_addr.s_addr == htonl(INADDR_LOOPBACK));
488     } else if (address->ss_family == AF_INET6) {
489         struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) address;
490         return IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr);
491     } else {
492         return 0;
493     }
494 }
495
496 /**
497  * Decide whether to use ADB networking for the given socket address.
498  *
499  * @param address pointer to sockaddr_storage structure to check
500  *
501  * @return true if ADB networking should be used, false otherwise.
502  */
503 static bool useAdbNetworkingForAddress(struct sockaddr_storage *address) {
504     return useAdbNetworking && !isLocalHost(address) &&
505            address->ss_family == AF_INET;
506 }
507
508 /**
509  * Convert a sockaddr_storage structure to a string for logging purposes.
510  *
511  * @param address pointer to sockaddr_storage structure to print
512  *
513  * @return a string with the textual representation of the address.
514  *
515  * @note Returns a statically allocated buffer, so is not thread-safe.
516  */
517 static char *socketAddressToString(struct sockaddr_storage *address) {
518     static char invalidString[] = "<invalid>";
519     static char ipString[INET6_ADDRSTRLEN + sizeof("[]:65535")];
520
521     char tmp[INET6_ADDRSTRLEN];
522     int port;
523     // TODO: getnameinfo seems to want its length parameter to be exactly
524     // sizeof(sockaddr_in) for an IPv4 address and sizeof (sockaddr_in6) for an
525     // IPv6 address. Fix getnameinfo so it accepts sizeof(sockaddr_storage), and
526     // then remove this hack.
527     int size = (address->ss_family == AF_INET) ?
528             sizeof(sockaddr_in) : sizeof(sockaddr_in6);
529     int result = getnameinfo((struct sockaddr *)address,
530             size, tmp, sizeof(tmp), NULL, 0,
531             NI_NUMERICHOST);
532
533     if (result != 0)
534         return invalidString;
535
536     if (address->ss_family == AF_INET6) {
537         struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) address;
538         port = ntohs(sin6->sin6_port);
539         sprintf(ipString, "[%s]:%d", tmp, port);
540         return ipString;
541     } else if (address->ss_family == AF_INET) {
542         struct sockaddr_in *sin = (struct sockaddr_in *) address;
543         port = ntohs(sin->sin_port);
544         sprintf(ipString, "%s:%d", tmp, port);
545         return ipString;
546     } else {
547         return invalidString;
548     }
549 }
550
551 /**
552  * Answer the errorString corresponding to the errorNumber, if available.
553  * This function will answer a default error string, if the errorNumber is not
554  * recognized.
555  *
556  * This function will have to be reworked to handle internationalization
557  * properly, removing the explicit strings.
558  *
559  * @param anErrorNum    the error code to resolve to a human readable string
560  *
561  * @return  a human readable error string
562  */
563
564 static const char * netLookupErrorString(int anErrorNum) {
565     switch (anErrorNum) {
566         case SOCKERR_BADSOCKET:
567             return "Bad socket";
568         case SOCKERR_NOTINITIALIZED:
569             return "Socket library uninitialized";
570         case SOCKERR_BADAF:
571             return "Bad address family";
572         case SOCKERR_BADPROTO:
573             return "Bad protocol";
574         case SOCKERR_BADTYPE:
575             return "Bad type";
576         case SOCKERR_SYSTEMBUSY:
577             return "System busy handling requests";
578         case SOCKERR_SYSTEMFULL:
579             return "Too many sockets allocated";
580         case SOCKERR_NOTCONNECTED:
581             return "Socket is not connected";
582         case SOCKERR_INTERRUPTED:
583             return "The system call was cancelled";
584         case SOCKERR_TIMEOUT:
585             return "The operation timed out";
586         case SOCKERR_CONNRESET:
587             return "The connection was reset";
588         case SOCKERR_WOULDBLOCK:
589             return "The nonblocking operation would block";
590         case SOCKERR_ADDRNOTAVAIL:
591             return "The address is not available";
592         case SOCKERR_ADDRINUSE:
593             return "The address is already in use";
594         case SOCKERR_NOTBOUND:
595             return "The socket is not bound";
596         case SOCKERR_UNKNOWNSOCKET:
597             return "Resolution of the FileDescriptor to socket failed";
598         case SOCKERR_INVALIDTIMEOUT:
599             return "The specified timeout is invalid";
600         case SOCKERR_FDSETFULL:
601             return "Unable to create an FDSET";
602         case SOCKERR_TIMEVALFULL:
603             return "Unable to create a TIMEVAL";
604         case SOCKERR_REMSOCKSHUTDOWN:
605             return "The remote socket has shutdown gracefully";
606         case SOCKERR_NOTLISTENING:
607             return "Listen() was not invoked prior to accept()";
608         case SOCKERR_NOTSTREAMSOCK:
609             return "The socket does not support connection-oriented service";
610         case SOCKERR_ALREADYBOUND:
611             return "The socket is already bound to an address";
612         case SOCKERR_NBWITHLINGER:
613             return "The socket is marked non-blocking & SO_LINGER is non-zero";
614         case SOCKERR_ISCONNECTED:
615             return "The socket is already connected";
616         case SOCKERR_NOBUFFERS:
617             return "No buffer space is available";
618         case SOCKERR_HOSTNOTFOUND:
619             return "Authoritative Answer Host not found";
620         case SOCKERR_NODATA:
621             return "Valid name, no data record of requested type";
622         case SOCKERR_BOUNDORCONN:
623             return "The socket has not been bound or is already connected";
624         case SOCKERR_OPNOTSUPP:
625             return "The socket does not support the operation";
626         case SOCKERR_OPTUNSUPP:
627             return "The socket option is not supported";
628         case SOCKERR_OPTARGSINVALID:
629             return "The socket option arguments are invalid";
630         case SOCKERR_SOCKLEVELINVALID:
631             return "The socket level is invalid";
632         case SOCKERR_TIMEOUTFAILURE:
633             return "The timeout operation failed";
634         case SOCKERR_SOCKADDRALLOCFAIL:
635             return "Failed to allocate address structure";
636         case SOCKERR_FDSET_SIZEBAD:
637             return "The calculated maximum size of the file descriptor set is bad";
638         case SOCKERR_UNKNOWNFLAG:
639             return "The flag is unknown";
640         case SOCKERR_MSGSIZE:
641             return "The datagram was too big to fit the specified buffer, so truncated";
642         case SOCKERR_NORECOVERY:
643             return "The operation failed with no recovery possible";
644         case SOCKERR_ARGSINVALID:
645             return "The arguments are invalid";
646         case SOCKERR_BADDESC:
647             return "The socket argument is not a valid file descriptor";
648         case SOCKERR_NOTSOCK:
649             return "The socket argument is not a socket";
650         case SOCKERR_HOSTENTALLOCFAIL:
651             return "Unable to allocate the hostent structure";
652         case SOCKERR_TIMEVALALLOCFAIL:
653             return "Unable to allocate the timeval structure";
654         case SOCKERR_LINGERALLOCFAIL:
655             return "Unable to allocate the linger structure";
656         case SOCKERR_IPMREQALLOCFAIL:
657             return "Unable to allocate the ipmreq structure";
658         case SOCKERR_FDSETALLOCFAIL:
659             return "Unable to allocate the fdset structure";
660         case SOCKERR_OPFAILED:
661             return "Operation failed";
662         case SOCKERR_CONNECTION_REFUSED:
663             return "Connection refused";
664         case SOCKERR_ENETUNREACH:
665             return "Network unreachable";
666         case SOCKERR_EHOSTUNREACH:
667             return "No route to host";
668         case SOCKERR_EPIPE:
669             return "Broken pipe";
670         case SOCKERR_EACCES:
671             return "Permission denied (maybe missing INTERNET permission)";
672
673         default:
674             LOGE("unknown socket error %d", anErrorNum);
675             return "unknown error";
676     }
677 }
678
679 static int convertError(int errorCode) {
680     switch (errorCode) {
681         case EBADF:
682             return SOCKERR_BADDESC;
683         case ENOBUFS:
684             return SOCKERR_NOBUFFERS;
685         case EOPNOTSUPP:
686             return SOCKERR_OPNOTSUPP;
687         case ENOPROTOOPT:
688             return SOCKERR_OPTUNSUPP;
689         case EINVAL:
690             return SOCKERR_SOCKLEVELINVALID;
691         case ENOTSOCK:
692             return SOCKERR_NOTSOCK;
693         case EINTR:
694             return SOCKERR_INTERRUPTED;
695         case ENOTCONN:
696             return SOCKERR_NOTCONNECTED;
697         case EAFNOSUPPORT:
698             return SOCKERR_BADAF;
699             /* note: CONNRESET not included because it has the same
700              * value as ECONNRESET and they both map to SOCKERR_CONNRESET */
701         case ECONNRESET:
702             return SOCKERR_CONNRESET;
703         case EAGAIN:
704             return SOCKERR_WOULDBLOCK;
705         case EPROTONOSUPPORT:
706             return SOCKERR_BADPROTO;
707         case EFAULT:
708             return SOCKERR_ARGSINVALID;
709         case ETIMEDOUT:
710             return SOCKERR_TIMEOUT;
711         case ECONNREFUSED:
712             return SOCKERR_CONNECTION_REFUSED;
713         case ENETUNREACH:
714             return SOCKERR_ENETUNREACH;
715         case EACCES:
716             return SOCKERR_EACCES;
717         case EPIPE:
718             return SOCKERR_EPIPE;
719         case EHOSTUNREACH:
720             return SOCKERR_EHOSTUNREACH;
721         case EADDRINUSE:
722             return SOCKERR_ADDRINUSE;
723         case EADDRNOTAVAIL:
724             return SOCKERR_ADDRNOTAVAIL;
725         case EMSGSIZE:
726             return SOCKERR_MSGSIZE;
727         default:
728             LOGE("unclassified errno %d (%s)", errorCode, strerror(errorCode));
729             return SOCKERR_OPFAILED;
730     }
731 }
732
733 static int sockSelect(int nfds, fd_set *readfds, fd_set *writefds,
734         fd_set *exceptfds, struct timeval *timeout) {
735
736     int result = select(nfds, readfds, writefds, exceptfds, timeout);
737
738     if (result < 0) {
739         if (errno == EINTR) {
740             result = SOCKERR_INTERRUPTED;
741         } else {
742             result = SOCKERR_OPFAILED;
743         }
744     } else if (result == 0) {
745         result = SOCKERR_TIMEOUT;
746     }
747     return result;
748 }
749
750 #define SELECT_READ_TYPE 0
751 #define SELECT_WRITE_TYPE 1
752
753 static int selectWait(int handle, int uSecTime, int type) {
754     fd_set fdset;
755     struct timeval time, *timePtr;
756     int result = 0;
757     int size = handle + 1;
758
759     FD_ZERO(&fdset);
760     FD_SET(handle, &fdset);
761
762     if (0 <= uSecTime) {
763         /* Use a timeout if uSecTime >= 0 */
764         memset(&time, 0, sizeof(time));
765         time.tv_usec = uSecTime;
766         timePtr = &time;
767     } else {
768         /* Infinite timeout if uSecTime < 0 */
769         timePtr = NULL;
770     }
771
772     if (type == SELECT_READ_TYPE) {
773         result = sockSelect(size, &fdset, NULL, NULL, timePtr);
774     } else {
775         result = sockSelect(size, NULL, &fdset, NULL, timePtr);
776     }
777     return result;
778 }
779
780 static int pollSelectWait(JNIEnv *env, jobject fileDescriptor, int timeout, int type) {
781     /* now try reading the socket for the timespan timeout.
782      * if timeout is 0 try forever until the soclets gets ready or until an
783      * exception occurs.
784      */
785     int pollTimeoutUSec = 100000, pollMsec = 100;
786     int finishTime = 0;
787     int timeLeft = timeout;
788     int hasTimeout = timeout > 0 ? 1 : 0;
789     int result = 0;
790     int handle;
791
792     if (hasTimeout) {
793         finishTime = time_msec_clock() + timeout;
794     }
795
796     int poll = 1;
797
798     while (poll) { /* begin polling loop */
799
800         /*
801          * Fetch the handle every time in case the socket is closed.
802          */
803         handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
804
805         if (handle == 0 || handle == -1) {
806             throwSocketException(env, SOCKERR_INTERRUPTED);
807             return -1;
808         }
809
810         if (hasTimeout) {
811
812             if (timeLeft - 10 < pollMsec) {
813                 pollTimeoutUSec = timeLeft <= 0 ? 0 : (timeLeft * 1000);
814             }
815
816             result = selectWait(handle, pollTimeoutUSec, type);
817
818             /*
819              * because we are polling at a time smaller than timeout
820              * (presumably) lets treat an interrupt and timeout the same - go
821              * see if we're done timewise, and then just try again if not.
822              */
823             if (SOCKERR_TIMEOUT == result ||
824                 SOCKERR_INTERRUPTED == result) {
825
826                 timeLeft = finishTime - time_msec_clock();
827
828                 if (timeLeft <= 0) {
829                     /*
830                      * Always throw the "timeout" message because that is
831                      * effectively what has happened, even if we happen to
832                      * have been interrupted.
833                      */
834                     jniThrowException(env, "java/net/SocketTimeoutException",
835                             netLookupErrorString(SOCKERR_TIMEOUT));
836                 } else {
837                     continue; // try again
838                 }
839
840             } else if (0 > result) {
841                 throwSocketException(env, result);
842             }
843             poll = 0;
844
845         } else { /* polling with no timeout (why would you do this?)*/
846
847             result = selectWait(handle, pollTimeoutUSec, type);
848
849             /*
850              *  if interrupted (or a timeout) just retry
851              */
852             if (SOCKERR_TIMEOUT == result ||
853                SOCKERR_INTERRUPTED == result) {
854
855                 continue; // try again
856             } else if (0 > result) {
857                 throwSocketException(env, result);
858             }
859             poll = 0;
860         }
861     } /* end polling loop */
862
863     return result;
864 }
865
866 /**
867  * Obtain the socket address family from an existing socket.
868  *
869  * @param socket the filedescriptor of the socket to examine
870  *
871  * @return an integer, the address family of the socket
872  */
873 static int getSocketAddressFamily(int socket) {
874   struct sockaddr_storage ss;
875   socklen_t namelen = sizeof(ss);
876   int ret = getsockname(socket, (struct sockaddr*) &ss, &namelen);
877   if (ret != 0) {
878     return AF_UNSPEC;
879   } else {
880     return ss.ss_family;
881   }
882 }
883
884 /**
885  * A helper method, to set the connect context to a Long object.
886  *
887  * @param env  pointer to the JNI library
888  * @param longclass Java Long Object
889  */
890 void setConnectContext(JNIEnv *env,jobject longclass,jbyte * context) {
891     jclass descriptorCLS;
892     jfieldID descriptorFID;
893     descriptorCLS = env->FindClass("java/lang/Long");
894     descriptorFID = env->GetFieldID(descriptorCLS, "value", "J");
895     env->SetLongField(longclass, descriptorFID, (jlong)((jint)context));
896 };
897
898 /**
899  * A helper method, to get the connect context.
900  *
901  * @param env  pointer to the JNI library
902  * @param longclass Java Long Object
903  */
904 jbyte *getConnectContext(JNIEnv *env, jobject longclass) {
905     jclass descriptorCLS;
906     jfieldID descriptorFID;
907     descriptorCLS = env->FindClass("java/lang/Long");
908     descriptorFID = env->GetFieldID(descriptorCLS, "value", "J");
909     return (jbyte*) ((jint)env->GetLongField(longclass, descriptorFID));
910 };
911
912 // typical ip checksum
913 unsigned short ip_checksum(unsigned short* buffer, int size) {
914     register unsigned short * buf = buffer;
915     register int bufleft = size;
916     register unsigned long sum = 0;
917
918     while (bufleft > 1) {
919         sum = sum + (*buf++);
920         bufleft = bufleft - sizeof(unsigned short );
921     }
922     if (bufleft) {
923         sum = sum + (*(unsigned char*)buf);
924     }
925     sum = (sum >> 16) + (sum & 0xffff);
926     sum += (sum >> 16);
927
928     return (unsigned short )(~sum);
929 }
930
931 /**
932  * Converts an IPv4 address to an IPv4-mapped IPv6 address. Performs no error
933  * checking.
934  *
935  * @param address the address to convert. Must contain an IPv4 address.
936  * @param outputAddress the converted address. Will contain an IPv6 address.
937  * @param mapUnspecified if true, convert 0.0.0.0 to ::ffff:0:0; if false, to ::
938  */
939 static void ipv4ToMappedAddress(struct sockaddr_storage *address,
940         struct sockaddr_storage *outputAddress, bool mapUnspecified) {
941   memset(outputAddress, 0, sizeof(struct sockaddr_storage));
942   const struct sockaddr_in *sin = ((struct sockaddr_in *) address);
943   struct sockaddr_in6 *sin6 = ((struct sockaddr_in6 *) outputAddress);
944   sin6->sin6_family = AF_INET6;
945   sin6->sin6_addr.s6_addr32[3] = sin->sin_addr.s_addr;
946   if (sin->sin_addr.s_addr != 0  || mapUnspecified) {
947       sin6->sin6_addr.s6_addr32[2] = htonl(0xffff);
948   }
949   sin6->sin6_port = sin->sin_port;
950 }
951
952 /**
953  * Wrapper for connect() that converts IPv4 addresses to IPv4-mapped IPv6
954  * addresses if necessary.
955  *
956  * @param socket the filedescriptor of the socket to connect
957  * @param socketAddress the address to connect to
958  */
959 static int doConnect(int socket, struct sockaddr_storage *socketAddress) {
960     struct sockaddr_storage mappedAddress;
961     struct sockaddr_storage *realAddress;
962     if (socketAddress->ss_family == AF_INET &&
963         getSocketAddressFamily(socket) == AF_INET6) {
964         ipv4ToMappedAddress(socketAddress, &mappedAddress, true);
965         realAddress = &mappedAddress;
966     } else {
967         realAddress = socketAddress;
968     }
969     int ret;
970     do {
971         ret = connect(socket, (struct sockaddr *) realAddress,
972                 sizeof(struct sockaddr_storage));
973     } while (ret < 0 && errno == EINTR);
974     return ret;
975 }
976
977 /**
978  * Wrapper for bind() that converts IPv4 addresses to IPv4-mapped IPv6
979  * addresses if necessary.
980  *
981  * @param socket the filedescriptor of the socket to connect
982  * @param socketAddress the address to connect to
983  */
984 static int doBind(int socket, struct sockaddr_storage *socketAddress) {
985     struct sockaddr_storage mappedAddress;
986     struct sockaddr_storage *realAddress;
987     if (socketAddress->ss_family == AF_INET &&
988         getSocketAddressFamily(socket) == AF_INET6) {
989         ipv4ToMappedAddress(socketAddress, &mappedAddress, false);
990         realAddress = &mappedAddress;
991     } else {
992         realAddress = socketAddress;
993     }
994     int ret;
995     do {
996         ret = bind(socket, (struct sockaddr *) realAddress,
997                 sizeof(struct sockaddr_storage));
998     } while (ret < 0 && errno == EINTR);
999     return ret;
1000 }
1001
1002 /**
1003  * Establish a connection to a peer with a timeout.  This function is called
1004  * repeatedly in order to carry out the connect and to allow other tasks to
1005  * proceed on certain platforms. The caller must first call with
1006  * step = SOCKET_STEP_START, if the result is SOCKERR_NOTCONNECTED it will then
1007  * call it with step = CHECK until either another error or 0 is returned to
1008  * indicate the connect is complete.  Each time the function should sleep for no
1009  * more than timeout milliseconds.  If the connect succeeds or an error occurs,
1010  * the caller must always end the process by calling the function with
1011  * step = SOCKET_STEP_DONE
1012  *
1013  * @param[in] portLibrary The port library.
1014  * @param[in] sock pointer to the unconnected local socket.
1015  * @param[in] addr pointer to the sockaddr, specifying remote host/port.
1016  * @param[in] timeout the timeout in milliseconds. If timeout is negative,
1017  *         perform a block operation.
1018  * @param[in,out] pointer to context pointer. Filled in on first call and then
1019  *         to be passed into each subsequent call.
1020  *
1021  * @return 0, if no errors occurred, otherwise the (negative) error code.
1022  */
1023 static int sockConnectWithTimeout(int handle, struct sockaddr_storage addr,
1024         unsigned int timeout, unsigned int step, jbyte *ctxt) {
1025     int rc = 0;
1026     struct timeval passedTimeout;
1027     int errorVal;
1028     socklen_t errorValLen = sizeof(int);
1029     struct selectFDSet *context = NULL;
1030
1031     if (SOCKET_STEP_START == step) {
1032
1033         context = (struct selectFDSet *) ctxt;
1034
1035         context->sock = handle;
1036         context->nfds = handle + 1;
1037
1038         if (useAdbNetworkingForAddress(&addr)) {
1039
1040             // LOGD("+connect to address 0x%08x (via adb)",
1041             //         addr.sin_addr.s_addr);
1042             rc = adb_networking_connect_fd(handle, (struct sockaddr_in *) &addr);
1043             // LOGD("-connect ret %d errno %d (via adb)", rc, errno);
1044
1045         } else {
1046             /* set the socket to non-blocking */
1047             int block = JNI_TRUE;
1048             rc = ioctl(handle, FIONBIO, &block);
1049             if (0 != rc) {
1050                 return convertError(rc);
1051             }
1052
1053             // LOGD("+connect to address 0x%08x (via normal) on handle %d",
1054             //         addr.sin_addr.s_addr, handle);
1055             rc = doConnect(handle, &addr);
1056             // LOGD("-connect to address 0x%08x (via normal) returned %d",
1057             //         addr.sin_addr.s_addr, (int) rc);
1058
1059         }
1060
1061         if (rc == -1) {
1062             rc = errno;
1063             switch (rc) {
1064                 case EINTR:
1065                     return SOCKERR_ALREADYBOUND;
1066                 case EAGAIN:
1067                 case EINPROGRESS:
1068                     return SOCKERR_NOTCONNECTED;
1069                 default:
1070                     return convertError(rc);
1071             }
1072         }
1073
1074         /* we connected right off the bat so just return */
1075         return rc;
1076
1077     } else if (SOCKET_STEP_CHECK == step) {
1078         /* now check if we have connected yet */
1079
1080         context = (struct selectFDSet *) ctxt;
1081
1082         /*
1083          * set the timeout value to be used. Because on some unix platforms we
1084          * don't get notified when a socket is closed we only sleep for 100ms
1085          * at a time
1086          */
1087         passedTimeout.tv_sec = 0;
1088         if (timeout > 100) {
1089             passedTimeout.tv_usec = 100 * 1000;
1090         } else if ((int)timeout >= 0) {
1091           passedTimeout.tv_usec = timeout * 1000;
1092         }
1093
1094         /* initialize the FD sets for the select */
1095         FD_ZERO(&(context->exceptionSet));
1096         FD_ZERO(&(context->writeSet));
1097         FD_ZERO(&(context->readSet));
1098         FD_SET(context->sock, &(context->writeSet));
1099         FD_SET(context->sock, &(context->readSet));
1100         FD_SET(context->sock, &(context->exceptionSet));
1101
1102         rc = select(context->nfds,
1103                    &(context->readSet),
1104                    &(context->writeSet),
1105                    &(context->exceptionSet),
1106                    (int)timeout >= 0 ? &passedTimeout : NULL);
1107
1108         /* if there is at least one descriptor ready to be checked */
1109         if (0 < rc) {
1110             /* if the descriptor is in the write set we connected or failed */
1111             if (FD_ISSET(context->sock, &(context->writeSet))) {
1112
1113                 if (!FD_ISSET(context->sock, &(context->readSet))) {
1114                     /* ok we have connected ok */
1115                     return 0;
1116                 } else {
1117                     /* ok we have more work to do to figure it out */
1118                     if (getsockopt(context->sock, SOL_SOCKET, SO_ERROR,
1119                             &errorVal, &errorValLen) >= 0) {
1120                         return errorVal ? convertError(errorVal) : 0;
1121                     } else {
1122                         return convertError(errno);
1123                     }
1124                 }
1125             }
1126
1127             /* if the descriptor is in the exception set the connect failed */
1128             if (FD_ISSET(context->sock, &(context->exceptionSet))) {
1129                 if (getsockopt(context->sock, SOL_SOCKET, SO_ERROR, &errorVal,
1130                         &errorValLen) >= 0) {
1131                     return errorVal ? convertError(errorVal) : 0;
1132                 }
1133                 rc = errno;
1134                 return convertError(rc);
1135             }
1136
1137         } else if (rc < 0) {
1138             /* something went wrong with the select call */
1139             rc = errno;
1140
1141             /* if it was EINTR we can just try again. Return not connected */
1142             if (EINTR == rc) {
1143                 return SOCKERR_NOTCONNECTED;
1144             }
1145
1146             /* some other error occured so look it up and return */
1147             return convertError(rc);
1148         }
1149
1150         /*
1151          * if we get here the timeout expired or the connect had not yet
1152          * completed just indicate that the connect is not yet complete
1153          */
1154         return SOCKERR_NOTCONNECTED;
1155     } else if (SOCKET_STEP_DONE == step) {
1156         /* we are done the connect or an error occured so clean up  */
1157         if (handle != -1) {
1158             int block = JNI_FALSE;
1159             ioctl(handle, FIONBIO, &block);
1160         }
1161         return 0;
1162     }
1163     return SOCKERR_ARGSINVALID;
1164 }
1165
1166
1167 /**
1168  * Helper method to get or set socket options
1169  *
1170  * @param action SOCKOPT_GET to get an option, SOCKOPT_SET to set it
1171  * @param socket the file descriptor of the socket to use
1172  * @param ipv4Option the option value to use for an IPv4 socket
1173  * @param ipv6Option the option value to use for an IPv6 socket
1174  * @param optionValue the value of the socket option to get or set
1175  * @param optionLength the length of the socket option to get or set
1176  *
1177  * @return the value of the socket call, or -1 on failure inside this function
1178  *
1179  * @note on internal failure, the errno variable will be set appropriately
1180  */
1181 static int getOrSetSocketOption(int action, int socket, int ipv4Option,
1182         int ipv6Option, void *optionValue, socklen_t *optionLength) {
1183     int option;
1184     int protocol;
1185     int family = getSocketAddressFamily(socket);
1186     switch (family) {
1187         case AF_INET:
1188             option = ipv4Option;
1189             protocol = IPPROTO_IP;
1190             break;
1191         case AF_INET6:
1192             option = ipv6Option;
1193             protocol = IPPROTO_IPV6;
1194             break;
1195         default:
1196             errno = EAFNOSUPPORT;
1197             return -1;
1198     }
1199     if (action == SOCKOPT_GET) {
1200         return getsockopt(socket, protocol, option, &optionValue, optionLength);
1201     } else if (action == SOCKOPT_SET) {
1202         return setsockopt(socket, protocol, option, &optionValue,
1203                           *optionLength);
1204     } else {
1205         errno = EINVAL;
1206         return -1;
1207     }
1208 }
1209
1210 /*
1211  * Find the interface index that was set for this socket by the IP_MULTICAST_IF
1212  * or IPV6_MULTICAST_IF socket option.
1213  *
1214  * @param socket the socket to examine
1215  *
1216  * @return the interface index, or -1 on failure
1217  *
1218  * @note on internal failure, the errno variable will be set appropriately
1219  */
1220 static int interfaceIndexFromMulticastSocket(int socket) {
1221     int family = getSocketAddressFamily(socket);
1222     socklen_t requestLength;
1223     int interfaceIndex;
1224     int result;
1225     if (family == AF_INET) {
1226         // IP_MULTICAST_IF returns a pointer to a struct ip_mreqn.
1227         struct ip_mreqn tempRequest;
1228         requestLength = sizeof(tempRequest);
1229         result = getsockopt(socket, IPPROTO_IP, IP_MULTICAST_IF, &tempRequest,
1230             &requestLength);
1231         interfaceIndex = tempRequest.imr_ifindex;
1232     } else if (family == AF_INET6) {
1233         // IPV6_MULTICAST_IF returns a pointer to an integer.
1234         requestLength = sizeof(interfaceIndex);
1235         result = getsockopt(socket, IPPROTO_IPV6, IPV6_MULTICAST_IF,
1236                 &interfaceIndex, &requestLength);
1237     } else {
1238         errno = EAFNOSUPPORT;
1239         return -1;
1240     }
1241
1242     if (result == 0)
1243         return interfaceIndex;
1244     else
1245         return -1;
1246 }
1247
1248
1249 /**
1250  * Join/Leave the nominated multicast group on the specified socket.
1251  * Implemented by setting the multicast 'add membership'/'drop membership'
1252  * option at the HY_IPPROTO_IP level on the socket.
1253  *
1254  * Implementation note for multicast sockets in general:
1255  *
1256  * - This code is untested, because at the time of this writing multicast can't
1257  * be properly tested on Android due to GSM routing restrictions. So it might
1258  * or might not work.
1259  *
1260  * - The REUSEPORT socket option that Harmony employs is not supported on Linux
1261  * and thus also not supported on Android. It's is not needed for multicast
1262  * to work anyway (REUSEADDR should suffice).
1263  *
1264  * @param env pointer to the JNI library.
1265  * @param socketP pointer to the hysocket to join/leave on.
1266  * @param optVal pointer to the InetAddress, the multicast group to join/drop.
1267  *
1268  * @exception SocketException if an error occurs during the call
1269  */
1270 static void mcastAddDropMembership (JNIEnv * env, int handle, jobject optVal,
1271         int ignoreIF, int setSockOptVal) {
1272     struct sockaddr_storage sockaddrP;
1273     int result;
1274     // By default, let the system decide which interface to use.
1275     int interfaceIndex = 0;
1276
1277     /*
1278      * Check whether we are getting an InetAddress or an Generic IPMreq. For now
1279      * we support both so that we will not break the tests. If an InetAddress
1280      * is passed in, only support IPv4 as obtaining an interface from an
1281      * InetAddress is complex and should be done by the Java caller.
1282      */
1283     if (env->IsInstanceOf (optVal, gCachedFields.iaddr_class)) {
1284         /*
1285          * optVal is an InetAddress. Construct a multicast request structure
1286          * from this address. Support IPv4 only.
1287          */
1288         struct ip_mreqn multicastRequest;
1289         socklen_t length = sizeof(multicastRequest);
1290         memset(&multicastRequest, 0, length);
1291
1292         // If ignoreIF is false, determine the index of the interface to use.
1293         if (!ignoreIF) {
1294             interfaceIndex = interfaceIndexFromMulticastSocket(handle);
1295             multicastRequest.imr_ifindex = interfaceIndex;
1296             if (interfaceIndex == -1) {
1297                 throwSocketException(env, convertError(errno));
1298                 return;
1299             }
1300         }
1301
1302         // Convert the inetAddress to an IPv4 address structure.
1303         result = inetAddressToSocketAddress(env, optVal, 0, &sockaddrP);
1304         if (result < 0)  // Exception has already been thrown.
1305             return;
1306         if (sockaddrP.ss_family != AF_INET) {
1307             throwSocketException(env, SOCKERR_BADAF);
1308             return;
1309         }
1310         struct sockaddr_in *sin = (struct sockaddr_in *) &sockaddrP;
1311         multicastRequest.imr_multiaddr = sin->sin_addr;
1312
1313         result = setsockopt(handle, IPPROTO_IP, setSockOptVal,
1314                             &multicastRequest, length);
1315         if (0 != result) {
1316             throwSocketException (env, convertError(errno));
1317             return;
1318         }
1319     } else {
1320         /*
1321          * optVal is a GenericIPMreq object. Extract the relevant fields from
1322          * it and construct a multicast request structure from these. Support
1323          * both IPv4 and IPv6.
1324          */
1325         jclass cls;
1326         jfieldID multiaddrID;
1327         jfieldID interfaceIdxID;
1328         jobject multiaddr;
1329
1330         // Get the multicast address to join or leave.
1331         cls = env->GetObjectClass(optVal);
1332         multiaddrID = env->GetFieldID(cls, "multiaddr", "Ljava/net/InetAddress;");
1333         multiaddr = env->GetObjectField(optVal, multiaddrID);
1334
1335         // Get the interface index to use.
1336         if (! ignoreIF) {
1337             interfaceIdxID = env->GetFieldID(cls, "interfaceIdx", "I");
1338             interfaceIndex = env->GetIntField(optVal, interfaceIdxID);
1339         }
1340
1341         result = inetAddressToSocketAddress(env, multiaddr, 0, &sockaddrP);
1342         if (result < 0)  // Exception has already been thrown.
1343             return;
1344
1345         struct ip_mreqn ipv4Request;
1346         struct ipv6_mreq ipv6Request;
1347         void *multicastRequest;
1348         socklen_t requestLength;
1349         int level;
1350         int family = getSocketAddressFamily(handle);
1351         switch (family) {
1352             case AF_INET:
1353                 requestLength = sizeof(ipv4Request);
1354                 memset(&ipv4Request, 0, requestLength);
1355                 ipv4Request.imr_multiaddr =
1356                         ((struct sockaddr_in *) &sockaddrP)->sin_addr;
1357                 ipv4Request.imr_ifindex = interfaceIndex;
1358                 multicastRequest = &ipv4Request;
1359                 level = IPPROTO_IP;
1360                 break;
1361             case AF_INET6:
1362                 requestLength = sizeof(ipv6Request);
1363                 memset(&ipv6Request, 0, requestLength);
1364                 ipv6Request.ipv6mr_multiaddr =
1365                         ((struct sockaddr_in6 *) &sockaddrP)->sin6_addr;
1366                 ipv6Request.ipv6mr_interface = interfaceIndex;
1367                 multicastRequest = &ipv6Request;
1368                 level = IPPROTO_IPV6;
1369                 break;
1370            default:
1371                throwSocketException (env, SOCKERR_BADAF);
1372                return;
1373         }
1374
1375         /* join/drop the multicast address */
1376         result = setsockopt(handle, level, setSockOptVal, multicastRequest,
1377                             requestLength);
1378         if (0 != result) {
1379             throwSocketException (env, convertError(errno));
1380             return;
1381         }
1382     }
1383 }
1384
1385 static void osNetworkSystem_oneTimeInitializationImpl(JNIEnv* env, jobject obj,
1386         jboolean jcl_supports_ipv6) {
1387     // LOGD("ENTER oneTimeInitializationImpl of OSNetworkSystem");
1388
1389     char useAdbNetworkingProperty[PROPERTY_VALUE_MAX];
1390     char adbConnectedProperty[PROPERTY_VALUE_MAX];
1391
1392     property_get("android.net.use-adb-networking", useAdbNetworkingProperty, "");
1393     property_get("adb.connected", adbConnectedProperty, "");
1394
1395     if (strlen((char *)useAdbNetworkingProperty) > 0
1396             && strlen((char *)adbConnectedProperty) > 0) {
1397         useAdbNetworking = 1;
1398     }
1399
1400     memset(&gCachedFields, 0, sizeof(gCachedFields));
1401
1402     // initializing InetAddress
1403
1404     jclass iaddrclass = env->FindClass("java/net/InetAddress");
1405     if (iaddrclass == NULL) {
1406         jniThrowException(env, "java/lang/ClassNotFoundException",
1407                 "java.net.InetAddress");
1408         return;
1409     }
1410     gCachedFields.iaddr_class = (jclass) env->NewGlobalRef(iaddrclass);
1411
1412     jclass i4addrclass = env->FindClass("java/net/Inet4Address");
1413     if (i4addrclass == NULL) {
1414         jniThrowException(env, "java/lang/ClassNotFoundException",
1415                 "java.net.Inet4Address");
1416         return;
1417     }
1418     gCachedFields.i4addr_class = (jclass) env->NewGlobalRef(i4addrclass);
1419
1420     jmethodID i4addrclassinit = env->GetMethodID(i4addrclass, "<init>", "([B)V");
1421     if (i4addrclassinit == NULL) {
1422         jniThrowException(env, "java/lang/NoSuchMethodError", "Inet4Address.<init>(byte[])");
1423         return;
1424     }
1425     gCachedFields.i4addr_class_init = i4addrclassinit;
1426
1427     jmethodID iaddrgetbyaddress = env->GetStaticMethodID(iaddrclass,
1428             "getByAddress", "([B)Ljava/net/InetAddress;");
1429
1430     if (iaddrgetbyaddress == NULL) {
1431         jniThrowException(env, "java/lang/NoSuchMethodError",
1432                 "InetAddress.getByAddress(byte[] val)");
1433         return;
1434     }
1435
1436     gCachedFields.iaddr_getbyaddress = iaddrgetbyaddress;
1437
1438     jfieldID iaddripaddress = env->GetFieldID(iaddrclass, "ipaddress", "[B");
1439     if (iaddripaddress == NULL) {
1440         jniThrowException(env, "java/lang/NoSuchFieldError",
1441                 "Can't find field InetAddress.ipaddress");
1442         return;
1443     }
1444     gCachedFields.iaddr_ipaddress = iaddripaddress;
1445
1446     // get the GenericIPMreq class
1447
1448     jclass genericipmreqclass = env->FindClass("org/apache/harmony/luni/net/GenericIPMreq");
1449
1450     if (genericipmreqclass == NULL) {
1451         jniThrowException(env, "java/lang/ClassNotFoundException",
1452                 "org.apache.harmony.luni.net.GenericIPMreq");
1453         return;
1454     }
1455
1456     gCachedFields.genericipmreq_class = (jclass) env->NewGlobalRef(genericipmreqclass);
1457
1458     // initializing Integer
1459
1460     jclass integerclass = env->FindClass("java/lang/Integer");
1461
1462     if (integerclass == NULL) {
1463         jniThrowException(env, "java/lang/ClassNotFoundException",
1464                 "java.lang.Integer");
1465         return;
1466     }
1467
1468     jmethodID integerclassinit = env->GetMethodID(integerclass, "<init>", "(I)V");
1469
1470     if (integerclassinit == NULL) {
1471         jniThrowException(env, "java/lang/NoSuchMethodError",
1472                 "Integer.<init>(int val)");
1473         return;
1474     }
1475
1476     jfieldID integerclassvalue = env->GetFieldID(integerclass, "value", "I");
1477
1478     if (integerclassvalue == NULL) {
1479         jniThrowException(env, "java/lang/NoSuchMethodError", "Integer.value");
1480         return;
1481     }
1482
1483     gCachedFields.integer_class = (jclass) env->NewGlobalRef(integerclass);
1484     gCachedFields.integer_class_init = integerclassinit;
1485     gCachedFields.integer_class_value = integerclassvalue;
1486
1487     // initializing Boolean
1488
1489     jclass booleanclass = env->FindClass("java/lang/Boolean");
1490
1491     if (booleanclass == NULL) {
1492         jniThrowException(env, "java/lang/ClassNotFoundException",
1493                 "java.lang.Boolean");
1494         return;
1495     }
1496
1497     jmethodID booleanclassinit = env->GetMethodID(booleanclass, "<init>", "(Z)V");
1498
1499     if (booleanclassinit == NULL) {
1500         jniThrowException(env, "java/lang/NoSuchMethodError",
1501                 "Boolean.<init>(boolean val)");
1502         return;
1503     }
1504
1505     jfieldID booleanclassvalue = env->GetFieldID(booleanclass, "value", "Z");
1506
1507     if (booleanclassvalue == NULL) {
1508         jniThrowException(env, "java/lang/NoSuchMethodError", "Boolean.value");
1509         return;
1510     }
1511
1512     gCachedFields.boolean_class = (jclass) env->NewGlobalRef(booleanclass);
1513     gCachedFields.boolean_class_init = booleanclassinit;
1514     gCachedFields.boolean_class_value = booleanclassvalue;
1515
1516     // initializing Byte
1517
1518     jclass byteclass = env->FindClass("java/lang/Byte");
1519
1520     if (byteclass == NULL) {
1521         jniThrowException(env, "java/lang/ClassNotFoundException",
1522                 "java.lang.Byte");
1523         return;
1524     }
1525
1526     jmethodID byteclassinit = env->GetMethodID(byteclass, "<init>", "(B)V");
1527
1528     if (byteclassinit == NULL) {
1529         jniThrowException(env, "java/lang/NoSuchMethodError",
1530                 "Byte.<init>(byte val)");
1531         return;
1532     }
1533
1534     jfieldID byteclassvalue = env->GetFieldID(byteclass, "value", "B");
1535
1536     if (byteclassvalue == NULL) {
1537         jniThrowException(env, "java/lang/NoSuchMethodError", "Byte.value");
1538         return;
1539     }
1540
1541     gCachedFields.byte_class = (jclass) env->NewGlobalRef(byteclass);
1542     gCachedFields.byte_class_init = byteclassinit;
1543     gCachedFields.byte_class_value = byteclassvalue;
1544
1545     // initializing String
1546
1547     jclass stringclass = env->FindClass("java/lang/String");
1548
1549     if (stringclass == NULL) {
1550         jniThrowException(env, "java/lang/ClassNotFoundException",
1551                 "java.lang.String");
1552         return;
1553     }
1554
1555     jmethodID stringclassinit = env->GetMethodID(stringclass, "<init>", "([B)V");
1556
1557     if (stringclassinit == NULL) {
1558         jniThrowException(env, "java/lang/NoSuchMethodError",
1559                 "String.<init>(byte[] val)");
1560         return;
1561     }
1562
1563     gCachedFields.string_class = (jclass) env->NewGlobalRef(stringclass);
1564     gCachedFields.string_class_init = stringclassinit;
1565
1566     // initializing ScoketImpl
1567
1568     jclass socketimplclass = env->FindClass("java/net/SocketImpl");
1569
1570     if (socketimplclass == NULL) {
1571         jniThrowException(env, "java/lang/ClassNotFoundException",
1572                 "java.net.SocketImpl");
1573         return;
1574     }
1575
1576     jfieldID socketimplport = env->GetFieldID(socketimplclass, "port", "I");
1577
1578     if (socketimplport == NULL) {
1579         jniThrowException(env, "java/lang/NoSuchFieldError", "SocketImpl.port");
1580         return;
1581     }
1582
1583     jfieldID socketimpladdress = env->GetFieldID(socketimplclass, "address",
1584             "Ljava/net/InetAddress;");
1585
1586     if (socketimpladdress == NULL) {
1587         jniThrowException(env, "java/lang/NoSuchFieldError",
1588                 "SocketImpl.address");
1589         return;
1590     }
1591
1592     gCachedFields.socketimpl_address = socketimpladdress;
1593     gCachedFields.socketimpl_port = socketimplport;
1594
1595     gCachedFields.dpack_class = env->FindClass("java/net/DatagramPacket");
1596     if (gCachedFields.dpack_class == NULL) {
1597         jniThrowException(env, "java/lang/ClassNotFoundException",
1598                 "java.net.DatagramPacket");
1599         return;
1600     }
1601
1602     gCachedFields.dpack_address = env->GetFieldID(gCachedFields.dpack_class,
1603             "address", "Ljava/net/InetAddress;");
1604     if (gCachedFields.dpack_address == NULL) {
1605         jniThrowException(env, "java/lang/NoSuchFieldError",
1606                 "DatagramPacket.address");
1607         return;
1608     }
1609
1610     gCachedFields.dpack_port = env->GetFieldID(gCachedFields.dpack_class,
1611             "port", "I");
1612     if (gCachedFields.dpack_port == NULL) {
1613         jniThrowException(env, "java/lang/NoSuchFieldError",
1614                 "DatagramPacket.port");
1615         return;
1616     }
1617
1618     gCachedFields.dpack_length = env->GetFieldID(gCachedFields.dpack_class,
1619             "length", "I");
1620     if (gCachedFields.dpack_length == NULL) {
1621         jniThrowException(env, "java/lang/NoSuchFieldError",
1622                 "DatagramPacket.length");
1623         return;
1624     }
1625
1626 }
1627
1628 /**
1629  * Helper function to create a socket of the specified type and bind it to a
1630  * Java file descriptor.
1631  *
1632  * @param fileDescriptor the file descriptor to bind the socket to
1633  * @param type the socket type to create, e.g., SOCK_STREAM
1634  *
1635  * @return the socket file descriptor, or -1 on failure
1636  *
1637  */
1638 static int createSocketFileDescriptor(JNIEnv* env, jobject fileDescriptor,
1639                                       int type) {
1640     if (fileDescriptor == NULL) {
1641         throwNullPointerException(env);
1642         errno = EBADF;
1643         return -1;
1644     }
1645
1646     int sock;
1647     sock = socket(PF_INET6, type, 0);
1648     if (sock < 0 && errno == EAFNOSUPPORT) {
1649         sock = socket(PF_INET, type, 0);
1650     }
1651     if (sock < 0) {
1652         int err = convertError(errno);
1653         throwSocketException(env, err);
1654     }
1655     jniSetFileDescriptorOfFD(env, fileDescriptor, sock);
1656     return sock;
1657 }
1658
1659
1660 static void osNetworkSystem_createStreamSocketImpl(JNIEnv* env, jclass clazz,
1661         jobject fileDescriptor, jboolean preferIPv4Stack) {
1662     // LOGD("ENTER createSocketImpl");
1663     createSocketFileDescriptor(env, fileDescriptor, SOCK_STREAM);
1664 }
1665
1666 static void osNetworkSystem_createDatagramSocketImpl(JNIEnv* env, jclass clazz,
1667         jobject fileDescriptor, jboolean preferIPv4Stack) {
1668     // LOGD("ENTER createDatagramSocketImpl");
1669     createSocketFileDescriptor(env, fileDescriptor, SOCK_DGRAM);
1670 }
1671
1672 static jint osNetworkSystem_readSocketDirectImpl(JNIEnv* env, jclass clazz,
1673         jobject fileDescriptor, jint address, jint offset, jint count,
1674         jint timeout) {
1675     // LOGD("ENTER readSocketDirectImpl");
1676
1677     int handle;
1678     jbyte *message = (jbyte *)address + offset;
1679     int result, ret, localCount;
1680
1681     handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
1682
1683     if (handle == 0 || handle == -1) {
1684         throwSocketException(env, SOCKERR_BADSOCKET);
1685         return 0;
1686     }
1687
1688     result = selectWait(handle, timeout, SELECT_READ_TYPE);
1689
1690     if (0 > result) {
1691         return 0;
1692     }
1693
1694     localCount = (count < 65536) ? count : 65536;
1695
1696     do {
1697         ret = recv(handle, (jbyte *) message, localCount, SOCKET_NOFLAGS);
1698     } while (ret < 0 && errno == EINTR);
1699
1700     if (0 == ret) {
1701         return -1;
1702     } else if (ret == -1) {
1703         int err = convertError(errno);
1704         throwSocketException(env, err);
1705         return 0;
1706     }
1707     return ret;
1708 }
1709
1710 static jint osNetworkSystem_readSocketImpl(JNIEnv* env, jclass clazz,
1711         jobject fileDescriptor, jbyteArray data, jint offset, jint count,
1712         jint timeout) {
1713     // LOGD("ENTER readSocketImpl");
1714
1715     jbyte *message;
1716     int result, localCount;
1717
1718     jbyte internalBuffer[BUFFERSIZE];
1719
1720     localCount = (count < 65536) ? count : 65536;
1721
1722     if (localCount > BUFFERSIZE) {
1723         message = (jbyte*)malloc(localCount * sizeof(jbyte));
1724         if (message == NULL) {
1725             jniThrowException(env, "java/lang/OutOfMemoryError",
1726                     "couldn't allocate enough memory for readSocket");
1727             return 0;
1728         }
1729     } else {
1730         message = (jbyte *)internalBuffer;
1731     }
1732
1733     result = osNetworkSystem_readSocketDirectImpl(env, clazz, fileDescriptor,
1734             (jint) message, 0, localCount, timeout);
1735
1736     if (result > 0) {
1737         env->SetByteArrayRegion(data, offset, result, (jbyte *)message);
1738     }
1739
1740     if (((jbyte *)message) != internalBuffer) {
1741         free(( jbyte *)message);
1742     }
1743
1744     return result;
1745 }
1746
1747 static jint osNetworkSystem_writeSocketDirectImpl(JNIEnv* env, jclass clazz,
1748         jobject fileDescriptor, jint address, jint offset, jint count) {
1749     // LOGD("ENTER writeSocketDirectImpl");
1750
1751     int handle;
1752     jbyte *message = (jbyte *)address + offset;
1753     int result = 0, sent = 0;
1754
1755     if (count <= 0) {
1756         return 0;
1757     }
1758
1759     handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
1760
1761     if (handle == 0 || handle == -1) {
1762         throwSocketException(env, SOCKERR_BADSOCKET);
1763         return 0;
1764     }
1765
1766     result = send(handle, (jbyte *) message, (int) count, SOCKET_NOFLAGS);
1767     if (result < 0) {
1768         int err = convertError(errno);
1769
1770         if (SOCKERR_WOULDBLOCK == err){
1771             jclass socketExClass,errorCodeExClass;
1772             jmethodID errorCodeExConstructor, socketExConstructor,socketExCauseMethod;
1773             jobject errorCodeEx, socketEx;
1774             const char* errorMessage = netLookupErrorString(err);
1775             jstring errorMessageString = env->NewStringUTF(errorMessage);
1776
1777             errorCodeExClass = env->FindClass("org/apache/harmony/luni/util/ErrorCodeException");
1778             if (!errorCodeExClass){
1779                 return 0;
1780             }
1781             errorCodeExConstructor = env->GetMethodID(errorCodeExClass,"<init>","(I)V");
1782             if (!errorCodeExConstructor){
1783                 return 0;
1784             }
1785             errorCodeEx = env->NewObject(errorCodeExClass,errorCodeExConstructor,err);
1786
1787             socketExClass = env->FindClass("java/net/SocketException");
1788             if (!socketExClass) {
1789                 return 0;
1790             }
1791             socketExConstructor = env->GetMethodID(socketExClass,"<init>","(Ljava/lang/String;)V");
1792             if (!socketExConstructor) {
1793                 return 0;
1794             }
1795             socketEx = env->NewObject(socketExClass, socketExConstructor, errorMessageString);
1796             socketExCauseMethod = env->GetMethodID(socketExClass,"initCause","(Ljava/lang/Throwable;)Ljava/lang/Throwable;");
1797             env->CallObjectMethod(socketEx,socketExCauseMethod,errorCodeEx);
1798             env->Throw((jthrowable)socketEx);
1799             return 0;
1800         }
1801         throwSocketException(env, err);
1802         return 0;
1803     }
1804
1805     return result;
1806 }
1807
1808 static jint osNetworkSystem_writeSocketImpl(JNIEnv* env, jclass clazz,
1809         jobject fileDescriptor, jbyteArray data, jint offset, jint count) {
1810     // LOGD("ENTER writeSocketImpl");
1811
1812     jbyte *message;
1813     int sent = 0;
1814     jint result = 0;
1815
1816 /* TODO: ARRAY PINNING */
1817 #define INTERNAL_SEND_BUFFER_MAX 512
1818     jbyte internalBuffer[INTERNAL_SEND_BUFFER_MAX];
1819
1820     if (count > INTERNAL_SEND_BUFFER_MAX) {
1821         message = (jbyte*)malloc(count * sizeof( jbyte));
1822         if (message == NULL) {
1823             jniThrowException(env, "java/lang/OutOfMemoryError",
1824                     "couldn't allocate enough memory for writeSocket");
1825             return 0;
1826         }
1827     } else {
1828         message = (jbyte *)internalBuffer;
1829     }
1830
1831     env->GetByteArrayRegion(data, offset, count, message);
1832
1833     result = osNetworkSystem_writeSocketDirectImpl(env, clazz, fileDescriptor,
1834             (jint) message, 0, count);
1835
1836     if (( jbyte *)message != internalBuffer) {
1837         free(( jbyte *)message);
1838     }
1839 #undef INTERNAL_SEND_BUFFER_MAX
1840     return result;
1841 }
1842
1843 static void osNetworkSystem_setNonBlockingImpl(JNIEnv* env, jclass clazz,
1844         jobject fileDescriptor, jboolean nonblocking) {
1845     // LOGD("ENTER setNonBlockingImpl");
1846
1847     int handle;
1848     int result;
1849
1850     handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
1851
1852     if (handle == 0 || handle == -1) {
1853         throwSocketException(env, SOCKERR_BADSOCKET);
1854         return;
1855     }
1856
1857     int block = nonblocking;
1858
1859     result = ioctl(handle, FIONBIO, &block);
1860
1861     if (result == -1) {
1862         throwSocketException(env, convertError(errno));
1863     }
1864 }
1865
1866 static jint osNetworkSystem_connectSocketImpl(JNIEnv* env, jclass clazz,
1867         jobject fileDescriptor, jint trafficClass, jobject inetAddr, jint port);
1868
1869 static jint osNetworkSystem_connectWithTimeoutSocketImpl(JNIEnv* env,
1870         jclass clazz, jobject fileDescriptor, jint timeout, jint trafficClass,
1871         jobject inetAddr, jint port, jint step, jbyteArray passContext) {
1872     // LOGD("ENTER connectWithTimeoutSocketImpl");
1873
1874     int handle;
1875     int result = 0;
1876     struct sockaddr_storage address;
1877     jbyte *context = NULL;
1878
1879     result = inetAddressToSocketAddress(env, inetAddr, port, &address);
1880     if (result < 0)
1881         return result;
1882
1883     // Check if we're using adb networking and redirect in case it is used.
1884     if (useAdbNetworkingForAddress(&address)) {
1885         return osNetworkSystem_connectSocketImpl(env, clazz, fileDescriptor,
1886                 trafficClass, inetAddr, port);
1887     }
1888
1889     handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
1890     if (handle == 0 || handle == -1) {
1891         throwSocketException(env, SOCKERR_BADDESC);
1892         return -1;
1893     }
1894
1895     context = (jbyte *)env->GetPrimitiveArrayCritical(passContext, NULL);
1896
1897     switch (step) {
1898         case SOCKET_CONNECT_STEP_START:
1899             result = sockConnectWithTimeout(handle, address, 0,
1900                     SOCKET_STEP_START, context);
1901             break;
1902         case SOCKET_CONNECT_STEP_CHECK:
1903             result = sockConnectWithTimeout(handle, address, timeout,
1904                     SOCKET_STEP_CHECK, context);
1905             break;
1906     }
1907
1908     env->ReleasePrimitiveArrayCritical(passContext, context, JNI_ABORT);
1909
1910     if (0 == result) {
1911         /* connected , so stop here */
1912         sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_DONE, NULL);
1913     } else if (result != SOCKERR_NOTCONNECTED) {
1914         /* can not connect... */
1915         sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_DONE, NULL);
1916         if (result == SOCKERR_EACCES) {
1917             jniThrowException(env, "java/lang/SecurityException",
1918                               netLookupErrorString(result));
1919         } else {
1920             jniThrowException(env, "java/net/ConnectException",
1921                               netLookupErrorString(result));
1922         }
1923     }
1924
1925     return result;
1926 }
1927
1928 static void osNetworkSystem_connectStreamWithTimeoutSocketImpl(JNIEnv* env,
1929         jclass clazz, jobject fileDescriptor, jint remotePort, jint timeout,
1930         jint trafficClass, jobject inetAddr) {
1931     // LOGD("ENTER connectStreamWithTimeoutSocketImpl");
1932
1933     int result = 0;
1934     int handle;
1935     struct sockaddr_storage address;
1936     jbyte *context = NULL;
1937     int remainingTimeout = timeout;
1938     int passedTimeout = 0;
1939     int finishTime = 0;
1940     int blocking = 0;
1941     char hasTimeout = timeout > 0;
1942
1943     /* if a timeout was specified calculate the finish time value */
1944     if (hasTimeout)  {
1945         finishTime = time_msec_clock() + (int) timeout;
1946     }
1947
1948     handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
1949     if (handle == 0 || handle == -1) {
1950         throwSocketException(env, SOCKERR_BADDESC);
1951         return;
1952     }
1953
1954     result = inetAddressToSocketAddress(env, inetAddr, remotePort, &address);
1955     if (result < 0)  // Exception has already been thrown.
1956         return;
1957
1958     // Check if we're using adb networking and redirect in case it is used.
1959     if (useAdbNetworkingForAddress(&address)) {
1960         int retVal = osNetworkSystem_connectSocketImpl(env, clazz,
1961                 fileDescriptor, trafficClass, inetAddr, remotePort);
1962         if (retVal != 0) {
1963             throwSocketException(env, SOCKERR_BADSOCKET);
1964         }
1965         return;
1966     }
1967
1968     /*
1969      * we will be looping checking for when we are connected so allocate
1970      * the descriptor sets that we will use
1971      */
1972     context =(jbyte *) malloc(sizeof(struct selectFDSet));
1973     if (NULL == context) {
1974         throwSocketException(env, SOCKERR_NOBUFFERS);
1975         return;
1976     }
1977
1978     result = sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_START, context);
1979     if (0 == result) {
1980         /* ok we connected right away so we are done */
1981         sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_DONE, context);
1982         goto bail;
1983     } else if (result != SOCKERR_NOTCONNECTED) {
1984         sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_DONE,
1985                                context);
1986         /* we got an error other than NOTCONNECTED so we cannot continue */
1987         if (SOCKERR_EACCES == result) {
1988             jniThrowException(env, "java/lang/SecurityException",
1989                               netLookupErrorString(result));
1990         } else {
1991             throwSocketException(env, result);
1992         }
1993         goto bail;
1994     }
1995
1996     while (SOCKERR_NOTCONNECTED == result) {
1997         passedTimeout = remainingTimeout;
1998
1999         /*
2000          * ok now try and connect. Depending on the platform this may sleep
2001          * for up to passedTimeout milliseconds
2002          */
2003         result = sockConnectWithTimeout(handle, address, passedTimeout,
2004                 SOCKET_STEP_CHECK, context);
2005
2006         /*
2007          * now check if the socket is still connected.
2008          * Do it here as some platforms seem to think they
2009          * are connected if the socket is closed on them.
2010          */
2011         handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
2012         if (handle == 0 || handle == -1) {
2013             sockConnectWithTimeout(handle, address, 0,
2014                     SOCKET_STEP_DONE, context);
2015             throwSocketException(env, SOCKERR_BADSOCKET);
2016             goto bail;
2017         }
2018
2019         /*
2020          * check if we are now connected,
2021          * if so we can finish the process and return
2022          */
2023         if (0 == result) {
2024             sockConnectWithTimeout(handle, address, 0,
2025                     SOCKET_STEP_DONE, context);
2026             goto bail;
2027         }
2028
2029         /*
2030          * if the error is SOCKERR_NOTCONNECTED then we have not yet
2031          * connected and we may not be done yet
2032          */
2033         if (SOCKERR_NOTCONNECTED == result) {
2034             /* check if the timeout has expired */
2035             if (hasTimeout) {
2036                 remainingTimeout = finishTime - time_msec_clock();
2037                 if (remainingTimeout <= 0) {
2038                     sockConnectWithTimeout(handle, address, 0,
2039                             SOCKET_STEP_DONE, context);
2040                     jniThrowException(env,
2041                             "java/net/SocketTimeoutException",
2042                             netLookupErrorString(result));
2043                     goto bail;
2044                 }
2045             } else {
2046                 remainingTimeout = 100;
2047             }
2048         } else {
2049             sockConnectWithTimeout(handle, address, remainingTimeout,
2050                                    SOCKET_STEP_DONE, context);
2051             if ((SOCKERR_CONNRESET == result) ||
2052                 (SOCKERR_CONNECTION_REFUSED == result) ||
2053                 (SOCKERR_ADDRNOTAVAIL == result) ||
2054                 (SOCKERR_ADDRINUSE == result) ||
2055                 (SOCKERR_ENETUNREACH == result)) {
2056                 jniThrowException(env, "java/net/ConnectException",
2057                                   netLookupErrorString(result));
2058             } else if (SOCKERR_EACCES == result) {
2059                 jniThrowException(env, "java/lang/SecurityException",
2060                                   netLookupErrorString(result));
2061             } else {
2062                 throwSocketException(env, result);
2063             }
2064             goto bail;
2065         }
2066     }
2067
2068 bail:
2069
2070     /* free the memory for the FD set */
2071     if (context != NULL)  {
2072         free(context);
2073     }
2074 }
2075
2076 static jint osNetworkSystem_connectSocketImpl(JNIEnv* env, jclass clazz,
2077         jobject fileDescriptor, jint trafficClass, jobject inetAddr, jint port) {
2078     //LOGD("ENTER direct-call connectSocketImpl\n");
2079
2080     struct sockaddr_storage address;
2081     int ret;
2082     int handle;
2083
2084     ret = inetAddressToSocketAddress(env, inetAddr, port, &address);
2085     if (ret < 0)
2086         return ret;
2087
2088     handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
2089     if (handle == 0 || handle == -1) {
2090         throwSocketException(env, SOCKERR_BADDESC);
2091         return -1;
2092     }
2093
2094     if (useAdbNetworkingForAddress(&address)) {
2095
2096         // LOGD("+connect to address 0x%08x port %d (via adb)",
2097         //         address.sin_addr.s_addr, (int) port);
2098         ret = adb_networking_connect_fd(handle, (struct sockaddr_in *) &address);
2099         // LOGD("-connect ret %d errno %d (via adb)", ret, errno);
2100
2101     } else {
2102
2103         // call this method with a timeout of zero
2104         osNetworkSystem_connectStreamWithTimeoutSocketImpl(env, clazz,
2105                 fileDescriptor, port, 0, trafficClass, inetAddr);
2106         if (env->ExceptionOccurred() != 0) {
2107             return -1;
2108         } else {
2109             return 0;
2110         }
2111
2112     }
2113
2114     if (ret < 0) {
2115         jniThrowException(env, "java/net/ConnectException",
2116                 netLookupErrorString(convertError(errno)));
2117         return ret;
2118     }
2119
2120     return ret;
2121 }
2122
2123 static void osNetworkSystem_socketBindImpl(JNIEnv* env, jclass clazz,
2124         jobject fileDescriptor, jint port, jobject inetAddress) {
2125     // LOGD("ENTER socketBindImpl");
2126
2127     struct sockaddr_storage sockaddress;
2128     int ret;
2129     int handle;
2130
2131     ret = inetAddressToSocketAddress(env, inetAddress, port, &sockaddress);
2132     if (ret < 0)
2133         return;
2134
2135     handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
2136     if (handle == 0 || handle == -1) {
2137         throwSocketException(env, SOCKERR_BADDESC);
2138         return;
2139     }
2140
2141     ret = doBind(handle, &sockaddress);
2142     if (ret < 0) {
2143         jniThrowException(env, "java/net/BindException",
2144                 netLookupErrorString(convertError(errno)));
2145         return;
2146     }
2147 }
2148
2149 static void osNetworkSystem_listenStreamSocketImpl(JNIEnv* env, jclass clazz,
2150         jobject fileDescriptor, jint backlog) {
2151     // LOGD("ENTER listenStreamSocketImpl");
2152
2153     int ret;
2154     int handle;
2155
2156     handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
2157
2158     if (handle == 0 || handle == -1) {
2159         throwSocketException(env, SOCKERR_BADSOCKET);
2160         return;
2161     }
2162
2163     ret = listen(handle, backlog);
2164
2165     if (ret < 0) {
2166         int err = convertError(errno);
2167         throwSocketException(env, err);
2168         return;
2169     }
2170 }
2171
2172 static jint osNetworkSystem_availableStreamImpl(JNIEnv* env, jclass clazz,
2173         jobject fileDescriptor) {
2174     // LOGD("ENTER availableStreamImpl");
2175
2176     int handle;
2177     char message[BUFFERSIZE];
2178
2179     int result;
2180
2181     handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
2182     if (handle == 0 || handle == -1) {
2183         throwSocketException(env, SOCKERR_BADDESC);
2184         return 0;
2185     }
2186
2187     do {
2188         result = selectWait(handle, 1, SELECT_READ_TYPE);
2189
2190         if (SOCKERR_TIMEOUT == result) {
2191             // The read operation timed out, so answer 0 bytes available
2192             return 0;
2193         } else if (SOCKERR_INTERRUPTED == result) {
2194             continue;
2195         } else if (0 > result) {
2196             throwSocketException(env, result);
2197             return 0;
2198         }
2199     } while (SOCKERR_INTERRUPTED == result);
2200
2201     result = recv(handle, (jbyte *) message, BUFFERSIZE, MSG_PEEK);
2202
2203     if (0 > result) {
2204         int err = convertError(errno);
2205         throwSocketException(env, err);
2206         return 0;
2207     }
2208     return result;
2209 }
2210
2211 static void osNetworkSystem_acceptSocketImpl(JNIEnv* env, jclass clazz,
2212         jobject fdServer, jobject newSocket, jobject fdnewSocket, jint timeout) {
2213     // LOGD("ENTER acceptSocketImpl");
2214
2215     struct sockaddr_storage sa;
2216
2217     int ret;
2218     int retFD;
2219     int result;
2220     int handle;
2221     socklen_t addrlen;
2222
2223     if (newSocket == NULL) {
2224         throwNullPointerException(env);
2225         return;
2226     }
2227
2228     result = pollSelectWait(env, fdServer, timeout, SELECT_READ_TYPE);
2229     if (0 > result) {
2230         return;
2231     }
2232
2233     handle = jniGetFDFromFileDescriptor(env, fdServer);
2234     if (handle == 0 || handle == -1) {
2235         throwSocketException(env, SOCKERR_BADDESC);
2236         return;
2237     }
2238
2239     do {
2240         addrlen = sizeof(sa);
2241         ret = accept(handle, (struct sockaddr *) &sa, &addrlen);
2242     } while (ret < 0 && errno == EINTR);
2243
2244     if (ret < 0) {
2245         int err = convertError(errno);
2246         throwSocketException(env, err);
2247         return;
2248     }
2249
2250     retFD = ret;
2251
2252     /*
2253      * For network sockets, put the peer address and port in instance variables.
2254      * We don't bother to do this for UNIX domain sockets, since most peers are
2255      * anonymous anyway.
2256      */
2257     if (sa.ss_family == AF_INET || sa.ss_family == AF_INET6) {
2258         jobject inetAddress =  socketAddressToInetAddress(env, &sa);
2259         if (ret == -1) {
2260             close(retFD);
2261             newSocket = NULL;  // Exception has already been thrown.
2262             return;
2263         }
2264
2265         env->SetObjectField(newSocket,
2266                 gCachedFields.socketimpl_address, inetAddress);
2267
2268         int port = getSocketAddressPort(&sa);
2269         env->SetIntField(newSocket, gCachedFields.socketimpl_port, port);
2270     }
2271
2272     jniSetFileDescriptorOfFD(env, fdnewSocket, retFD);
2273 }
2274
2275 static jboolean osNetworkSystem_supportsUrgentDataImpl(JNIEnv* env,
2276         jclass clazz, jobject fileDescriptor) {
2277     // LOGD("ENTER supportsUrgentDataImpl");
2278
2279     int handle;
2280
2281     handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
2282     if (handle == 0 || handle == -1) {
2283         return JNI_FALSE;
2284     }
2285
2286     return JNI_TRUE;
2287 }
2288
2289 static void osNetworkSystem_sendUrgentDataImpl(JNIEnv* env, jclass clazz,
2290         jobject fileDescriptor, jbyte value) {
2291     // LOGD("ENTER sendUrgentDataImpl");
2292
2293     int handle;
2294     int result;
2295
2296     handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
2297     if (handle == 0 || handle == -1) {
2298         throwSocketException(env, SOCKERR_BADSOCKET);
2299         return;
2300     }
2301
2302     result = send(handle, (jbyte *) &value, 1, MSG_OOB);
2303     if (result < 0) {
2304         int err = convertError(errno);
2305         throwSocketException(env, err);
2306     }
2307 }
2308
2309 static void osNetworkSystem_connectDatagramImpl2(JNIEnv* env, jclass clazz,
2310         jobject fd, jint port, jint trafficClass, jobject inetAddress) {
2311     // LOGD("ENTER connectDatagramImpl2");
2312
2313     int handle = jniGetFDFromFileDescriptor(env, fd);
2314
2315     struct sockaddr_storage sockAddr;
2316     int ret;
2317
2318     ret = inetAddressToSocketAddress(env, inetAddress, port, &sockAddr);
2319     if (ret < 0)  // Exception has already been thrown.
2320         return;
2321
2322     ret = doConnect(handle, &sockAddr);
2323     if (ret < 0) {
2324         int err = convertError(errno);
2325         throwSocketException(env, err);
2326     }
2327 }
2328
2329 static void osNetworkSystem_disconnectDatagramImpl(JNIEnv* env, jclass clazz,
2330         jobject fd) {
2331     // LOGD("ENTER disconnectDatagramImpl");
2332
2333     int handle = jniGetFDFromFileDescriptor(env, fd);
2334
2335     struct sockaddr_storage sockAddr;
2336     memset(&sockAddr, 0, sizeof(sockAddr));
2337     sockAddr.ss_family = AF_UNSPEC;
2338
2339     int result = doConnect(handle, &sockAddr);
2340     if (result < 0) {
2341         int err = convertError(errno);
2342         throwSocketException(env, err);
2343     }
2344 }
2345
2346 static jint osNetworkSystem_peekDatagramImpl(JNIEnv* env, jclass clazz,
2347         jobject fd, jobject sender, jint receiveTimeout) {
2348     // LOGD("ENTER peekDatagramImpl");
2349
2350     int port = -1;
2351
2352     int result = pollSelectWait (env, fd, receiveTimeout, SELECT_READ_TYPE);
2353     if (0> result) {
2354         return (jint) 0;
2355     }
2356
2357     int handle = jniGetFDFromFileDescriptor(env, fd);
2358     if (handle == 0 || handle == -1) {
2359         throwSocketException(env, SOCKERR_BADDESC);
2360         return 0;
2361     }
2362
2363     struct sockaddr_storage sockAddr;
2364     socklen_t sockAddrLen = sizeof(sockAddr);
2365     ssize_t length;
2366     do {
2367         length = recvfrom(handle, NULL, 0, MSG_PEEK,
2368                 (struct sockaddr *)&sockAddr, &sockAddrLen);
2369     } while (length < 0 && errno == EINTR);
2370     if (length < 0) {
2371         int err = convertError(errno);
2372         throwSocketException(env, err);
2373         return 0;
2374     }
2375
2376     sender = socketAddressToInetAddress(env, &sockAddr);
2377     if (sender == NULL)  // Exception has already been thrown.
2378         return -1;
2379
2380     port = getSocketAddressPort(&sockAddr);
2381     return port;
2382 }
2383
2384 static jint osNetworkSystem_receiveDatagramDirectImpl(JNIEnv* env, jclass clazz,
2385         jobject fd, jobject packet, jint address, jint offset, jint length,
2386         jint receiveTimeout, jboolean peek) {
2387     // LOGD("ENTER receiveDatagramDirectImpl");
2388
2389     int result = pollSelectWait (env, fd, receiveTimeout, SELECT_READ_TYPE);
2390     if (0 > result) {
2391         return (jint) 0;
2392     }
2393
2394     int handle = jniGetFDFromFileDescriptor(env, fd);
2395     if (handle == 0 || handle == -1) {
2396         throwSocketException(env, SOCKERR_BADDESC);
2397         return 0;
2398     }
2399
2400     struct sockaddr_storage sockAddr;
2401     socklen_t sockAddrLen = sizeof(sockAddr);
2402
2403     int mode = peek ? MSG_PEEK : 0;
2404
2405     ssize_t actualLength;
2406     do {
2407         actualLength = recvfrom(handle, (char*)(address + offset), length, mode,
2408                 (struct sockaddr *)&sockAddr, &sockAddrLen);
2409     } while (actualLength < 0 && errno == EINTR);
2410     if (actualLength < 0) {
2411         int err = convertError(errno);
2412         throwSocketException(env, err);
2413         return 0;
2414     }
2415
2416     if (packet != NULL) {
2417         jbyteArray addr = socketAddressToAddressBytes(env, &sockAddr);
2418         if (addr == NULL)  // Exception has already been thrown.
2419             return 0;
2420         int port = getSocketAddressPort(&sockAddr);
2421         jobject sender = env->CallStaticObjectMethod(
2422                 gCachedFields.iaddr_class, gCachedFields.iaddr_getbyaddress,
2423                 addr);
2424         env->SetObjectField(packet, gCachedFields.dpack_address, sender);
2425         env->SetIntField(packet, gCachedFields.dpack_port, port);
2426         env->SetIntField(packet, gCachedFields.dpack_length,
2427                 (jint) actualLength);
2428     }
2429     return (jint) actualLength;
2430 }
2431
2432 static jint osNetworkSystem_receiveDatagramImpl(JNIEnv* env, jclass clazz,
2433         jobject fd, jobject packet, jbyteArray data, jint offset, jint length,
2434         jint receiveTimeout, jboolean peek) {
2435     // LOGD("ENTER receiveDatagramImpl");
2436
2437     int localLength = (length < 65536) ? length : 65536;
2438     jbyte *bytes = (jbyte*) malloc(localLength);
2439     if (bytes == NULL) {
2440         jniThrowException(env, "java/lang/OutOfMemoryError",
2441                 "couldn't allocate enough memory for receiveDatagram");
2442         return 0;
2443     }
2444
2445     int actualLength = osNetworkSystem_receiveDatagramDirectImpl(env, clazz, fd,
2446             packet, (jint)bytes, 0, localLength, receiveTimeout, peek);
2447
2448     if (actualLength > 0) {
2449         env->SetByteArrayRegion(data, offset, actualLength, bytes);
2450     }
2451     free(bytes);
2452
2453     return actualLength;
2454 }
2455
2456 static jint osNetworkSystem_recvConnectedDatagramDirectImpl(JNIEnv* env,
2457         jclass clazz, jobject fd, jobject packet, jint address, jint offset,
2458         jint length, jint receiveTimeout, jboolean peek) {
2459     // LOGD("ENTER receiveConnectedDatagramDirectImpl");
2460
2461     int result = pollSelectWait (env, fd, receiveTimeout, SELECT_READ_TYPE);
2462
2463     if (0 > result) {
2464         return 0;
2465     }
2466
2467     int handle = jniGetFDFromFileDescriptor(env, fd);
2468
2469     if (handle == 0 || handle == -1) {
2470         throwSocketException(env, SOCKERR_BADSOCKET);
2471         return 0;
2472     }
2473
2474     int mode = peek ? MSG_PEEK : 0;
2475
2476     int actualLength = recvfrom(handle,
2477             (char*)(address + offset), length, mode, NULL, NULL);
2478
2479     if (actualLength < 0) {
2480         jniThrowException(env, "java/net/PortUnreachableException", "");
2481         return 0;
2482     }
2483
2484     if ( packet != NULL) {
2485         env->SetIntField(packet, gCachedFields.dpack_length, actualLength);
2486     }
2487     return actualLength;
2488 }
2489
2490 static jint osNetworkSystem_recvConnectedDatagramImpl(JNIEnv* env, jclass clazz,
2491         jobject fd, jobject packet, jbyteArray data, jint offset, jint length,
2492         jint receiveTimeout, jboolean peek) {
2493     // LOGD("ENTER receiveConnectedDatagramImpl");
2494
2495     int localLength = (length < 65536) ? length : 65536;
2496     jbyte *bytes = (jbyte*) malloc(localLength);
2497     if (bytes == NULL) {
2498         jniThrowException(env, "java/lang/OutOfMemoryError",
2499                 "couldn't allocate enough memory for recvConnectedDatagram");
2500         return 0;
2501     }
2502
2503     int actualLength = osNetworkSystem_recvConnectedDatagramDirectImpl(env,
2504             clazz, fd, packet, (jint)bytes, 0, localLength,
2505             receiveTimeout, peek);
2506
2507     if (actualLength > 0) {
2508         env->SetByteArrayRegion(data, offset, actualLength, bytes);
2509     }
2510     free(bytes);
2511
2512     return actualLength;
2513 }
2514
2515 static jint osNetworkSystem_sendDatagramDirectImpl(JNIEnv* env, jclass clazz,
2516         jobject fd, jint address, jint offset, jint length, jint port,
2517         jboolean bindToDevice, jint trafficClass, jobject inetAddress) {
2518     // LOGD("ENTER sendDatagramDirectImpl");
2519
2520     int handle = jniGetFDFromFileDescriptor(env, fd);
2521
2522     if (handle == 0 || handle == -1) {
2523         throwSocketException(env, SOCKERR_BADSOCKET);
2524         return 0;
2525     }
2526
2527     struct sockaddr_storage receiver;
2528     if (inetAddressToSocketAddress(env, inetAddress, port, &receiver) < 0) {
2529         // Exception has already been thrown.
2530         return 0;
2531     }
2532
2533     ssize_t result = 0;
2534     do {
2535         result = sendto(handle, (char*)(address + offset), length,
2536                 SOCKET_NOFLAGS, (struct sockaddr*)&receiver, sizeof(receiver));
2537     } while (result < 0 && errno == EINTR);
2538     if (result < 0) {
2539         int err = convertError(errno);
2540         if ((SOCKERR_CONNRESET == err)
2541                 || (SOCKERR_CONNECTION_REFUSED == err)) {
2542             return 0;
2543         } else {
2544             throwSocketException(env, err);
2545             return 0;
2546         }
2547     }
2548     return (jint) result;
2549 }
2550
2551 static jint osNetworkSystem_sendDatagramImpl(JNIEnv* env, jclass clazz,
2552         jobject fd, jbyteArray data, jint offset, jint length, jint port,
2553         jboolean bindToDevice, jint trafficClass, jobject inetAddress) {
2554     // LOGD("ENTER sendDatagramImpl");
2555
2556     jbyte *bytes = env->GetByteArrayElements(data, NULL);
2557     int actualLength = osNetworkSystem_sendDatagramDirectImpl(env, clazz, fd,
2558             (jint)bytes, offset, length, port, bindToDevice, trafficClass,
2559             inetAddress);
2560     env->ReleaseByteArrayElements(data, bytes, JNI_ABORT);
2561
2562     return actualLength;
2563 }
2564
2565 static jint osNetworkSystem_sendConnectedDatagramDirectImpl(JNIEnv* env,
2566         jclass clazz, jobject fd, jint address, jint offset, jint length,
2567         jboolean bindToDevice) {
2568     // LOGD("ENTER sendConnectedDatagramDirectImpl");
2569
2570     int handle = jniGetFDFromFileDescriptor(env, fd);
2571
2572     if (handle == 0 || handle == -1) {
2573         throwSocketException(env, SOCKERR_BADSOCKET);
2574         return 0;
2575     }
2576
2577     int result = send(handle, (char*)(address + offset), length, 0);
2578
2579     if (result < 0) {
2580         int err = convertError(errno);
2581         if ((SOCKERR_CONNRESET == err) || (SOCKERR_CONNECTION_REFUSED == err)) {
2582             return 0;
2583         } else {
2584             throwSocketException(env, err);
2585             return 0;
2586         }
2587     }
2588     return result;
2589 }
2590
2591 static jint osNetworkSystem_sendConnectedDatagramImpl(JNIEnv* env, jclass clazz,
2592         jobject fd, jbyteArray data, jint offset, jint length,
2593         jboolean bindToDevice) {
2594     // LOGD("ENTER sendConnectedDatagramImpl");
2595
2596     jbyte *bytes = env->GetByteArrayElements(data, NULL);
2597     int actualLength = osNetworkSystem_sendConnectedDatagramDirectImpl(env,
2598             clazz, fd, (jint)bytes, offset, length, bindToDevice);
2599     env->ReleaseByteArrayElements(data, bytes, JNI_ABORT);
2600
2601     return actualLength;
2602 }
2603
2604 static void osNetworkSystem_createServerStreamSocketImpl(JNIEnv* env,
2605         jclass clazz, jobject fileDescriptor, jboolean preferIPv4Stack) {
2606     // LOGD("ENTER createServerStreamSocketImpl");
2607
2608     int handle = createSocketFileDescriptor(env, fileDescriptor, SOCK_STREAM);
2609     if (handle < 0)
2610         return;
2611
2612     int value = 1;
2613     setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(int));
2614 }
2615
2616 /*
2617  * @param timeout in milliseconds.  If zero, block until data received
2618  */
2619 static jint osNetworkSystem_receiveStreamImpl(JNIEnv* env, jclass clazz,
2620         jobject fileDescriptor, jbyteArray data, jint offset, jint count,
2621         jint timeout) {
2622     // LOGD("ENTER receiveStreamImpl");
2623
2624     int result;
2625     int handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
2626
2627     if (handle == 0 || handle == -1) {
2628         throwSocketException(env, SOCKERR_BADSOCKET);
2629         return 0;
2630     }
2631
2632     // Cap read length to available buf size
2633     int spaceAvailable = env->GetArrayLength(data) - offset;
2634     int localCount = count < spaceAvailable? count : spaceAvailable;
2635
2636     jboolean isCopy;
2637     jbyte *body = env->GetByteArrayElements(data, &isCopy);
2638
2639     // set timeout
2640     struct timeval tv;
2641     tv.tv_sec = timeout / 1000;
2642     tv.tv_usec = (timeout % 1000) * 1000;
2643     setsockopt(handle, SOL_SOCKET, SO_RCVTIMEO, (struct timeval *)&tv,
2644                sizeof(struct timeval));
2645
2646     do {
2647         result = recv(handle, body + offset, localCount, SOCKET_NOFLAGS);
2648     } while (result < 0 && errno == EINTR);
2649
2650     env->ReleaseByteArrayElements(data, body, 0);
2651
2652     /*
2653      * If no bytes are read, return -1 to signal 'endOfFile'
2654      * to the Java input stream
2655      */
2656     if (0 < result) {
2657         return result;
2658     } else if (0 == result) {
2659         return -1;
2660     } else {
2661         // If EAGAIN or EWOULDBLOCK, read timed out
2662         if (errno == EAGAIN || errno == EWOULDBLOCK) {
2663             jniThrowException(env, "java/net/SocketTimeoutException",
2664                               netLookupErrorString(SOCKERR_TIMEOUT));
2665         } else {
2666             int err = convertError(errno);
2667             throwSocketException(env, err);
2668         }
2669         return 0;
2670     }
2671 }
2672
2673 static jint osNetworkSystem_sendStreamImpl(JNIEnv* env, jclass clazz,
2674         jobject fileDescriptor, jbyteArray data, jint offset, jint count) {
2675     // LOGD("ENTER sendStreamImpl");
2676
2677     int handle = 0;
2678     int result = 0, sent = 0;
2679
2680     jboolean isCopy;
2681     jbyte *message = env->GetByteArrayElements(data, &isCopy);
2682
2683     // Cap write length to available buf size
2684     int spaceAvailable = env->GetArrayLength(data) - offset;
2685     if (count > spaceAvailable) count = spaceAvailable;
2686
2687     while (sent < count) {
2688
2689         handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
2690         if (handle == 0 || handle == -1) {
2691             throwSocketException(env,
2692                     sent == 0 ? SOCKERR_BADSOCKET : SOCKERR_INTERRUPTED);
2693             env->ReleaseByteArrayElements(data, message, 0);
2694             return 0;
2695         }
2696
2697         // LOGD("before select %d", count);
2698         selectWait(handle, SEND_RETRY_TIME, SELECT_WRITE_TYPE);
2699         result = send(handle, (jbyte *)message + offset + sent,
2700                 (int) count - sent, SOCKET_NOFLAGS);
2701
2702         if (result < 0) {
2703             result = errno;
2704             if (result == EAGAIN ||result == EWOULDBLOCK) {
2705                 // LOGD("write blocked %d", sent);
2706                 continue;
2707             }
2708             env->ReleaseByteArrayElements(data, message, 0);
2709             int err = convertError(result);
2710             throwSocketException(env, err);
2711             return 0;
2712         }
2713         sent += result;
2714     }
2715
2716     env->ReleaseByteArrayElements(data, message, 0);
2717     return sent;
2718 }
2719
2720 static void osNetworkSystem_shutdownInputImpl(JNIEnv* env, jobject obj,
2721         jobject fileDescriptor) {
2722     // LOGD("ENTER shutdownInputImpl");
2723
2724     int ret;
2725     int handle;
2726
2727     handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
2728
2729     if (handle == 0 || handle == -1) {
2730         throwSocketException(env, SOCKERR_BADSOCKET);
2731         return;
2732     }
2733
2734     ret = shutdown(handle, SHUT_RD);
2735
2736     if (ret < 0) {
2737         int err = convertError(errno);
2738         throwSocketException(env, err);
2739         return;
2740     }
2741 }
2742
2743 static void osNetworkSystem_shutdownOutputImpl(JNIEnv* env, jobject obj,
2744         jobject fileDescriptor) {
2745     // LOGD("ENTER shutdownOutputImpl");
2746
2747     int ret;
2748     int handle;
2749
2750     handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
2751
2752     if (handle == 0 || handle == -1) {
2753         return;
2754     }
2755
2756     ret = shutdown(handle, SHUT_WR);
2757
2758     if (ret < 0) {
2759         int err = convertError(errno);
2760         throwSocketException(env, err);
2761         return;
2762     }
2763 }
2764
2765 static jint osNetworkSystem_sendDatagramImpl2(JNIEnv* env, jclass clazz,
2766         jobject fd, jbyteArray data, jint offset, jint length, jint port,
2767         jobject inetAddress) {
2768     // LOGD("ENTER sendDatagramImpl2");
2769
2770     jbyte *message;
2771     unsigned short nPort;
2772     int ret = 0, sent = 0;
2773     int handle = 0;
2774     struct sockaddr_storage sockaddrP;
2775
2776     if (inetAddress != NULL) {
2777         ret = inetAddressToSocketAddress(env, inetAddress, port, &sockaddrP);
2778         if (ret < 0)  // Exception has already been thrown.
2779             return 0;
2780
2781         handle = jniGetFDFromFileDescriptor(env, fd);
2782         if (handle == 0 || handle == -1) {
2783             throwSocketException(env, SOCKERR_BADDESC);
2784             return 0;
2785         }
2786     }
2787
2788     message = (jbyte*) malloc(length * sizeof(jbyte));
2789     if (message == NULL) {
2790         jniThrowException(env, "java/lang/OutOfMemoryError",
2791                 "couldn't allocate enough memory for readSocket");
2792         return 0;
2793     }
2794
2795     env->GetByteArrayRegion(data, offset, length, message);
2796
2797     while (sent < length) {
2798         handle = jniGetFDFromFileDescriptor(env, fd);
2799
2800         if (handle == 0 || handle == -1) {
2801             throwSocketException(env,
2802                     sent == 0 ? SOCKERR_BADDESC : SOCKERR_INTERRUPTED);
2803             free(message);
2804             return 0;
2805         }
2806
2807         ssize_t result;
2808         do {
2809             result = sendto(handle, (char *) (message + sent),
2810                     (int) (length - sent), SOCKET_NOFLAGS,
2811                     (struct sockaddr *) &sockaddrP, sizeof(sockaddrP));
2812         } while (result < 0 && errno == EINTR);
2813         if (result < 0) {
2814             int err = convertError(errno);
2815             throwSocketException(env, err);
2816             free(message);
2817             return 0;
2818         }
2819
2820         sent += result;
2821     }
2822
2823     free(message);
2824     return sent;
2825 }
2826
2827 static jint osNetworkSystem_selectImpl(JNIEnv* env, jclass clazz,
2828         jobjectArray readFDArray, jobjectArray writeFDArray, jint countReadC,
2829         jint countWriteC, jintArray outFlags, jlong timeout) {
2830     // LOGD("ENTER selectImpl");
2831
2832     struct timeval timeP;
2833     int result = 0;
2834     int size = 0;
2835     jobject gotFD;
2836     fd_set *fdset_read,*fdset_write;
2837     int handle;
2838     jboolean isCopy ;
2839     jint *flagArray;
2840     int val;
2841     unsigned int time_sec = (unsigned int)timeout/1000;
2842     unsigned int time_msec = (unsigned int)(timeout%1000);
2843
2844     fdset_read = (fd_set *)malloc(sizeof(fd_set));
2845     fdset_write = (fd_set *)malloc(sizeof(fd_set));
2846
2847     FD_ZERO(fdset_read);
2848     FD_ZERO(fdset_write);
2849
2850     for (val = 0; val<countReadC; val++) {
2851
2852         gotFD = env->GetObjectArrayElement(readFDArray,val);
2853
2854         handle = jniGetFDFromFileDescriptor(env, gotFD);
2855
2856         FD_SET(handle, fdset_read);
2857
2858         if (0 > (size - handle)) {
2859             size = handle;
2860         }
2861     }
2862
2863     for (val = 0; val<countWriteC; val++) {
2864
2865         gotFD = env->GetObjectArrayElement(writeFDArray,val);
2866
2867         handle = jniGetFDFromFileDescriptor(env, gotFD);
2868
2869         FD_SET(handle, fdset_write);
2870
2871         if (0 > (size - handle)) {
2872             size = handle;
2873         }
2874     }
2875
2876     /* the size is the max_fd + 1 */
2877     size =size + 1;
2878
2879     if (0 > size) {
2880         result = SOCKERR_FDSET_SIZEBAD;
2881     } else {
2882       /* only set when timeout >= 0 (non-block)*/
2883         if (0 <= timeout) {
2884
2885             timeP.tv_sec = time_sec;
2886             timeP.tv_usec = time_msec*1000;
2887
2888             result = sockSelect(size, fdset_read, fdset_write, NULL, &timeP);
2889
2890         } else {
2891             result = sockSelect(size, fdset_read, fdset_write, NULL, NULL);
2892         }
2893     }
2894
2895     if (0 < result) {
2896         /*output the result to a int array*/
2897         flagArray = env->GetIntArrayElements(outFlags, &isCopy);
2898
2899         for (val=0; val<countReadC; val++) {
2900             gotFD = env->GetObjectArrayElement(readFDArray,val);
2901
2902             handle = jniGetFDFromFileDescriptor(env, gotFD);
2903
2904             if (FD_ISSET(handle,fdset_read)) {
2905                 flagArray[val] = SOCKET_OP_READ;
2906             } else {
2907                 flagArray[val] = SOCKET_OP_NONE;
2908             }
2909         }
2910
2911         for (val=0; val<countWriteC; val++) {
2912
2913             gotFD = env->GetObjectArrayElement(writeFDArray,val);
2914
2915             handle = jniGetFDFromFileDescriptor(env, gotFD);
2916
2917             if (FD_ISSET(handle,fdset_write)) {
2918                 flagArray[val+countReadC] = SOCKET_OP_WRITE;
2919             } else {
2920                 flagArray[val+countReadC] = SOCKET_OP_NONE;
2921             }
2922         }
2923
2924         env->ReleaseIntArrayElements(outFlags, flagArray, 0);
2925     }
2926
2927     free(fdset_write);
2928     free(fdset_read);
2929
2930     /* return both correct and error result, let java handle the exception*/
2931     return result;
2932 }
2933
2934 static jobject osNetworkSystem_getSocketLocalAddressImpl(JNIEnv* env,
2935         jclass clazz, jobject fileDescriptor, jboolean preferIPv6Addresses) {
2936     // LOGD("ENTER getSocketLocalAddressImpl");
2937
2938     struct sockaddr_storage addr;
2939     socklen_t addrLen = sizeof(addr);
2940
2941     memset(&addr, 0, addrLen);
2942
2943
2944     int handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
2945     if (handle == 0 || handle == -1) {
2946         throwSocketException(env, SOCKERR_UNKNOWNSOCKET);
2947         return NULL;
2948     }
2949
2950     int result;
2951     result = getsockname(handle, (struct sockaddr *)&addr, &addrLen);
2952
2953     // Spec says ignore all errors
2954     return socketAddressToInetAddress(env, &addr);
2955 }
2956
2957 static jint osNetworkSystem_getSocketLocalPortImpl(JNIEnv* env, jclass clazz,
2958         jobject fileDescriptor, jboolean preferIPv6Addresses) {
2959     // LOGD("ENTER getSocketLocalPortImpl");
2960
2961     struct sockaddr_storage addr;
2962     socklen_t addrLen = sizeof(addr);
2963
2964     int handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
2965     int result;
2966
2967     if (handle == 0 || handle == -1) {
2968         throwSocketException(env, SOCKERR_UNKNOWNSOCKET);
2969         return 0;
2970     }
2971
2972     result = getsockname(handle, (struct sockaddr *)&addr, &addrLen);
2973
2974     if (0 != result) {
2975         // The java spec does not indicate any exceptions on this call
2976         return 0;
2977     } else {
2978         return getSocketAddressPort(&addr);
2979     }
2980 }
2981
2982 static jobject osNetworkSystem_getSocketOptionImpl(JNIEnv* env, jclass clazz,
2983         jobject fileDescriptor, jint anOption) {
2984     // LOGD("ENTER getSocketOptionImpl");
2985
2986     int handle;
2987     int intValue = 0;
2988     socklen_t intSize = sizeof(int);
2989     unsigned char byteValue = 0;
2990     socklen_t byteSize = sizeof(unsigned char);
2991     int result;
2992     struct sockaddr_storage sockVal;
2993     socklen_t sockSize = sizeof(sockVal);
2994
2995     handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
2996     if (handle == 0 || handle == -1) {
2997         throwSocketException(env, SOCKERR_BADDESC);
2998         return NULL;
2999     }
3000
3001     switch ((int) anOption & 0xffff) {
3002         case JAVASOCKOPT_SO_LINGER: {
3003             struct linger lingr;
3004             socklen_t size = sizeof(struct linger);
3005             result = getsockopt(handle, SOL_SOCKET, SO_LINGER, &lingr, &size);
3006             if (0 != result) {
3007                 throwSocketException(env, convertError(errno));
3008                 return NULL;
3009             }
3010             if (!lingr.l_onoff) {
3011                 intValue = -1;
3012             } else {
3013                 intValue = lingr.l_linger;
3014             }
3015             return newJavaLangInteger(env, intValue);
3016         }
3017         case JAVASOCKOPT_TCP_NODELAY: {
3018             if ((anOption >> 16) & BROKEN_TCP_NODELAY) {
3019                 return NULL;
3020             }
3021             result = getsockopt(handle, IPPROTO_TCP, TCP_NODELAY, &intValue, &intSize);
3022             if (0 != result) {
3023                 throwSocketException(env, convertError(errno));
3024                 return NULL;
3025             }
3026             return newJavaLangBoolean(env, intValue);
3027         }
3028         case JAVASOCKOPT_MCAST_TTL: {
3029             if ((anOption >> 16) & BROKEN_MULTICAST_TTL) {
3030                 return newJavaLangByte(env, 0);
3031             }
3032             result = getOrSetSocketOption(SOCKOPT_GET, handle, IP_MULTICAST_TTL,
3033                                           IPV6_MULTICAST_HOPS, &byteValue,
3034                                           &byteSize);
3035             if (0 != result) {
3036                 throwSocketException(env, convertError(errno));
3037                 return NULL;
3038             }
3039             return newJavaLangByte(env, (jbyte)(byteValue & 0xFF));
3040         }
3041         case JAVASOCKOPT_MCAST_INTERFACE: {
3042             if ((anOption >> 16) & BROKEN_MULTICAST_IF) {
3043                 return NULL;
3044             }
3045             result = getsockopt(handle, IPPROTO_IP, IP_MULTICAST_IF, &sockVal, &sockSize);
3046             if (0 != result) {
3047                 throwSocketException(env, convertError(errno));
3048                 return NULL;
3049             }
3050             // This option is IPv4-only.
3051             sockVal.ss_family = AF_INET;
3052             return socketAddressToInetAddress(env, &sockVal);
3053         }
3054         case JAVASOCKOPT_IP_MULTICAST_IF2: {
3055             if ((anOption >> 16) & BROKEN_MULTICAST_IF) {
3056                 return NULL;
3057             }
3058             struct ip_mreqn multicastRequest;
3059             int interfaceIndex;
3060             socklen_t optionLength;
3061             int addressFamily = getSocketAddressFamily(handle);
3062             switch (addressFamily) {
3063                 case AF_INET:
3064                     optionLength = sizeof(multicastRequest);
3065                     result = getsockopt(handle, IPPROTO_IP, IP_MULTICAST_IF,
3066                                         &multicastRequest, &optionLength);
3067                     if (result == 0)
3068                         interfaceIndex = multicastRequest.imr_ifindex;
3069                     break;
3070                 case AF_INET6:
3071                     optionLength = sizeof(interfaceIndex);
3072                     result = getsockopt(handle, IPPROTO_IPV6, IPV6_MULTICAST_IF,
3073                                         &interfaceIndex, &optionLength);
3074                     break;
3075                 default:
3076                     throwSocketException(env, SOCKERR_BADAF);
3077                     return NULL;
3078             }
3079
3080             if (0 != result) {
3081                 throwSocketException(env, convertError(errno));
3082                 return NULL;
3083             }
3084
3085             return newJavaLangInteger(env, interfaceIndex);
3086         }
3087         case JAVASOCKOPT_SO_SNDBUF: {
3088             result = getsockopt(handle, SOL_SOCKET, SO_SNDBUF, &intValue, &intSize);
3089             if (0 != result) {
3090                 throwSocketException(env, convertError(errno));
3091                 return NULL;
3092             }
3093             return newJavaLangInteger(env, intValue);
3094         }
3095         case JAVASOCKOPT_SO_RCVBUF: {
3096             result = getsockopt(handle, SOL_SOCKET, SO_RCVBUF, &intValue, &intSize);
3097             if (0 != result) {
3098                 throwSocketException(env, convertError(errno));
3099                 return NULL;
3100             }
3101             return newJavaLangInteger(env, intValue);
3102         }
3103         case JAVASOCKOPT_SO_BROADCAST: {
3104             result = getsockopt(handle, SOL_SOCKET, SO_BROADCAST, &intValue, &intSize);
3105             if (0 != result) {
3106                 throwSocketException(env, convertError(errno));
3107                 return NULL;
3108             }
3109             return newJavaLangBoolean(env, intValue);
3110         }
3111         case JAVASOCKOPT_SO_REUSEADDR: {
3112             result = getsockopt(handle, SOL_SOCKET, SO_REUSEADDR, &intValue, &intSize);
3113             if (0 != result) {
3114                 throwSocketException(env, convertError(errno));
3115                 return NULL;
3116             }
3117             return newJavaLangBoolean(env, intValue);
3118         }
3119         case JAVASOCKOPT_SO_KEEPALIVE: {
3120             result = getsockopt(handle, SOL_SOCKET, SO_KEEPALIVE, &intValue, &intSize);
3121             if (0 != result) {
3122                 throwSocketException(env, convertError(errno));
3123                 return NULL;
3124             }
3125             return newJavaLangBoolean(env, intValue);
3126         }
3127         case JAVASOCKOPT_SO_OOBINLINE: {
3128             result = getsockopt(handle, SOL_SOCKET, SO_OOBINLINE, &intValue, &intSize);
3129             if (0 != result) {
3130                 throwSocketException(env, convertError(errno));
3131                 return NULL;
3132             }
3133             return newJavaLangBoolean(env, intValue);
3134         }
3135         case JAVASOCKOPT_IP_MULTICAST_LOOP: {
3136             result = getOrSetSocketOption(SOCKOPT_GET, handle,
3137                                           IP_MULTICAST_LOOP,
3138                                           IPV6_MULTICAST_LOOP, &intValue,
3139                                           &intSize);
3140             if (0 != result) {
3141                 throwSocketException(env, convertError(errno));
3142                 return NULL;
3143             }
3144             return newJavaLangBoolean(env, intValue);
3145         }
3146         case JAVASOCKOPT_IP_TOS: {
3147             result = getOrSetSocketOption(SOCKOPT_GET, handle, IP_TOS,
3148                                           IPV6_TCLASS, &intValue, &intSize);
3149             if (0 != result) {
3150                 throwSocketException(env, convertError(errno));
3151                 return NULL;
3152             }
3153             return newJavaLangInteger(env, intValue);
3154         }
3155         case JAVASOCKOPT_SO_RCVTIMEOUT: {
3156             struct timeval timeout;
3157             socklen_t size = sizeof(timeout);
3158             result = getsockopt(handle, SOL_SOCKET, SO_RCVTIMEO, &timeout, &size);
3159             if (0 != result) {
3160                 throwSocketException(env, convertError(errno));
3161                 return NULL;
3162             }
3163             return newJavaLangInteger(env, timeout.tv_sec * 1000 + timeout.tv_usec/1000);
3164         }
3165         default: {
3166             throwSocketException(env, SOCKERR_OPTUNSUPP);
3167             return NULL;
3168         }
3169     }
3170
3171 }
3172
3173 static void osNetworkSystem_setSocketOptionImpl(JNIEnv* env, jclass clazz,
3174         jobject fileDescriptor, jint anOption, jobject optVal) {
3175     // LOGD("ENTER setSocketOptionImpl");
3176
3177     int handle, result;
3178     int intVal;
3179     socklen_t intSize = sizeof(int);
3180     unsigned char byteVal;
3181     socklen_t byteSize = sizeof(unsigned char);
3182     struct sockaddr_storage sockVal;
3183     int sockSize = sizeof(sockVal);
3184
3185     if (env->IsInstanceOf(optVal, gCachedFields.integer_class)) {
3186         intVal = (int) env->GetIntField(optVal, gCachedFields.integer_class_value);
3187     } else if (env->IsInstanceOf(optVal, gCachedFields.boolean_class)) {
3188         intVal = (int) env->GetBooleanField(optVal, gCachedFields.boolean_class_value);
3189     } else if (env->IsInstanceOf(optVal, gCachedFields.byte_class)) {
3190         byteVal = (int) env->GetByteField(optVal, gCachedFields.byte_class_value);
3191     } else if (env->IsInstanceOf(optVal, gCachedFields.iaddr_class)) {
3192         if (inetAddressToSocketAddress(env, optVal, 0, &sockVal) < 0) {
3193             // Exception has already been thrown.
3194             return;
3195         }
3196     } else if (env->IsInstanceOf(optVal, gCachedFields.genericipmreq_class)) {
3197         // we'll use optVal directly
3198     } else {
3199         throwSocketException(env, SOCKERR_OPTUNSUPP);
3200         return;
3201     }
3202
3203     handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
3204     if (handle == 0 || handle == -1) {
3205         throwSocketException(env, SOCKERR_BADDESC);
3206         return;
3207     }
3208
3209     switch ((int) anOption & 0xffff) {
3210         case JAVASOCKOPT_SO_LINGER: {
3211             struct linger lingr;
3212             lingr.l_onoff = intVal > 0 ? 1 : 0;
3213             lingr.l_linger = intVal;
3214             result = setsockopt(handle, SOL_SOCKET, SO_LINGER, &lingr,
3215                     sizeof(struct linger));
3216             if (0 != result) {
3217                 throwSocketException(env, convertError(errno));
3218                 return;
3219             }
3220             break;
3221         }
3222
3223         case JAVASOCKOPT_TCP_NODELAY: {
3224             if ((anOption >> 16) & BROKEN_TCP_NODELAY) {
3225                 return;
3226             }
3227             result = setsockopt(handle, IPPROTO_TCP, TCP_NODELAY, &intVal, intSize);
3228             if (0 != result) {
3229                 throwSocketException(env, convertError(errno));
3230                 return;
3231             }
3232             break;
3233         }
3234
3235         case JAVASOCKOPT_MCAST_TTL: {
3236             if ((anOption >> 16) & BROKEN_MULTICAST_TTL) {
3237                 return;
3238             }
3239             result = getOrSetSocketOption(SOCKOPT_SET, handle, IP_MULTICAST_TTL,
3240                                           IPV6_MULTICAST_HOPS, &byteVal,
3241                                           &byteSize);
3242             if (0 != result) {
3243                 throwSocketException(env, convertError(errno));
3244                 return;
3245             }
3246             break;
3247         }
3248
3249         case JAVASOCKOPT_MCAST_ADD_MEMBERSHIP: {
3250             mcastAddDropMembership(env, handle, optVal,
3251                     (anOption >> 16) & BROKEN_MULTICAST_IF, IP_ADD_MEMBERSHIP);
3252             break;
3253         }
3254
3255         case JAVASOCKOPT_MCAST_DROP_MEMBERSHIP: {
3256             mcastAddDropMembership(env, handle, optVal,
3257                     (anOption >> 16) & BROKEN_MULTICAST_IF, IP_DROP_MEMBERSHIP);
3258             break;
3259         }
3260
3261         case JAVASOCKOPT_MCAST_INTERFACE: {
3262             if ((anOption >> 16) & BROKEN_MULTICAST_IF) {
3263                 return;
3264             }
3265             // This call is IPv4 only.
3266             if (getSocketAddressFamily(handle) != AF_INET) {
3267                 throwSocketException(env, SOCKERR_BADAF);
3268                 return;
3269             }
3270             struct ip_mreqn mcast_req;
3271             memset(&mcast_req, 0, sizeof(mcast_req));
3272             struct sockaddr_in *sin = (struct sockaddr_in *) &sockVal;
3273             mcast_req.imr_address = sin->sin_addr;
3274             result = setsockopt(handle, IPPROTO_IP, IP_MULTICAST_IF,
3275                                 &mcast_req, sizeof(mcast_req));
3276             if (0 != result) {
3277                 throwSocketException(env, convertError(errno));
3278                 return;
3279             }
3280             break;
3281         }
3282
3283         case JAVASOCKOPT_IP_MULTICAST_IF2: {
3284             if ((anOption >> 16) & BROKEN_MULTICAST_IF) {
3285                 return;
3286             }
3287             int addressFamily = getSocketAddressFamily(handle);
3288             int interfaceIndex = intVal;
3289             void *optionValue;
3290             socklen_t optionLength;
3291             struct ip_mreqn multicastRequest;
3292             switch (addressFamily) {
3293                 case AF_INET:
3294                     // IP_MULTICAST_IF expects a pointer to a struct ip_mreqn.
3295                     memset(&multicastRequest, 0, sizeof(multicastRequest));
3296                     multicastRequest.imr_ifindex = interfaceIndex;
3297                     optionValue = &multicastRequest;
3298                     optionLength = sizeof(multicastRequest);
3299                     break;
3300                 case AF_INET6:
3301                     // IPV6_MULTICAST_IF expects a pointer to an integer.
3302                     optionValue = &interfaceIndex;
3303                     optionLength = sizeof(interfaceIndex);
3304                     break;
3305                 default:
3306                     throwSocketException(env, SOCKERR_BADAF);
3307                     return;
3308             }
3309             result = getOrSetSocketOption(SOCKOPT_SET, handle,
3310                     IP_MULTICAST_IF, IPV6_MULTICAST_IF, optionValue,
3311                     &optionLength);
3312             if (0 != result) {
3313                 throwSocketException(env, convertError(errno));
3314                 return;
3315             }
3316             break;
3317         }
3318
3319         case JAVASOCKOPT_SO_SNDBUF: {
3320             result = setsockopt(handle, SOL_SOCKET, SO_SNDBUF, &intVal, intSize);
3321             if (0 != result) {
3322                 throwSocketException(env, convertError(errno));
3323                 return;
3324             }
3325             break;
3326         }
3327
3328         case JAVASOCKOPT_SO_RCVBUF: {
3329             result = setsockopt(handle, SOL_SOCKET, SO_RCVBUF, &intVal, intSize);
3330             if (0 != result) {
3331                 throwSocketException(env, convertError(errno));
3332                 return;
3333             }
3334             break;
3335         }
3336
3337         case JAVASOCKOPT_SO_BROADCAST: {
3338             result = setsockopt(handle, SOL_SOCKET, SO_BROADCAST, &intVal, intSize);
3339             if (0 != result) {
3340                 throwSocketException(env, convertError(errno));
3341                 return;
3342             }
3343             break;
3344         }
3345
3346         case JAVASOCKOPT_SO_REUSEADDR: {
3347             result = setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, &intVal, intSize);
3348             if (0 != result) {
3349                 throwSocketException(env, convertError(errno));
3350                 return;
3351             }
3352             break;
3353         }
3354         case JAVASOCKOPT_SO_KEEPALIVE: {
3355             result = setsockopt(handle, SOL_SOCKET, SO_KEEPALIVE, &intVal, intSize);
3356             if (0 != result) {
3357                 throwSocketException(env, convertError(errno));
3358                 return;
3359             }
3360             break;
3361         }
3362
3363         case JAVASOCKOPT_SO_OOBINLINE: {
3364             result = setsockopt(handle, SOL_SOCKET, SO_OOBINLINE, &intVal, intSize);
3365             if (0 != result) {
3366                 throwSocketException(env, convertError(errno));
3367                 return;
3368             }
3369             break;
3370         }
3371
3372         case JAVASOCKOPT_IP_MULTICAST_LOOP: {
3373             result = getOrSetSocketOption(SOCKOPT_SET, handle,
3374                                           IP_MULTICAST_LOOP,
3375                                           IPV6_MULTICAST_LOOP, &intVal,
3376                                           &intSize);
3377             if (0 != result) {
3378                 throwSocketException(env, convertError(errno));
3379                 return;
3380             }
3381             break;
3382         }
3383
3384         case JAVASOCKOPT_IP_TOS: {
3385             result = getOrSetSocketOption(SOCKOPT_SET, handle, IP_TOS,
3386                                           IPV6_TCLASS, &intVal, &intSize);
3387             if (0 != result) {
3388                 throwSocketException(env, convertError(errno));
3389                 return;
3390             }
3391             break;
3392         }
3393
3394         case JAVASOCKOPT_REUSEADDR_AND_REUSEPORT: {
3395             // SO_REUSEPORT doesn't need to get set on this System
3396             result = setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, &intVal, intSize);
3397             if (0 != result) {
3398                 throwSocketException(env, convertError(errno));
3399                 return;
3400             }
3401             break;
3402         }
3403
3404         case JAVASOCKOPT_SO_RCVTIMEOUT: {
3405             struct timeval timeout;
3406             timeout.tv_sec = intVal / 1000;
3407             timeout.tv_usec = (intVal % 1000) * 1000;
3408             result = setsockopt(handle, SOL_SOCKET, SO_RCVTIMEO, &timeout,
3409                     sizeof(struct timeval));
3410             if (0 != result) {
3411                 throwSocketException(env, convertError(errno));
3412                 return;
3413             }
3414             break;
3415         }
3416
3417         default: {
3418             throwSocketException(env, SOCKERR_OPTUNSUPP);
3419         }
3420     }
3421 }
3422
3423 static jint osNetworkSystem_getSocketFlagsImpl(JNIEnv* env, jclass clazz) {
3424     // LOGD("ENTER getSocketFlagsImpl");
3425
3426     // Not implemented by harmony
3427     return 0;
3428 }
3429
3430 static void osNetworkSystem_socketCloseImpl(JNIEnv* env, jclass clazz,
3431         jobject fileDescriptor) {
3432     // LOGD("ENTER socketCloseImpl");
3433
3434     int handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
3435
3436     if (handle == 0 || handle == -1) {
3437         throwSocketException(env, SOCKERR_BADSOCKET);
3438         return;
3439     }
3440
3441     jniSetFileDescriptorOfFD(env, fileDescriptor, -1);
3442
3443     close(handle);
3444 }
3445
3446 static jobject osNetworkSystem_getHostByAddrImpl(JNIEnv* env, jclass clazz,
3447         jbyteArray addrStr) {
3448     // LOGD("ENTER getHostByAddrImpl");
3449
3450     if (addrStr == NULL) {
3451         throwNullPointerException(env);
3452         return JNI_FALSE;
3453     }
3454
3455     jstring address = (jstring)newJavaLangString(env, addrStr);
3456     jstring result;
3457     const char* addr = env->GetStringUTFChars(address, NULL);
3458
3459     struct hostent* ent = gethostbyaddr(addr, strlen(addr), AF_INET);
3460
3461     if (ent != NULL  && ent->h_name != NULL) {
3462         result = env->NewStringUTF(ent->h_name);
3463     } else {
3464         result = NULL;
3465     }
3466
3467     env->ReleaseStringUTFChars(address, addr);
3468
3469     return result;
3470 }
3471
3472 static jobject osNetworkSystem_getHostByNameImpl(JNIEnv* env, jclass clazz,
3473         jstring nameStr, jboolean preferIPv6Addresses) {
3474     // LOGD("ENTER getHostByNameImpl");
3475
3476     if (nameStr == NULL) {
3477         throwNullPointerException(env);
3478         return NULL;
3479     }
3480
3481     const char* name = env->GetStringUTFChars(nameStr, NULL);
3482
3483     if (useAdbNetworking) {
3484
3485         union {
3486             struct in_addr a;
3487             jbyte j[4];
3488         } outaddr;
3489
3490         // LOGD("ADB networking: +gethostbyname '%s'", name);
3491         int err;
3492         err = adb_networking_gethostbyname(name, &(outaddr.a));
3493
3494         env->ReleaseStringUTFChars(nameStr, name);
3495 #if 0
3496         LOGD("ADB networking: -gethostbyname err %d addr 0x%08x %u.%u.%u.%u",
3497                 err, (unsigned int)outaddr.a.s_addr,
3498                 outaddr.j[0],outaddr.j[1],
3499                 outaddr.j[2],outaddr.j[3]);
3500 #endif
3501
3502         if (err < 0) {
3503             return NULL;
3504         } else {
3505             jbyteArray addr = env->NewByteArray(4);
3506             env->SetByteArrayRegion(addr, 0, 4, outaddr.j);
3507             return addr;
3508         }
3509     } else {
3510
3511         // normal case...no adb networking
3512         struct hostent* ent = gethostbyname(name);
3513
3514         env->ReleaseStringUTFChars(nameStr, name);
3515
3516         if (ent != NULL  && ent->h_length > 0) {
3517             jbyteArray addr = env->NewByteArray(4);
3518             jbyte v[4];
3519             memcpy(v, ent->h_addr, 4);
3520             env->SetByteArrayRegion(addr, 0, 4, v);
3521             return addr;
3522         } else {
3523             return NULL;
3524         }
3525     }
3526 }
3527
3528 static void osNetworkSystem_setInetAddressImpl(JNIEnv* env, jobject obj,
3529         jobject sender, jbyteArray address) {
3530     // LOGD("ENTER setInetAddressImpl");
3531
3532     env->SetObjectField(sender, gCachedFields.iaddr_ipaddress, address);
3533 }
3534
3535 // TODO: rewrite this method in Java and make it support IPv6.
3536 static jobject osNetworkSystem_inheritedChannelImpl(JNIEnv* env, jobject obj) {
3537     // LOGD("ENTER inheritedChannelImpl");
3538
3539     int socket = 0;
3540     int opt;
3541     socklen_t length = sizeof(opt);
3542     int socket_type;
3543     struct sockaddr_in local_addr;
3544     struct sockaddr_in remote_addr;
3545     jclass channel_class, socketaddr_class, serverSocket_class, socketImpl_class;
3546     jobject channel_object = NULL, socketaddr_object, serverSocket_object;
3547     jobject fd_object, addr_object, localAddr_object, socketImpl_object;
3548     jfieldID port_field, socketaddr_field, bound_field, fd_field;
3549     jfieldID serverSocket_field, socketImpl_field, addr_field, localAddr_field;
3550     jmethodID channel_new;
3551     jbyteArray addr_array;
3552     struct sockaddr_in *sock;
3553     jbyte * address;
3554     jbyte * localAddr;
3555     jboolean jtrue = JNI_TRUE;
3556
3557     if (0 != getsockopt(socket, SOL_SOCKET, SO_TYPE, &opt, &length)) {
3558         return NULL;
3559     }
3560     if (SOCK_STREAM !=opt && SOCK_DGRAM !=opt) {
3561         return NULL;
3562     }
3563     socket_type = opt;
3564
3565     length  = sizeof(struct sockaddr);
3566     if (0 != getsockname(socket, (struct sockaddr *)&local_addr, &length)) {
3567         return NULL;
3568     } else {
3569         if (AF_INET != local_addr.sin_family || length != sizeof(struct sockaddr)) {
3570             return NULL;
3571         }
3572         localAddr = (jbyte*) malloc(sizeof(jbyte)*4);
3573         if (NULL == localAddr) {
3574             return NULL;
3575         }
3576         memcpy (localAddr, &(local_addr.sin_addr.s_addr), 4);
3577     }
3578     if (0 != getpeername(socket, (struct sockaddr *)&remote_addr, &length)) {
3579         remote_addr.sin_port = 0;
3580         remote_addr.sin_addr.s_addr = 0;
3581         address = (jbyte*) malloc(sizeof(jbyte)*4);
3582         bzero(address, sizeof(jbyte)*4);
3583     } else {
3584         if (AF_INET != remote_addr.sin_family
3585                 || length != sizeof(struct sockaddr)) {
3586             return NULL;
3587         }
3588         address = (jbyte*) malloc(sizeof(jbyte)*4);
3589         memcpy (address, &(remote_addr.sin_addr.s_addr), 4);
3590     }
3591
3592     // analysis end, begin pack to java
3593     if (SOCK_STREAM == opt) {
3594         if (remote_addr.sin_port!=0) {
3595             //socket
3596             channel_class = env->FindClass(
3597                     "org/apache/harmony/nio/internal/SocketChannelImpl");
3598             if (NULL == channel_class) {
3599                 goto clean;
3600             }
3601
3602             channel_new = env->GetMethodID(channel_class, "<init>", "()V");
3603             if (NULL == channel_new) {
3604                 goto clean;
3605             }
3606             channel_object = env->NewObject(channel_class, channel_new);
3607             if (NULL == channel_object) {
3608                 goto clean;
3609             }
3610             // new and set FileDescript
3611
3612             fd_field = env->GetFieldID(channel_class, "fd",
3613                     "java/io/FielDescriptor");
3614             fd_object = env->GetObjectField(channel_object, fd_field);
3615             if (NULL == fd_object) {
3616                 goto clean;
3617             }
3618
3619             jniSetFileDescriptorOfFD(env, fd_object, socket);
3620
3621             // local port
3622             port_field = env->GetFieldID(channel_class, "localPort", "I");
3623             env->SetIntField(channel_object, port_field,
3624                     ntohs(local_addr.sin_port));
3625
3626             // new and set remote addr
3627             addr_array = env->NewByteArray((jsize)4);
3628             env->SetByteArrayRegion(addr_array, (jsize)0, (jsize)4, address);
3629             addr_object = env->NewObject(gCachedFields.i4addr_class,
3630                     gCachedFields.i4addr_class_init, addr_array);
3631             if (NULL == addr_object) {
3632                 goto clean;
3633             }
3634             socketaddr_class = env->FindClass("java/net/InetSocketAddress");
3635             socketaddr_field = env->GetFieldID(channel_class, "connectAddress",
3636                     "Ljava/net/InetSocketAddress;");
3637             socketaddr_object = env->GetObjectField(channel_object,
3638                     socketaddr_field);
3639             if (NULL == socketaddr_object) {
3640                 goto clean;
3641             }
3642
3643             // localAddr
3644             socketaddr_class = env->FindClass("java/net/InetSocketAddress");
3645             socketaddr_field = env->GetFieldID(channel_class, "connectAddress",
3646                      "Ljava/net/InetSocketAddress;");
3647             socketaddr_object = env->GetObjectField(channel_object,
3648                      socketaddr_field);
3649
3650             localAddr_field = env->GetFieldID(channel_class, "localAddress",
3651                      "Ljava/net/Inet4Address;");
3652             addr_array = env->NewByteArray((jsize)4);
3653             env->SetByteArrayRegion(addr_array, (jsize)0, (jsize)4, localAddr);
3654             localAddr_object = env->NewObject(gCachedFields.i4addr_class,
3655                      gCachedFields.i4addr_class_init, addr_array);
3656             jfieldID socketaddr_field = env->GetFieldID(channel_class,
3657                      "connectAddress", "Ljava/net/InetSocketAddress;");
3658             jobject socketaddr_object = env->GetObjectField(channel_object,
3659                      socketaddr_field);
3660             env->SetObjectField(socketaddr_object, localAddr_field,
3661                      localAddr_object);
3662             if (NULL == localAddr_object) {
3663                 goto clean;
3664             }
3665
3666
3667             // set port
3668             port_field = env->GetFieldID(socketaddr_class, "port", "I");
3669             env->SetIntField(socketaddr_object, port_field,
3670                     ntohs(remote_addr.sin_port));
3671
3672             // set bound
3673             if (0 != local_addr.sin_port) {
3674                 bound_field = env->GetFieldID(channel_class, "isBound", "Z");
3675                 env->SetBooleanField(channel_object, bound_field, jtrue);
3676             }
3677
3678         } else {
3679             //serverSocket
3680             channel_class = env->FindClass(
3681                     "org/apache/harmony/nio/internal/ServerSocketChannelImpl");
3682             if (NULL == channel_class) {
3683                 goto clean;
3684             }
3685
3686             channel_new = env->GetMethodID(channel_class, "<init>", "()V");
3687             if (NULL == channel_new) {
3688                 goto clean;
3689             }
3690             channel_object = env->NewObject(channel_class, channel_new);
3691             if (NULL == channel_object) {
3692                 goto clean;
3693             }
3694
3695             serverSocket_field = env->GetFieldID(channel_class, "socket",
3696                     "Ljava/net/ServerSocket;");
3697             serverSocket_class = env->FindClass("Ljava/net/ServerSocket;");
3698             serverSocket_object = env->GetObjectField(channel_object,
3699                     serverSocket_field);
3700             // set bound
3701             if (0 != local_addr.sin_port) {
3702                 bound_field = env->GetFieldID(channel_class, "isBound", "Z");
3703                 env->SetBooleanField(channel_object, bound_field, jtrue);
3704                 bound_field = env->GetFieldID(serverSocket_class, "isBound", "Z");
3705                 env->SetBooleanField(serverSocket_object, bound_field, jtrue);
3706             }
3707             // localAddr
3708             socketImpl_class = env->FindClass("java/net/SocketImpl");
3709             socketImpl_field = env->GetFieldID(channel_class, "impl",
3710                     "Ljava/net/SocketImpl;");
3711             socketImpl_object =  env->GetObjectField(channel_object,
3712                     socketImpl_field);
3713             if (NULL == socketImpl_object) {
3714                  goto clean;
3715             }
3716
3717             localAddr_field = env->GetFieldID(channel_class, "localAddress",
3718                     "Ljava/net/InetAddress;");
3719             memset(address, 0, 4);
3720             env->SetByteArrayRegion(addr_array, (jsize)0, (jsize)4, address);
3721             localAddr_object = env->NewObject(gCachedFields.i4addr_class,
3722                     gCachedFields.i4addr_class_init, addr_array);
3723             if (NULL == localAddr_object) {
3724                  goto clean;
3725             }
3726             env->SetObjectField(socketImpl_object, localAddr_field,
3727                     localAddr_object);
3728             addr_array = env->NewByteArray((jsize)4);
3729             env->SetByteArrayRegion(addr_array, (jsize)0, (jsize)4, localAddr);
3730             env->SetObjectField(localAddr_object,
3731                     gCachedFields.iaddr_ipaddress, addr_array);
3732
3733             // set port
3734             port_field = env->GetFieldID(socketImpl_class, "localport", "I");
3735             env->SetIntField(socketImpl_object, port_field,
3736                     ntohs(local_addr.sin_port));
3737         }
3738     } else {
3739         //Datagram Socket
3740         // new DatagramChannel
3741         channel_class = env->FindClass(
3742                 "org/apache/harmony/nio/internal/DatagramChannelImpl");
3743         if (NULL == channel_class) {
3744             goto clean;
3745         }
3746
3747         channel_new = env->GetMethodID(channel_class, "<init>", "()V");
3748         if (NULL == channel_new) {
3749             goto clean;
3750         }
3751         channel_object = env->NewObject(channel_class, channel_new);
3752         if (NULL == channel_object) {
3753             goto clean;
3754         }
3755
3756         // new and set FileDescript
3757         fd_field = env->GetFieldID(channel_class, "fd", "java/io/FileDescriptor");
3758         fd_object = env->GetObjectField(channel_object, fd_field);
3759         if (NULL == fd_object) {
3760             goto clean;
3761         }
3762
3763         jniSetFileDescriptorOfFD(env, fd_object, socket);
3764
3765         port_field = env->GetFieldID(channel_class, "localPort", "I");
3766         env->SetIntField(channel_object, port_field, ntohs(local_addr.sin_port));
3767
3768         // new and set remote addr
3769         addr_array = env->NewByteArray((jsize)4);
3770         env->SetByteArrayRegion(addr_array, (jsize)0, (jsize)4, address);
3771         addr_object = env->NewObject(gCachedFields.iaddr_class,
3772                 gCachedFields.i4addr_class_init, addr_array);
3773         if (NULL == addr_object) {
3774             goto clean;
3775         }
3776         socketaddr_class = env->FindClass("java/net/InetSocketAddress");
3777         socketaddr_field = env->GetFieldID(channel_class, "connectAddress",
3778                 "Ljava/net/InetSocketAddress;");
3779         socketaddr_object = env->GetObjectField(channel_object, socketaddr_field);
3780         if (NULL == socketaddr_object) {
3781             goto clean;
3782         }
3783
3784         // set bound
3785         if (0 != local_addr.sin_port) {
3786             bound_field = env->GetFieldID(channel_class, "isBound", "Z");
3787             env->SetBooleanField(channel_object, bound_field, jtrue);
3788         }
3789     }
3790 clean:
3791     free(address);
3792     free(localAddr);
3793     return channel_object;
3794 }
3795
3796 /*
3797  * JNI registration.
3798  */
3799 static JNINativeMethod gMethods[] = {
3800     /* name, signature, funcPtr */
3801     { "oneTimeInitializationImpl",         "(Z)V",                                                                     (void*) osNetworkSystem_oneTimeInitializationImpl          },
3802     { "createStreamSocketImpl",            "(Ljava/io/FileDescriptor;Z)V",                                             (void*) osNetworkSystem_createStreamSocketImpl             },
3803     { "createDatagramSocketImpl",          "(Ljava/io/FileDescriptor;Z)V",                                             (void*) osNetworkSystem_createDatagramSocketImpl           },
3804     { "readSocketImpl",                    "(Ljava/io/FileDescriptor;[BIII)I",                                         (void*) osNetworkSystem_readSocketImpl                     },
3805     { "readSocketDirectImpl",              "(Ljava/io/FileDescriptor;IIII)I",                                          (void*) osNetworkSystem_readSocketDirectImpl               },
3806     { "writeSocketImpl",                   "(Ljava/io/FileDescriptor;[BII)I",                                          (void*) osNetworkSystem_writeSocketImpl                    },
3807     { "writeSocketDirectImpl",             "(Ljava/io/FileDescriptor;III)I",                                           (void*) osNetworkSystem_writeSocketDirectImpl              },
3808     { "setNonBlockingImpl",                "(Ljava/io/FileDescriptor;Z)V",                                             (void*) osNetworkSystem_setNonBlockingImpl                 },
3809     { "connectSocketImpl",                 "(Ljava/io/FileDescriptor;ILjava/net/InetAddress;I)I",                      (void*) osNetworkSystem_connectSocketImpl                  },
3810     { "connectWithTimeoutSocketImpl",      "(Ljava/io/FileDescriptor;IILjava/net/InetAddress;II[B)I",                  (void*) osNetworkSystem_connectWithTimeoutSocketImpl       },
3811     { "connectStreamWithTimeoutSocketImpl","(Ljava/io/FileDescriptor;IIILjava/net/InetAddress;)V",                     (void*) osNetworkSystem_connectStreamWithTimeoutSocketImpl },
3812     { "socketBindImpl",                    "(Ljava/io/FileDescriptor;ILjava/net/InetAddress;)V",                       (void*) osNetworkSystem_socketBindImpl                     },
3813     { "listenStreamSocketImpl",            "(Ljava/io/FileDescriptor;I)V",                                             (void*) osNetworkSystem_listenStreamSocketImpl             },
3814     { "availableStreamImpl",               "(Ljava/io/FileDescriptor;)I",                                              (void*) osNetworkSystem_availableStreamImpl                },
3815     { "acceptSocketImpl",                  "(Ljava/io/FileDescriptor;Ljava/net/SocketImpl;Ljava/io/FileDescriptor;I)V",(void*) osNetworkSystem_acceptSocketImpl                   },
3816     { "supportsUrgentDataImpl",            "(Ljava/io/FileDescriptor;)Z",                                              (void*) osNetworkSystem_supportsUrgentDataImpl             },
3817     { "sendUrgentDataImpl",                "(Ljava/io/FileDescriptor;B)V",                                             (void*) osNetworkSystem_sendUrgentDataImpl                 },
3818     { "connectDatagramImpl2",              "(Ljava/io/FileDescriptor;IILjava/net/InetAddress;)V",                      (void*) osNetworkSystem_connectDatagramImpl2               },
3819     { "disconnectDatagramImpl",            "(Ljava/io/FileDescriptor;)V",                                              (void*) osNetworkSystem_disconnectDatagramImpl             },
3820     { "peekDatagramImpl",                  "(Ljava/io/FileDescriptor;Ljava/net/InetAddress;I)I",                       (void*) osNetworkSystem_peekDatagramImpl                   },
3821     { "receiveDatagramImpl",               "(Ljava/io/FileDescriptor;Ljava/net/DatagramPacket;[BIIIZ)I",               (void*) osNetworkSystem_receiveDatagramImpl                },
3822     { "receiveDatagramDirectImpl",         "(Ljava/io/FileDescriptor;Ljava/net/DatagramPacket;IIIIZ)I",                (void*) osNetworkSystem_receiveDatagramDirectImpl          },
3823     { "recvConnectedDatagramImpl",         "(Ljava/io/FileDescriptor;Ljava/net/DatagramPacket;[BIIIZ)I",               (void*) osNetworkSystem_recvConnectedDatagramImpl          },
3824     { "recvConnectedDatagramDirectImpl",   "(Ljava/io/FileDescriptor;Ljava/net/DatagramPacket;IIIIZ)I",                (void*) osNetworkSystem_recvConnectedDatagramDirectImpl    },
3825     { "sendDatagramImpl",                  "(Ljava/io/FileDescriptor;[BIIIZILjava/net/InetAddress;)I",                 (void*) osNetworkSystem_sendDatagramImpl                   },
3826     { "sendDatagramDirectImpl",            "(Ljava/io/FileDescriptor;IIIIZILjava/net/InetAddress;)I",                  (void*) osNetworkSystem_sendDatagramDirectImpl             },
3827     { "sendConnectedDatagramImpl",         "(Ljava/io/FileDescriptor;[BIIZ)I",                                         (void*) osNetworkSystem_sendConnectedDatagramImpl          },
3828     { "sendConnectedDatagramDirectImpl",   "(Ljava/io/FileDescriptor;IIIZ)I",                                          (void*) osNetworkSystem_sendConnectedDatagramDirectImpl    },
3829     { "createServerStreamSocketImpl",      "(Ljava/io/FileDescriptor;Z)V",                                             (void*) osNetworkSystem_createServerStreamSocketImpl       },
3830     { "receiveStreamImpl",                 "(Ljava/io/FileDescriptor;[BIII)I",                                         (void*) osNetworkSystem_receiveStreamImpl                  },
3831     { "sendStreamImpl",                    "(Ljava/io/FileDescriptor;[BII)I",                                          (void*) osNetworkSystem_sendStreamImpl                     },
3832     { "shutdownInputImpl",                 "(Ljava/io/FileDescriptor;)V",                                              (void*) osNetworkSystem_shutdownInputImpl                  },
3833     { "shutdownOutputImpl",                "(Ljava/io/FileDescriptor;)V",                                              (void*) osNetworkSystem_shutdownOutputImpl                 },
3834     { "sendDatagramImpl2",                 "(Ljava/io/FileDescriptor;[BIIILjava/net/InetAddress;)I",                   (void*) osNetworkSystem_sendDatagramImpl2                  },
3835     { "selectImpl",                        "([Ljava/io/FileDescriptor;[Ljava/io/FileDescriptor;II[IJ)I",               (void*) osNetworkSystem_selectImpl                         },
3836     { "getSocketLocalAddressImpl",         "(Ljava/io/FileDescriptor;Z)Ljava/net/InetAddress;",                        (void*) osNetworkSystem_getSocketLocalAddressImpl          },
3837     { "getSocketLocalPortImpl",            "(Ljava/io/FileDescriptor;Z)I",                                             (void*) osNetworkSystem_getSocketLocalPortImpl             },
3838     { "getSocketOptionImpl",               "(Ljava/io/FileDescriptor;I)Ljava/lang/Object;",                            (void*) osNetworkSystem_getSocketOptionImpl                },
3839     { "setSocketOptionImpl",               "(Ljava/io/FileDescriptor;ILjava/lang/Object;)V",                           (void*) osNetworkSystem_setSocketOptionImpl                },
3840     { "getSocketFlagsImpl",                "()I",                                                                      (void*) osNetworkSystem_getSocketFlagsImpl                 },
3841     { "socketCloseImpl",                   "(Ljava/io/FileDescriptor;)V",                                              (void*) osNetworkSystem_socketCloseImpl                    },
3842     { "getHostByAddrImpl",                 "([B)Ljava/net/InetAddress;",                                               (void*) osNetworkSystem_getHostByAddrImpl                  },
3843     { "getHostByNameImpl",                 "(Ljava/lang/String;Z)Ljava/net/InetAddress;",                              (void*) osNetworkSystem_getHostByNameImpl                  },
3844     { "setInetAddressImpl",                "(Ljava/net/InetAddress;[B)V",                                              (void*) osNetworkSystem_setInetAddressImpl                 },
3845     { "inheritedChannelImpl",              "()Ljava/nio/channels/Channel;",                                            (void*) osNetworkSystem_inheritedChannelImpl               },
3846 };
3847
3848 int register_org_apache_harmony_luni_platform_OSNetworkSystem(JNIEnv* env) {
3849     return jniRegisterNativeMethods(env,
3850             "org/apache/harmony/luni/platform/OSNetworkSystem",
3851             gMethods,
3852             NELEM(gMethods));
3853 }