OSDN Git Service

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