OSDN Git Service

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