OSDN Git Service

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