OSDN Git Service

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