OSDN Git Service

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