OSDN Git Service

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