2 * Copyright (C) 2007 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #define LOG_TAG "OSNetworkSystem"
25 #include <sys/socket.h>
26 #include <netinet/in.h>
27 #include <netinet/tcp.h>
31 #include <sys/ioctl.h>
34 #include <cutils/properties.h>
35 #include <cutils/adb_networking.h>
36 #include <utils/LogSocket.h>
37 #include "AndroidSystemNatives.h"
41 * Error codes for socket operations
43 * @internal SOCKERR* range from -200 to -299 avoid overlap
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 */
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
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
125 #define BROKEN_MULTICAST_IF 1
126 #define BROKEN_MULTICAST_TTL 2
127 #define BROKEN_TCP_NODELAY 4
129 #define SOCKET_CONNECT_STEP_START 0
130 #define SOCKET_CONNECT_STEP_CHECK 1
132 #define SOCKET_OP_NONE 0
133 #define SOCKET_OP_READ 1
134 #define SOCKET_OP_WRITE 2
135 #define SOCKET_READ_WRITE 3
137 #define SOCKET_MSG_PEEK 1
138 #define SOCKET_MSG_OOB 2
140 #define SOCKET_NOFLAGS 0
143 #define BUFFERSIZE 2048
145 // wait for 500000 usec = 0.5 second
146 #define SEND_RETRY_TIME 500000
149 struct CachedFields {
150 jfieldID fd_descriptor;
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;
163 jmethodID byte_class_init;
164 jfieldID byte_class_value;
166 jmethodID string_class_init;
167 jfieldID socketimpl_address;
168 jfieldID socketimpl_port;
170 jfieldID dpack_address;
172 jfieldID dpack_length;
175 static int useAdbNetworking = 0;
177 /* needed for connecting with timeout */
178 typedef struct selectFDSet {
186 static const char * netLookupErrorString(int anErrorNum);
189 * Throws an SocketException with the message affiliated with the errorCode.
191 static void throwSocketException(JNIEnv *env, int errorCode) {
192 jniThrowException(env, "java/net/SocketException",
193 netLookupErrorString(errorCode));
197 * Throws an IOException with the given message.
199 static void throwIOExceptionStr(JNIEnv *env, const char *message) {
200 jniThrowException(env, "java/io/IOException", message);
204 * Throws a NullPointerException.
206 static void throwNullPointerException(JNIEnv *env) {
207 jniThrowException(env, "java/lang/NullPointerException", NULL);
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.
215 static int javaAddressToStructIn(
216 JNIEnv *env, jbyteArray java_address, struct in_addr *address) {
218 memset(address, 0, sizeof(address));
220 if (java_address == NULL) {
224 if (env->GetArrayLength(java_address) != sizeof(address->s_addr)) {
228 jbyte * java_address_bytes
229 = env->GetByteArrayElements(java_address, NULL);
231 memcpy(&(address->s_addr),
233 sizeof(address->s_addr));
235 env->ReleaseByteArrayElements(java_address, java_address_bytes, JNI_ABORT);
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.
245 static int structInToJavaAddress(
246 JNIEnv *env, struct in_addr *address, jbyteArray java_address) {
248 if (java_address == NULL) {
252 if (env->GetArrayLength(java_address) != sizeof(address->s_addr)) {
256 jbyte *java_address_bytes;
258 java_address_bytes = env->GetByteArrayElements(java_address, NULL);
260 memcpy(java_address_bytes, &(address->s_addr), sizeof(address->s_addr));
262 env->ReleaseByteArrayElements(java_address, java_address_bytes, 0);
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
273 static int socketAddressToInetAddress(JNIEnv *env,
274 struct sockaddr_in *sockaddress, jobject inetaddress, int *port) {
276 jbyteArray ipaddress;
279 ipaddress = (jbyteArray)env->GetObjectField(inetaddress,
280 gCachedFields.iaddr_ipaddress);
282 if (structInToJavaAddress(env, &sockaddress->sin_addr, ipaddress) < 0) {
286 *port = ntohs(sockaddress->sin_port);
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
297 static int inetAddressToSocketAddress(JNIEnv *env,
298 jobject inetaddress, int port, struct sockaddr_in *sockaddress) {
300 jbyteArray ipaddress;
303 ipaddress = (jbyteArray)env->GetObjectField(inetaddress,
304 gCachedFields.iaddr_ipaddress);
306 memset(sockaddress, 0, sizeof(sockaddress));
308 sockaddress->sin_family = AF_INET;
309 sockaddress->sin_port = htons(port);
311 if (javaAddressToStructIn(env, ipaddress, &(sockaddress->sin_addr)) < 0) {
318 static jobject structInToInetAddress(JNIEnv *env, struct in_addr *address) {
322 bytes = env->NewByteArray(4);
328 if (structInToJavaAddress(env, address, bytes) < 0) {
332 return env->CallStaticObjectMethod(gCachedFields.iaddr_class,
333 gCachedFields.iaddr_getbyaddress, bytes);
337 * Answer a new java.lang.Boolean object.
339 * @param env pointer to the JNI library
340 * @param anInt the Boolean constructor argument
342 * @return the new Boolean
345 jobject newJavaLangBoolean(JNIEnv * env, jint anInt) {
347 jmethodID tempMethod;
349 tempClass = gCachedFields.boolean_class;
350 tempMethod = gCachedFields.boolean_class_init;
351 return env->NewObject(tempClass, tempMethod, (jboolean) (anInt != 0));
355 * Answer a new java.lang.Byte object.
357 * @param env pointer to the JNI library
358 * @param anInt the Byte constructor argument
360 * @return the new Byte
363 jobject newJavaLangByte(JNIEnv * env, jbyte val) {
365 jmethodID tempMethod;
367 tempClass = gCachedFields.byte_class;
368 tempMethod = gCachedFields.byte_class_init;
369 return env->NewObject(tempClass, tempMethod, val);
373 * Answer a new java.lang.Integer object.
375 * @param env pointer to the JNI library
376 * @param anInt the Integer constructor argument
378 * @return the new Integer
381 jobject newJavaLangInteger(JNIEnv * env, jint anInt) {
383 jmethodID tempMethod;
385 tempClass = gCachedFields.integer_class;
386 tempMethod = gCachedFields.integer_class_init;
387 return env->NewObject(tempClass, tempMethod, anInt);
391 * Answer a new java.lang.String object.
393 * @param env pointer to the JNI library
394 * @param anInt the byte[] constructor argument
396 * @return the new String
399 jobject newJavaLangString(JNIEnv * env, jbyteArray bytes) {
401 jmethodID tempMethod;
403 tempClass = gCachedFields.string_class;
404 tempMethod = gCachedFields.string_class_init;
405 return env->NewObject(tempClass, tempMethod, (jbyteArray) bytes);
409 * Query OS for timestamp.
410 * Retrieve the current value of system clock and convert to milliseconds.
412 * @param[in] portLibrary The port library.
414 * @return 0 on failure, time value in milliseconds on success.
415 * @deprecated Use @ref time_hires_clock and @ref time_hires_delta
417 * technically, this should return I_64 since both timeval.tv_sec and
418 * timeval.tv_usec are long
421 static int time_msec_clock() {
425 gettimeofday(&tp, &tzp);
426 return (tp.tv_sec * 1000) + (tp.tv_usec / 1000);
430 * check if the passed sockaddr_in struct contains a localhost address
432 * @param[in] address pointer to the address to check
434 * @return 0 if the passed address isn't a localhost address
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;
442 * Answer the errorString corresponding to the errorNumber, if available.
443 * This function will answer a default error string, if the errorNumber is not
446 * This function will have to be reworked to handle internationalization
447 * properly, removing the explicit strings.
449 * @param anErrorNum the error code to resolve to a human readable string
451 * @return a human readable error string
454 static const char * netLookupErrorString(int anErrorNum) {
455 switch (anErrorNum) {
456 case SOCKERR_BADSOCKET:
458 case SOCKERR_NOTINITIALIZED:
459 return "Socket library uninitialized";
461 return "Bad address family";
462 case SOCKERR_BADPROTO:
463 return "Bad protocol";
464 case SOCKERR_BADTYPE:
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";
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";
559 return "Broken pipe";
561 return "Permission denied (maybe missing INTERNET permission)";
564 LOGE("unknown socket error %d", anErrorNum);
565 return "unknown error";
569 static int convertError(int errorCode) {
572 return SOCKERR_BADDESC;
574 return SOCKERR_NOBUFFERS;
576 return SOCKERR_OPNOTSUPP;
578 return SOCKERR_OPTUNSUPP;
580 return SOCKERR_SOCKLEVELINVALID;
582 return SOCKERR_NOTSOCK;
584 return SOCKERR_INTERRUPTED;
586 return SOCKERR_NOTCONNECTED;
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 */
592 return SOCKERR_CONNRESET;
594 return SOCKERR_WOULDBLOCK;
595 case EPROTONOSUPPORT:
596 return SOCKERR_BADPROTO;
598 return SOCKERR_ARGSINVALID;
600 return SOCKERR_TIMEOUT;
602 return SOCKERR_CONNECTION_REFUSED;
604 return SOCKERR_ENETUNREACH;
606 return SOCKERR_EACCES;
608 return SOCKERR_EPIPE;
610 return SOCKERR_EHOSTUNREACH;
612 return SOCKERR_ADDRINUSE;
614 return SOCKERR_ADDRNOTAVAIL;
616 return SOCKERR_MSGSIZE;
618 LOGE("unclassified errno %d (%s)", errorCode, strerror(errorCode));
619 return SOCKERR_OPFAILED;
623 static int sockSelect(int nfds, fd_set *readfds, fd_set *writefds,
624 fd_set *exceptfds, struct timeval *timeout) {
626 int result = select(nfds, readfds, writefds, exceptfds, timeout);
629 if (errno == EINTR) {
630 result = SOCKERR_INTERRUPTED;
632 result = SOCKERR_OPFAILED;
634 } else if (result == 0) {
635 result = SOCKERR_TIMEOUT;
640 #define SELECT_READ_TYPE 0
641 #define SELECT_WRITE_TYPE 1
643 static int selectWait(int handle, int uSecTime, int type) {
645 struct timeval time, *timePtr;
647 int size = handle + 1;
650 FD_SET(handle, &fdset);
653 /* Use a timeout if uSecTime >= 0 */
654 memset(&time, 0, sizeof(time));
655 time.tv_usec = uSecTime;
658 /* Infinite timeout if uSecTime < 0 */
662 if (type == SELECT_READ_TYPE) {
663 result = sockSelect(size, &fdset, NULL, NULL, timePtr);
665 result = sockSelect(size, NULL, &fdset, NULL, timePtr);
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
675 int pollTimeoutUSec = 100000, pollMsec = 100;
677 int timeLeft = timeout;
678 int hasTimeout = timeout > 0 ? 1 : 0;
683 finishTime = time_msec_clock() + timeout;
688 while (poll) { /* begin polling loop */
691 * Fetch the handle every time in case the socket is closed.
693 handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
695 if (handle == 0 || handle == -1) {
696 throwSocketException(env, SOCKERR_INTERRUPTED);
702 if (timeLeft - 10 < pollMsec) {
703 pollTimeoutUSec = timeLeft <= 0 ? 0 : (timeLeft * 1000);
706 result = selectWait(handle, pollTimeoutUSec, type);
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.
713 if (SOCKERR_TIMEOUT == result ||
714 SOCKERR_INTERRUPTED == result) {
716 timeLeft = finishTime - time_msec_clock();
720 * Always throw the "timeout" message because that is
721 * effectively what has happened, even if we happen to
722 * have been interrupted.
724 jniThrowException(env, "java/net/SocketTimeoutException",
725 netLookupErrorString(SOCKERR_TIMEOUT));
727 continue; // try again
730 } else if (0 > result) {
731 log_socket_close(handle, result);
732 throwSocketException(env, result);
736 } else { /* polling with no timeout (why would you do this?)*/
738 result = selectWait(handle, pollTimeoutUSec, type);
741 * if interrupted (or a timeout) just retry
743 if (SOCKERR_TIMEOUT == result ||
744 SOCKERR_INTERRUPTED == result) {
746 continue; // try again
747 } else if (0 > result) {
748 log_socket_close(handle, result);
749 throwSocketException(env, result);
753 } /* end polling loop */
759 * A helper method, to set the connect context to a Long object.
761 * @param env pointer to the JNI library
762 * @param longclass Java Long Object
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));
773 * A helper method, to get the connect context.
775 * @param env pointer to the JNI library
776 * @param longclass Java Long Object
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));
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;
792 while (bufleft > 1) {
793 sum = sum + (*buf++);
794 bufleft = bufleft - sizeof(unsigned short );
797 sum = sum + (*(unsigned char*)buf);
799 sum = (sum >> 16) + (sum & 0xffff);
802 return (unsigned short )(~sum);
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
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.
824 * @return 0, if no errors occurred, otherwise the (negative) error code.
826 static int sockConnectWithTimeout(int handle, struct sockaddr_in addr,
827 unsigned int timeout, unsigned int step, jbyte *ctxt) {
829 struct timeval passedTimeout;
831 socklen_t errorValLen = sizeof(int);
832 struct selectFDSet *context = NULL;
834 if (SOCKET_STEP_START == step) {
836 context = (struct selectFDSet *) ctxt;
838 context->sock = handle;
839 context->nfds = handle + 1;
841 if (useAdbNetworking && !isLocalhost(&addr)) {
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);
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);
855 return convertError(rc);
858 // LOGD("+connect to address 0x%08x (via normal) on handle %d",
859 // addr.sin_addr.s_addr, handle);
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);
873 return SOCKERR_ALREADYBOUND;
876 return SOCKERR_NOTCONNECTED;
878 return convertError(rc);
882 /* we connected right off the bat so just return */
885 } else if (SOCKET_STEP_CHECK == step) {
886 /* now check if we have connected yet */
888 context = (struct selectFDSet *) ctxt;
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
895 passedTimeout.tv_sec = 0;
897 passedTimeout.tv_usec = 100 * 1000;
898 } else if ((int)timeout >= 0) {
899 passedTimeout.tv_usec = timeout * 1000;
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));
910 rc = select(context->nfds,
912 &(context->writeSet),
913 &(context->exceptionSet),
914 (int)timeout >= 0 ? &passedTimeout : NULL);
916 /* if there is at least one descriptor ready to be checked */
918 /* if the descriptor is in the write set we connected or failed */
919 if (FD_ISSET(context->sock, &(context->writeSet))) {
921 if (!FD_ISSET(context->sock, &(context->readSet))) {
922 /* ok we have connected ok */
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;
930 return convertError(errno);
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;
942 return convertError(rc);
946 /* something went wrong with the select call */
949 /* if it was EINTR we can just try again. Return not connected */
951 return SOCKERR_NOTCONNECTED;
954 /* some other error occured so look it up and return */
955 return convertError(rc);
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
962 return SOCKERR_NOTCONNECTED;
963 } else if (SOCKET_STEP_DONE == step) {
964 /* we are done the connect or an error occured so clean up */
966 int block = JNI_FALSE;
967 ioctl(handle, FIONBIO, &block);
971 return SOCKERR_ARGSINVALID;
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.
979 * Implementation note for multicast sockets in general:
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
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).
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.
993 * @exception SocketException if an error occurs during the call
995 static void mcastAddDropMembership (JNIEnv * env, int handle, jobject optVal,
996 int ignoreIF, int setSockOptVal) {
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);
1004 * JNI objects needed to access the information in the optVal oject
1005 * passed in. The object passed in is a GenericIPMreq object
1008 jfieldID multiaddrID;
1009 jfieldID interfaceAddrID;
1011 jobject interfaceAddr;
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
1017 if (env->IsInstanceOf (optVal, gCachedFields.iaddr_class)) {
1019 ipmreqP.imr_interface.s_addr = htonl(INADDR_ANY);
1022 result = getsockopt(handle, IPPROTO_IP, IP_MULTICAST_IF, &sockaddrP,
1026 throwSocketException (env, convertError(errno));
1030 memcpy(&(ipmreqP.imr_interface.s_addr), &(sockaddrP.sin_addr), 4);
1033 result = inetAddressToSocketAddress(env, optVal, 0, &sockaddrP);
1036 throwSocketException(env, SOCKERR_BADSOCKET);
1040 memcpy(&(ipmreqP.imr_multiaddr.s_addr), &(sockaddrP.sin_addr), 4);
1042 result = setsockopt(handle, IPPROTO_IP, setSockOptVal, &ipmreqP, length);
1044 throwSocketException (env, convertError(errno));
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);
1055 result = inetAddressToSocketAddress(env, multiaddr, 0, &sockaddrP);
1058 throwSocketException(env, SOCKERR_BADSOCKET);
1062 memcpy(&(ipmreqP.imr_multiaddr.s_addr), &(sockaddrP.sin_addr), 4);
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);
1069 ipmreqP.imr_interface.s_addr = htonl(INADDR_ANY);
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
1077 if (NULL != interfaceAddr) {
1079 result = inetAddressToSocketAddress(env, interfaceAddr, 0,
1083 throwSocketException(env, SOCKERR_BADSOCKET);
1087 memcpy(&(ipmreqP.imr_interface.s_addr), &(sockaddrP.sin_addr), 4);
1092 /* join/drop the multicast address */
1093 result = setsockopt(handle, IPPROTO_IP, setSockOptVal, &ipmreqP, length);
1095 throwSocketException (env, convertError(errno));
1101 static void osNetworkSystem_oneTimeInitializationImpl(JNIEnv* env, jobject obj,
1102 jboolean jcl_supports_ipv6) {
1103 // LOGD("ENTER oneTimeInitializationImpl of OSNetworkSystem");
1105 char useAdbNetworkingProperty[PROPERTY_VALUE_MAX];
1106 char adbConnectedProperty[PROPERTY_VALUE_MAX];
1108 property_get("android.net.use-adb-networking", useAdbNetworkingProperty, "");
1109 property_get("adb.connected", adbConnectedProperty, "");
1111 if (strlen((char *)useAdbNetworkingProperty) > 0
1112 && strlen((char *)adbConnectedProperty) > 0) {
1113 useAdbNetworking = 1;
1116 memset(&gCachedFields, 0, sizeof(gCachedFields));
1118 // initializing InetAddress
1120 jclass iaddrclass = env->FindClass("java/net/InetAddress");
1122 if (iaddrclass == NULL) {
1123 jniThrowException(env, "java/lang/ClassNotFoundException",
1124 "java.net.InetAddress");
1128 gCachedFields.iaddr_class = (jclass) env->NewGlobalRef(iaddrclass);
1130 jmethodID iaddrclassinit = env->GetMethodID(iaddrclass, "<init>", "()V");
1132 if (iaddrclassinit == NULL) {
1133 jniThrowException(env, "java/lang/NoSuchMethodError", "InetAddress.<init>()");
1137 gCachedFields.iaddr_class_init = iaddrclassinit;
1139 jmethodID iaddrgetbyaddress = env->GetStaticMethodID(iaddrclass,
1140 "getByAddress", "([B)Ljava/net/InetAddress;");
1142 if (iaddrgetbyaddress == NULL) {
1143 jniThrowException(env, "java/lang/NoSuchMethodError",
1144 "InetAddress.getByAddress(byte[] val)");
1148 gCachedFields.iaddr_getbyaddress = iaddrgetbyaddress;
1150 jfieldID iaddripaddress = env->GetFieldID(iaddrclass, "ipaddress", "[B");
1152 if (iaddripaddress == NULL) {
1153 jniThrowException(env, "java/lang/NoSuchFieldError",
1154 "Can't find field InetAddress.ipaddress");
1158 gCachedFields.iaddr_ipaddress = iaddripaddress;
1160 // get the GenericIPMreq class
1162 jclass genericipmreqclass = env->FindClass("org/apache/harmony/luni/net/GenericIPMreq");
1164 if (genericipmreqclass == NULL) {
1165 jniThrowException(env, "java/lang/ClassNotFoundException",
1166 "org.apache.harmony.luni.net.GenericIPMreq");
1170 gCachedFields.genericipmreq_class = (jclass) env->NewGlobalRef(genericipmreqclass);
1172 // initializing Integer
1174 jclass integerclass = env->FindClass("java/lang/Integer");
1176 if (integerclass == NULL) {
1177 jniThrowException(env, "java/lang/ClassNotFoundException",
1178 "java.lang.Integer");
1182 jmethodID integerclassinit = env->GetMethodID(integerclass, "<init>", "(I)V");
1184 if (integerclassinit == NULL) {
1185 jniThrowException(env, "java/lang/NoSuchMethodError",
1186 "Integer.<init>(int val)");
1190 jfieldID integerclassvalue = env->GetFieldID(integerclass, "value", "I");
1192 if (integerclassvalue == NULL) {
1193 jniThrowException(env, "java/lang/NoSuchMethodError", "Integer.value");
1197 gCachedFields.integer_class = (jclass) env->NewGlobalRef(integerclass);
1198 gCachedFields.integer_class_init = integerclassinit;
1199 gCachedFields.integer_class_value = integerclassvalue;
1201 // initializing Boolean
1203 jclass booleanclass = env->FindClass("java/lang/Boolean");
1205 if (booleanclass == NULL) {
1206 jniThrowException(env, "java/lang/ClassNotFoundException",
1207 "java.lang.Boolean");
1211 jmethodID booleanclassinit = env->GetMethodID(booleanclass, "<init>", "(Z)V");
1213 if (booleanclassinit == NULL) {
1214 jniThrowException(env, "java/lang/NoSuchMethodError",
1215 "Boolean.<init>(boolean val)");
1219 jfieldID booleanclassvalue = env->GetFieldID(booleanclass, "value", "Z");
1221 if (booleanclassvalue == NULL) {
1222 jniThrowException(env, "java/lang/NoSuchMethodError", "Boolean.value");
1226 gCachedFields.boolean_class = (jclass) env->NewGlobalRef(booleanclass);
1227 gCachedFields.boolean_class_init = booleanclassinit;
1228 gCachedFields.boolean_class_value = booleanclassvalue;
1230 // initializing Byte
1232 jclass byteclass = env->FindClass("java/lang/Byte");
1234 if (byteclass == NULL) {
1235 jniThrowException(env, "java/lang/ClassNotFoundException",
1240 jmethodID byteclassinit = env->GetMethodID(byteclass, "<init>", "(B)V");
1242 if (byteclassinit == NULL) {
1243 jniThrowException(env, "java/lang/NoSuchMethodError",
1244 "Byte.<init>(byte val)");
1248 jfieldID byteclassvalue = env->GetFieldID(byteclass, "value", "B");
1250 if (byteclassvalue == NULL) {
1251 jniThrowException(env, "java/lang/NoSuchMethodError", "Byte.value");
1255 gCachedFields.byte_class = (jclass) env->NewGlobalRef(byteclass);
1256 gCachedFields.byte_class_init = byteclassinit;
1257 gCachedFields.byte_class_value = byteclassvalue;
1259 // initializing String
1261 jclass stringclass = env->FindClass("java/lang/String");
1263 if (stringclass == NULL) {
1264 jniThrowException(env, "java/lang/ClassNotFoundException",
1265 "java.lang.String");
1269 jmethodID stringclassinit = env->GetMethodID(stringclass, "<init>", "([B)V");
1271 if (stringclassinit == NULL) {
1272 jniThrowException(env, "java/lang/NoSuchMethodError",
1273 "String.<init>(byte[] val)");
1277 gCachedFields.string_class = (jclass) env->NewGlobalRef(stringclass);
1278 gCachedFields.string_class_init = stringclassinit;
1280 // initializing ScoketImpl
1282 jclass socketimplclass = env->FindClass("java/net/SocketImpl");
1284 if (socketimplclass == NULL) {
1285 jniThrowException(env, "java/lang/ClassNotFoundException",
1286 "java.net.SocketImpl");
1290 jfieldID socketimplport = env->GetFieldID(socketimplclass, "port", "I");
1292 if (socketimplport == NULL) {
1293 jniThrowException(env, "java/lang/NoSuchFieldError", "SocketImpl.port");
1297 jfieldID socketimpladdress = env->GetFieldID(socketimplclass, "address",
1298 "Ljava/net/InetAddress;");
1300 if (socketimpladdress == NULL) {
1301 jniThrowException(env, "java/lang/NoSuchFieldError",
1302 "SocketImpl.address");
1306 gCachedFields.socketimpl_address = socketimpladdress;
1307 gCachedFields.socketimpl_port = socketimplport;
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");
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");
1324 gCachedFields.dpack_port = env->GetFieldID(gCachedFields.dpack_class,
1326 if (gCachedFields.dpack_port == NULL) {
1327 jniThrowException(env, "java/lang/NoSuchFieldError",
1328 "DatagramPacket.port");
1332 gCachedFields.dpack_length = env->GetFieldID(gCachedFields.dpack_class,
1334 if (gCachedFields.dpack_length == NULL) {
1335 jniThrowException(env, "java/lang/NoSuchFieldError",
1336 "DatagramPacket.length");
1342 static void osNetworkSystem_createSocketImpl(JNIEnv* env, jclass clazz,
1343 jobject fileDescriptor, jboolean preferIPv4Stack) {
1344 // LOGD("ENTER createSocketImpl");
1346 int ret = socket(PF_INET, SOCK_STREAM, 0);
1349 int err = convertError(errno);
1350 throwSocketException(env, err);
1354 jniSetFileDescriptorOfFD(env, fileDescriptor, ret);
1359 static void osNetworkSystem_createDatagramSocketImpl(JNIEnv* env, jclass clazz,
1360 jobject fileDescriptor, jboolean preferIPv4Stack) {
1361 // LOGD("ENTER createDatagramSocketImpl");
1363 int ret = socket(PF_INET, SOCK_DGRAM, 0);
1366 int err = convertError(errno);
1367 throwSocketException(env, err);
1371 jniSetFileDescriptorOfFD(env, fileDescriptor, ret);
1376 static jint osNetworkSystem_readSocketDirectImpl(JNIEnv* env, jclass clazz,
1377 jobject fileDescriptor, jint address, jint offset, jint count,
1379 // LOGD("ENTER readSocketDirectImpl");
1382 jbyte *message = (jbyte *)address + offset;
1383 int result, ret, localCount;
1385 handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
1387 if (handle == 0 || handle == -1) {
1388 throwSocketException(env, SOCKERR_BADSOCKET);
1392 result = selectWait(handle, timeout, SELECT_READ_TYPE);
1398 localCount = (count < 65536) ? count : 65536;
1401 ret = recv(handle, (jbyte *) message, localCount, SOCKET_NOFLAGS);
1402 } while (ret < 0 && errno == EINTR);
1406 } else if (ret == -1) {
1407 int err = convertError(errno);
1408 log_socket_close(handle, err);
1409 throwSocketException(env, err);
1412 add_recv_stats(handle, ret);
1416 static jint osNetworkSystem_readSocketImpl(JNIEnv* env, jclass clazz,
1417 jobject fileDescriptor, jbyteArray data, jint offset, jint count,
1419 // LOGD("ENTER readSocketImpl");
1422 int result, localCount;
1424 jbyte internalBuffer[BUFFERSIZE];
1426 localCount = (count < 65536) ? count : 65536;
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");
1436 message = (jbyte *)internalBuffer;
1439 result = osNetworkSystem_readSocketDirectImpl(env, clazz, fileDescriptor,
1440 (jint) message, 0, localCount, timeout);
1443 env->SetByteArrayRegion(data, offset, result, (jbyte *)message);
1446 if (((jbyte *)message) != internalBuffer) {
1447 free(( jbyte *)message);
1453 static jint osNetworkSystem_writeSocketDirectImpl(JNIEnv* env, jclass clazz,
1454 jobject fileDescriptor, jint address, jint offset, jint count) {
1455 // LOGD("ENTER writeSocketDirectImpl");
1458 jbyte *message = (jbyte *)address + offset;
1459 int result = 0, sent = 0;
1465 handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
1467 if (handle == 0 || handle == -1) {
1468 throwSocketException(env, SOCKERR_BADSOCKET);
1472 result = send(handle, (jbyte *) message, (int) count, SOCKET_NOFLAGS);
1474 int err = convertError(errno);
1475 log_socket_close(handle, err);
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);
1484 errorCodeExClass = env->FindClass("org/apache/harmony/luni/util/ErrorCodeException");
1485 if (!errorCodeExClass){
1488 errorCodeExConstructor = env->GetMethodID(errorCodeExClass,"<init>","(I)V");
1489 if (!errorCodeExConstructor){
1492 errorCodeEx = env->NewObject(errorCodeExClass,errorCodeExConstructor,err);
1494 socketExClass = env->FindClass("java/net/SocketException");
1495 if (!socketExClass) {
1498 socketExConstructor = env->GetMethodID(socketExClass,"<init>","(Ljava/lang/String;)V");
1499 if (!socketExConstructor) {
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);
1508 throwSocketException(env, err);
1512 add_send_stats(handle, result);
1516 static jint osNetworkSystem_writeSocketImpl(JNIEnv* env, jclass clazz,
1517 jobject fileDescriptor, jbyteArray data, jint offset, jint count) {
1518 // LOGD("ENTER writeSocketImpl");
1524 /* TODO: ARRAY PINNING */
1525 #define INTERNAL_SEND_BUFFER_MAX 512
1526 jbyte internalBuffer[INTERNAL_SEND_BUFFER_MAX];
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");
1536 message = (jbyte *)internalBuffer;
1539 env->GetByteArrayRegion(data, offset, count, message);
1541 result = osNetworkSystem_writeSocketDirectImpl(env, clazz, fileDescriptor,
1542 (jint) message, 0, count);
1544 if (( jbyte *)message != internalBuffer) {
1545 free(( jbyte *)message);
1547 #undef INTERNAL_SEND_BUFFER_MAX
1551 static void osNetworkSystem_setNonBlockingImpl(JNIEnv* env, jclass clazz,
1552 jobject fileDescriptor, jboolean nonblocking) {
1553 // LOGD("ENTER setNonBlockingImpl");
1558 handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
1560 if (handle == 0 || handle == -1) {
1561 throwSocketException(env, SOCKERR_BADSOCKET);
1565 int block = nonblocking;
1567 result = ioctl(handle, FIONBIO, &block);
1570 throwSocketException(env, convertError(errno));
1574 static jint osNetworkSystem_connectSocketImpl(JNIEnv* env, jclass clazz,
1575 jobject fileDescriptor, jint trafficClass, jobject inetAddr, jint port);
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");
1584 struct sockaddr_in address;
1585 jbyte *context = NULL;
1587 memset(&address, 0, sizeof(address));
1589 address.sin_family = AF_INET;
1591 result = inetAddressToSocketAddress(env, inetAddr, port,
1592 (struct sockaddr_in *) &address);
1595 throwSocketException(env, SOCKERR_BADSOCKET);
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);
1605 handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
1607 if (handle == 0 || handle == -1) {
1608 throwSocketException(env, SOCKERR_BADSOCKET);
1612 address.sin_port = htons(port);
1614 context = (jbyte *)env->GetPrimitiveArrayCritical(passContext, NULL);
1617 case SOCKET_CONNECT_STEP_START:
1618 result = sockConnectWithTimeout(handle, address, 0,
1619 SOCKET_STEP_START, context);
1621 case SOCKET_CONNECT_STEP_CHECK:
1622 result = sockConnectWithTimeout(handle, address, timeout,
1623 SOCKET_STEP_CHECK, context);
1627 env->ReleasePrimitiveArrayCritical(passContext, context, JNI_ABORT);
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));
1639 jniThrowException(env, "java/net/ConnectException",
1640 netLookupErrorString(result));
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");
1654 struct sockaddr_in address;
1655 jbyte *context = NULL;
1656 int remainingTimeout = timeout;
1657 int passedTimeout = 0;
1660 char hasTimeout = timeout > 0;
1662 /* if a timeout was specified calculate the finish time value */
1664 finishTime = time_msec_clock() + (int) timeout;
1668 handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
1670 if (handle == 0 || handle == -1) {
1671 throwSocketException(env, SOCKERR_BADSOCKET);
1674 result = inetAddressToSocketAddress(env, inetAddr, remotePort,
1675 (struct sockaddr_in *) &address);
1678 throwSocketException(env, SOCKERR_BADSOCKET);
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);
1687 throwSocketException(env, SOCKERR_BADSOCKET);
1693 * we will be looping checking for when we are connected so allocate
1694 * the descriptor sets that we will use
1696 context =(jbyte *) malloc(sizeof(struct selectFDSet));
1698 if (NULL == context) {
1699 throwSocketException(env, SOCKERR_NOBUFFERS);
1703 result = sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_START, context);
1705 /* ok we connected right away so we are done */
1706 sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_DONE, context);
1708 } else if (result != SOCKERR_NOTCONNECTED) {
1709 log_socket_close(handle, result);
1710 sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_DONE,
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));
1717 throwSocketException(env, result);
1722 while (SOCKERR_NOTCONNECTED == result) {
1723 passedTimeout = remainingTimeout;
1726 * ok now try and connect. Depending on the platform this may sleep
1727 * for up to passedTimeout milliseconds
1729 result = sockConnectWithTimeout(handle, address, passedTimeout,
1730 SOCKET_STEP_CHECK, context);
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.
1737 handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
1739 if (handle == 0 || handle == -1) {
1740 sockConnectWithTimeout(handle, address, 0,
1741 SOCKET_STEP_DONE, context);
1742 throwSocketException(env, SOCKERR_BADSOCKET);
1747 * check if we are now connected,
1748 * if so we can finish the process and return
1751 sockConnectWithTimeout(handle, address, 0,
1752 SOCKET_STEP_DONE, context);
1757 * if the error is SOCKERR_NOTCONNECTED then we have not yet
1758 * connected and we may not be done yet
1760 if (SOCKERR_NOTCONNECTED == result) {
1761 /* check if the timeout has expired */
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));
1774 remainingTimeout = 100;
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));
1791 throwSocketException(env, result);
1800 /* free the memory for the FD set */
1801 if (context != NULL) {
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");
1810 struct sockaddr_in address;
1813 jbyteArray java_in_addr;
1815 memset(&address, 0, sizeof(address));
1817 address.sin_family = AF_INET;
1819 ret = inetAddressToSocketAddress(env, inetAddr, port,
1820 (struct sockaddr_in *) &address);
1823 throwSocketException(env, SOCKERR_BADSOCKET);
1827 handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
1829 if (handle == 0 || handle == -1) {
1830 throwSocketException(env, SOCKERR_BADSOCKET);
1834 address.sin_port = htons(port);
1836 if (useAdbNetworking && !isLocalhost(&address)) {
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);
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) {
1857 jniThrowException(env, "java/net/ConnectException",
1858 netLookupErrorString(convertError(errno)));
1865 static void osNetworkSystem_socketBindImpl(JNIEnv* env, jclass clazz,
1866 jobject fileDescriptor, jint port, jobject inetAddress) {
1867 // LOGD("ENTER socketBindImpl");
1869 struct sockaddr_in sockaddress;
1873 ret = inetAddressToSocketAddress(env, inetAddress, port,
1874 (struct sockaddr_in *) &sockaddress);
1877 throwSocketException(env, SOCKERR_BADSOCKET);
1881 handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
1883 if (handle == 0 || handle == -1) {
1884 throwSocketException(env, SOCKERR_BADSOCKET);
1888 ret = bind(handle, (const sockaddr*)&sockaddress, sizeof(sockaddress));
1891 jniThrowException(env, "java/net/BindException",
1892 netLookupErrorString(convertError(errno)));
1897 static void osNetworkSystem_listenStreamSocketImpl(JNIEnv* env, jclass clazz,
1898 jobject fileDescriptor, jint backlog) {
1899 // LOGD("ENTER listenStreamSocketImpl");
1904 handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
1906 if (handle == 0 || handle == -1) {
1907 throwSocketException(env, SOCKERR_BADSOCKET);
1911 ret = listen(handle, backlog);
1914 int err = convertError(errno);
1915 log_socket_close(handle, err);
1916 throwSocketException(env, err);
1921 static jint osNetworkSystem_availableStreamImpl(JNIEnv* env, jclass clazz,
1922 jobject fileDescriptor) {
1923 // LOGD("ENTER availableStreamImpl");
1926 char message[BUFFERSIZE];
1930 handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
1932 if (handle == 0 || handle == -1) {
1933 throwSocketException(env, SOCKERR_BADSOCKET);
1938 result = selectWait(handle, 1, SELECT_READ_TYPE);
1940 if (SOCKERR_TIMEOUT == result) {
1941 // The read operation timed out, so answer 0 bytes available
1943 } else if (SOCKERR_INTERRUPTED == result) {
1945 } else if (0 > result) {
1946 log_socket_close(handle, result);
1947 throwSocketException(env, result);
1950 } while (SOCKERR_INTERRUPTED == result);
1952 result = recv(handle, (jbyte *) message, BUFFERSIZE, MSG_PEEK);
1955 int err = convertError(errno);
1956 log_socket_close(handle, err);
1957 throwSocketException(env, err);
1960 add_recv_stats(handle, result);
1964 static void osNetworkSystem_acceptSocketImpl(JNIEnv* env, jclass clazz,
1965 jobject fdServer, jobject newSocket, jobject fdnewSocket, jint timeout) {
1966 // LOGD("ENTER acceptSocketImpl");
1969 struct sockaddr address;
1970 struct sockaddr_in in_address;
1979 if (newSocket == NULL) {
1980 throwNullPointerException(env);
1984 result = pollSelectWait(env, fdServer, timeout, SELECT_READ_TYPE);
1990 handle = jniGetFDFromFileDescriptor(env, fdServer);
1992 if (handle == 0 || handle == -1) {
1993 throwSocketException(env, SOCKERR_BADSOCKET);
1998 addrlen = sizeof(sa);
1999 ret = accept(handle, &(sa.address), &addrlen);
2000 } while (ret < 0 && errno == EINTR);
2003 int err = convertError(errno);
2004 log_socket_close(handle, err);
2005 throwSocketException(env, err);
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
2016 if (sa.address.sa_family == AF_INET) {
2017 // inetOrLocal should also be true
2019 jobject inetAddress;
2021 inetAddress = structInToInetAddress(env, &(sa.in_address.sin_addr));
2023 if (inetAddress == NULL) {
2029 env->SetObjectField(newSocket,
2030 gCachedFields.socketimpl_address, inetAddress);
2032 env->SetIntField(newSocket, gCachedFields.socketimpl_port,
2033 ntohs(sa.in_address.sin_port));
2036 jniSetFileDescriptorOfFD(env, fdnewSocket, retFD);
2039 static jboolean osNetworkSystem_supportsUrgentDataImpl(JNIEnv* env,
2040 jclass clazz, jobject fileDescriptor) {
2041 // LOGD("ENTER supportsUrgentDataImpl");
2045 handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
2046 if (handle == 0 || handle == -1) {
2053 static void osNetworkSystem_sendUrgentDataImpl(JNIEnv* env, jclass clazz,
2054 jobject fileDescriptor, jbyte value) {
2055 // LOGD("ENTER sendUrgentDataImpl");
2060 handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
2061 if (handle == 0 || handle == -1) {
2062 throwSocketException(env, SOCKERR_BADSOCKET);
2066 result = send(handle, (jbyte *) &value, 1, MSG_OOB);
2068 int err = convertError(errno);
2069 log_socket_close(handle, err);
2070 throwSocketException(env, err);
2074 static void osNetworkSystem_connectDatagramImpl2(JNIEnv* env, jclass clazz,
2075 jobject fd, jint port, jint trafficClass, jobject inetAddress) {
2076 // LOGD("ENTER connectDatagramImpl2");
2078 int handle = jniGetFDFromFileDescriptor(env, fd);
2080 struct sockaddr_in sockAddr;
2083 ret = inetAddressToSocketAddress(env, inetAddress, port, &sockAddr);
2086 throwSocketException(env, SOCKERR_BADSOCKET);
2089 log_socket_connect(handle, ntohl(sockAddr.sin_addr.s_addr), port);
2090 int result = connect(handle, (struct sockaddr *)&sockAddr, sizeof(sockAddr));
2092 int err = convertError(errno);
2093 log_socket_close(handle, err);
2094 throwSocketException(env, err);
2098 static void osNetworkSystem_disconnectDatagramImpl(JNIEnv* env, jclass clazz,
2100 // LOGD("ENTER disconnectDatagramImpl");
2102 int handle = jniGetFDFromFileDescriptor(env, fd);
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);
2109 sockAddr->sin_family = AF_UNSPEC;
2110 int result = connect(handle, (struct sockaddr *)sockAddr, sockAddrLen);
2114 int err = convertError(errno);
2115 log_socket_close(handle, err);
2116 throwSocketException(env, err);
2120 static jboolean osNetworkSystem_socketBindImpl2(JNIEnv* env, jclass clazz,
2121 jobject fileDescriptor, jint port, jboolean bindToDevice,
2122 jobject inetAddress) {
2123 // LOGD("ENTER socketBindImpl2");
2125 struct sockaddr_in sockaddress;
2129 ret = inetAddressToSocketAddress(env, inetAddress, port,
2130 (struct sockaddr_in *) &sockaddress);
2133 throwSocketException(env, SOCKERR_BADSOCKET);
2137 handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
2138 if (handle == 0 || handle == -1) {
2139 throwSocketException(env, SOCKERR_BADSOCKET);
2143 ret = bind(handle, (const sockaddr*)&sockaddress, sizeof(sockaddress));
2146 int err = convertError(errno);
2147 log_socket_close(handle, err);
2148 jniThrowException(env, "java/net/BindException", netLookupErrorString(err));
2155 static jint osNetworkSystem_peekDatagramImpl(JNIEnv* env, jclass clazz,
2156 jobject fd, jobject sender, jint receiveTimeout) {
2157 // LOGD("ENTER peekDatagramImpl");
2161 int result = pollSelectWait (env, fd, receiveTimeout, SELECT_READ_TYPE);
2166 int handle = jniGetFDFromFileDescriptor(env, fd);
2168 if (handle == 0 || handle == -1) {
2169 throwSocketException(env, SOCKERR_BADSOCKET);
2173 struct sockaddr_in sockAddr;
2174 socklen_t sockAddrLen = sizeof(sockAddr);
2176 int length = recvfrom(handle, NULL, 0, MSG_PEEK,
2177 (struct sockaddr *)&sockAddr, &sockAddrLen);
2180 int err = convertError(errno);
2181 log_socket_close(handle, err);
2182 throwSocketException(env, err);
2186 if (socketAddressToInetAddress(env, &sockAddr, sender, &port) < 0) {
2187 throwIOExceptionStr(env, "Address conversion failed");
2190 add_recv_stats(handle, length);
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");
2199 int result = pollSelectWait (env, fd, receiveTimeout, SELECT_READ_TYPE);
2204 int handle = jniGetFDFromFileDescriptor(env, fd);
2206 if (handle == 0 || handle == -1) {
2207 throwSocketException(env, SOCKERR_BADSOCKET);
2211 struct sockaddr_in sockAddr;
2212 socklen_t sockAddrLen = sizeof(sockAddr);
2214 int mode = peek ? MSG_PEEK : 0;
2216 int actualLength = recvfrom(handle, (char*)(address + offset), length, mode,
2217 (struct sockaddr *)&sockAddr, &sockAddrLen);
2219 if (actualLength < 0) {
2220 int err = convertError(errno);
2221 log_socket_close(handle, err);
2222 throwSocketException(env, err);
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.");
2234 jobject sender = env->CallStaticObjectMethod(
2235 gCachedFields.iaddr_class, gCachedFields.iaddr_getbyaddress,
2237 env->SetObjectField(packet, gCachedFields.dpack_address, sender);
2238 env->SetIntField(packet, gCachedFields.dpack_port, port);
2239 env->SetIntField(packet, gCachedFields.dpack_length, actualLength);
2241 add_recv_stats(handle, actualLength);
2242 return actualLength;
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");
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");
2258 int actualLength = osNetworkSystem_receiveDatagramDirectImpl(env, clazz, fd,
2259 packet, (jint)bytes, 0, localLength, receiveTimeout, peek);
2261 if (actualLength > 0) {
2262 env->SetByteArrayRegion(data, offset, actualLength, bytes);
2266 return actualLength;
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");
2274 int result = pollSelectWait (env, fd, receiveTimeout, SELECT_READ_TYPE);
2280 int handle = jniGetFDFromFileDescriptor(env, fd);
2282 if (handle == 0 || handle == -1) {
2283 throwSocketException(env, SOCKERR_BADSOCKET);
2287 int mode = peek ? MSG_PEEK : 0;
2289 int actualLength = recvfrom(handle,
2290 (char*)(address + offset), length, mode, NULL, NULL);
2292 if (actualLength < 0) {
2293 jniThrowException(env, "java/net/PortUnreachableException", "");
2297 if ( packet != NULL) {
2298 env->SetIntField(packet, gCachedFields.dpack_length, actualLength);
2300 add_recv_stats(handle, actualLength);
2301 return actualLength;
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");
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");
2317 int actualLength = osNetworkSystem_recvConnectedDatagramDirectImpl(env,
2318 clazz, fd, packet, (jint)bytes, 0, localLength,
2319 receiveTimeout, peek);
2321 if (actualLength > 0) {
2322 env->SetByteArrayRegion(data, offset, actualLength, bytes);
2326 return actualLength;
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");
2336 int handle = jniGetFDFromFileDescriptor(env, fd);
2338 if (handle == 0 || handle == -1) {
2339 throwSocketException(env, SOCKERR_BADSOCKET);
2343 struct sockaddr_in receiver;
2345 if (inetAddressToSocketAddress(env, inetAddress, port, &receiver) < 0) {
2346 throwSocketException(env, SOCKERR_BADSOCKET);
2350 result = sendto(handle, (char*)(address + offset), length, SOCKET_NOFLAGS,
2351 (struct sockaddr*)&receiver, sizeof(receiver));
2354 int err = convertError(errno);
2355 if ((SOCKERR_CONNRESET == err)
2356 || (SOCKERR_CONNECTION_REFUSED == err)) {
2359 log_socket_close(handle, err);
2360 throwSocketException(env, err);
2364 add_send_stats(handle, result);
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");
2373 jbyte *bytes = env->GetByteArrayElements(data, NULL);
2374 int actualLength = osNetworkSystem_sendDatagramDirectImpl(env, clazz, fd,
2375 (jint)bytes, offset, length, port, bindToDevice, trafficClass,
2377 env->ReleaseByteArrayElements(data, bytes, JNI_ABORT);
2379 return actualLength;
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");
2387 int handle = jniGetFDFromFileDescriptor(env, fd);
2389 if (handle == 0 || handle == -1) {
2390 throwSocketException(env, SOCKERR_BADSOCKET);
2394 int result = send(handle, (char*)(address + offset), length, 0);
2397 int err = convertError(errno);
2398 if ((SOCKERR_CONNRESET == err) || (SOCKERR_CONNECTION_REFUSED == err)) {
2401 log_socket_close(handle, err);
2402 throwSocketException(env, err);
2406 add_send_stats(handle, length);
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");
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);
2420 return actualLength;
2423 static void osNetworkSystem_createServerStreamSocketImpl(JNIEnv* env,
2424 jclass clazz, jobject fileDescriptor, jboolean preferIPv4Stack) {
2425 // LOGD("ENTER createServerStreamSocketImpl");
2427 if (fileDescriptor == NULL) {
2428 throwNullPointerException(env);
2432 int handle = socket(PF_INET, SOCK_STREAM, 0);
2435 int err = convertError(errno);
2436 throwSocketException(env, err);
2440 jniSetFileDescriptorOfFD(env, fileDescriptor, handle);
2444 setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(int));
2447 static void osNetworkSystem_createMulticastSocketImpl(JNIEnv* env,
2448 jclass clazz, jobject fileDescriptor, jboolean preferIPv4Stack) {
2449 // LOGD("ENTER createMulticastSocketImpl");
2451 int handle = socket(PF_INET, SOCK_DGRAM, 0);
2454 int err = convertError(errno);
2455 throwSocketException(env, err);
2459 jniSetFileDescriptorOfFD(env, fileDescriptor, handle);
2463 // setsockopt(handle, SOL_SOCKET, SO_REUSEPORT, &value, sizeof(jbyte));
2464 setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(int));
2468 * @param timeout in milliseconds. If zero, block until data received
2470 static jint osNetworkSystem_receiveStreamImpl(JNIEnv* env, jclass clazz,
2471 jobject fileDescriptor, jbyteArray data, jint offset, jint count,
2473 // LOGD("ENTER receiveStreamImpl");
2476 int handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
2478 if (handle == 0 || handle == -1) {
2479 throwSocketException(env, SOCKERR_BADSOCKET);
2483 // Cap read length to available buf size
2484 int spaceAvailable = env->GetArrayLength(data) - offset;
2485 int localCount = count < spaceAvailable? count : spaceAvailable;
2488 jbyte *body = env->GetByteArrayElements(data, &isCopy);
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));
2498 result = recv(handle, body + offset, localCount, SOCKET_NOFLAGS);
2499 } while (result < 0 && errno == EINTR);
2501 env->ReleaseByteArrayElements(data, body, 0);
2504 * If no bytes are read, return -1 to signal 'endOfFile'
2505 * to the Java input stream
2508 add_recv_stats(handle, result);
2510 } else if (0 == result) {
2513 // If EAGAIN or EWOULDBLOCK, read timed out
2514 if (errno == EAGAIN || errno == EWOULDBLOCK) {
2515 jniThrowException(env, "java/net/SocketTimeoutException",
2516 netLookupErrorString(SOCKERR_TIMEOUT));
2518 int err = convertError(errno);
2519 log_socket_close(handle, err);
2520 throwSocketException(env, err);
2526 static jint osNetworkSystem_sendStreamImpl(JNIEnv* env, jclass clazz,
2527 jobject fileDescriptor, jbyteArray data, jint offset, jint count) {
2528 // LOGD("ENTER sendStreamImpl");
2531 int result = 0, sent = 0;
2534 jbyte *message = env->GetByteArrayElements(data, &isCopy);
2536 // Cap write length to available buf size
2537 int spaceAvailable = env->GetArrayLength(data) - offset;
2538 if (count > spaceAvailable) count = spaceAvailable;
2540 while (sent < count) {
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);
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);
2557 if (result == EAGAIN ||result == EWOULDBLOCK) {
2558 // LOGD("write blocked %d", sent);
2561 env->ReleaseByteArrayElements(data, message, 0);
2562 int err = convertError(result);
2563 log_socket_close(handle, err);
2564 throwSocketException(env, err);
2570 env->ReleaseByteArrayElements(data, message, 0);
2571 add_send_stats(handle, sent);
2575 static void osNetworkSystem_shutdownInputImpl(JNIEnv* env, jobject obj,
2576 jobject fileDescriptor) {
2577 // LOGD("ENTER shutdownInputImpl");
2582 handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
2584 if (handle == 0 || handle == -1) {
2585 throwSocketException(env, SOCKERR_BADSOCKET);
2589 ret = shutdown(handle, SHUT_RD);
2592 int err = convertError(errno);
2593 log_socket_close(handle, err);
2594 throwSocketException(env, err);
2599 static void osNetworkSystem_shutdownOutputImpl(JNIEnv* env, jobject obj,
2600 jobject fileDescriptor) {
2601 // LOGD("ENTER shutdownOutputImpl");
2606 handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
2608 if (handle == 0 || handle == -1) {
2612 ret = shutdown(handle, SHUT_WR);
2615 int err = convertError(errno);
2616 log_socket_close(handle, err);
2617 throwSocketException(env, err);
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");
2628 jbyte nhostAddrBytes[4];
2629 unsigned short nPort;
2630 int result = 0, sent = 0;
2632 struct sockaddr_in sockaddrP;
2634 if (inetAddress != NULL) {
2636 result = inetAddressToSocketAddress(env, inetAddress, port,
2637 (struct sockaddr_in *) &sockaddrP);
2640 throwSocketException(env, SOCKERR_BADSOCKET);
2644 handle = jniGetFDFromFileDescriptor(env, fd);
2646 if (handle == 0 || handle == -1) {
2647 throwSocketException(env, SOCKERR_BADSOCKET);
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");
2659 env->GetByteArrayRegion(data, offset, length, message);
2661 while (sent < length) {
2662 handle = jniGetFDFromFileDescriptor(env, fd);
2664 if (handle == 0 || handle == -1) {
2665 throwSocketException(env,
2666 sent == 0 ? SOCKERR_BADSOCKET : SOCKERR_INTERRUPTED);
2671 result = sendto(handle, (char *) (message + sent),
2672 (int) (length - sent), SOCKET_NOFLAGS,
2673 (struct sockaddr *) &sockaddrP, sizeof(sockaddrP));
2676 int err = convertError(errno);
2677 log_socket_close(handle, err);
2678 throwSocketException(env, err);
2687 add_send_stats(handle, sent);
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");
2696 struct timeval timeP;
2700 fd_set *fdset_read,*fdset_write;
2705 unsigned int time_sec = (unsigned int)timeout/1000;
2706 unsigned int time_msec = (unsigned int)(timeout%1000);
2708 fdset_read = (fd_set *)malloc(sizeof(fd_set));
2709 fdset_write = (fd_set *)malloc(sizeof(fd_set));
2711 FD_ZERO(fdset_read);
2712 FD_ZERO(fdset_write);
2714 for (val = 0; val<countReadC; val++) {
2716 gotFD = env->GetObjectArrayElement(readFDArray,val);
2718 handle = jniGetFDFromFileDescriptor(env, gotFD);
2720 FD_SET(handle, fdset_read);
2722 if (0 > (size - handle)) {
2727 for (val = 0; val<countWriteC; val++) {
2729 gotFD = env->GetObjectArrayElement(writeFDArray,val);
2731 handle = jniGetFDFromFileDescriptor(env, gotFD);
2733 FD_SET(handle, fdset_write);
2735 if (0 > (size - handle)) {
2740 /* the size is the max_fd + 1 */
2744 result = SOCKERR_FDSET_SIZEBAD;
2746 /* only set when timeout >= 0 (non-block)*/
2749 timeP.tv_sec = time_sec;
2750 timeP.tv_usec = time_msec*1000;
2752 result = sockSelect(size, fdset_read, fdset_write, NULL, &timeP);
2755 result = sockSelect(size, fdset_read, fdset_write, NULL, NULL);
2760 /*output the result to a int array*/
2761 flagArray = env->GetIntArrayElements(outFlags, &isCopy);
2763 for (val=0; val<countReadC; val++) {
2764 gotFD = env->GetObjectArrayElement(readFDArray,val);
2766 handle = jniGetFDFromFileDescriptor(env, gotFD);
2768 if (FD_ISSET(handle,fdset_read)) {
2769 flagArray[val] = SOCKET_OP_READ;
2771 flagArray[val] = SOCKET_OP_NONE;
2775 for (val=0; val<countWriteC; val++) {
2777 gotFD = env->GetObjectArrayElement(writeFDArray,val);
2779 handle = jniGetFDFromFileDescriptor(env, gotFD);
2781 if (FD_ISSET(handle,fdset_write)) {
2782 flagArray[val+countReadC] = SOCKET_OP_WRITE;
2784 flagArray[val+countReadC] = SOCKET_OP_NONE;
2788 env->ReleaseIntArrayElements(outFlags, flagArray, 0);
2794 /* return both correct and error result, let java handle the exception*/
2798 static jobject osNetworkSystem_getSocketLocalAddressImpl(JNIEnv* env,
2799 jclass clazz, jobject fileDescriptor, jboolean preferIPv6Addresses) {
2800 // LOGD("ENTER getSocketLocalAddressImpl");
2802 struct sockaddr_in addr;
2803 socklen_t addrLen = sizeof(addr);
2805 memset(&addr, 0, addrLen);
2807 int handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
2811 if (handle == 0 || handle == -1) {
2812 throwSocketException(env, SOCKERR_UNKNOWNSOCKET);
2816 result = getsockname(handle, (struct sockaddr *)&addr, &addrLen);
2818 // Spec says ignore all errors
2820 return structInToInetAddress(env, &(addr.sin_addr));
2824 static jint osNetworkSystem_getSocketLocalPortImpl(JNIEnv* env, jclass clazz,
2825 jobject fileDescriptor, jboolean preferIPv6Addresses) {
2826 // LOGD("ENTER getSocketLocalPortImpl");
2828 struct sockaddr_in addr;
2829 socklen_t addrLen = sizeof(addr);
2831 int handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
2834 if (handle == 0 || handle == -1) {
2835 throwSocketException(env, SOCKERR_UNKNOWNSOCKET);
2839 result = getsockname(handle, (struct sockaddr *)&addr, &addrLen);
2842 // The java spec does not indicate any exceptions on this call
2845 return ntohs(addr.sin_port);
2849 static jobject osNetworkSystem_getSocketOptionImpl(JNIEnv* env, jclass clazz,
2850 jobject fileDescriptor, jint anOption) {
2851 // LOGD("ENTER getSocketOptionImpl");
2855 socklen_t intSize = sizeof(int);
2856 unsigned char byteValue = 0;
2857 socklen_t byteSize = sizeof(unsigned char);
2859 struct sockaddr_in sockVal;
2860 socklen_t sockSize = sizeof(sockVal);
2862 handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
2863 if (handle == 0 || handle == -1) {
2864 throwSocketException(env, SOCKERR_BADSOCKET);
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);
2874 throwSocketException(env, convertError(errno));
2877 if (!lingr.l_onoff) {
2880 intValue = lingr.l_linger;
2882 return newJavaLangInteger(env, intValue);
2884 case JAVASOCKOPT_TCP_NODELAY: {
2885 if ((anOption >> 16) & BROKEN_TCP_NODELAY) {
2888 result = getsockopt(handle, IPPROTO_TCP, TCP_NODELAY, &intValue, &intSize);
2890 throwSocketException(env, convertError(errno));
2893 return newJavaLangBoolean(env, intValue);
2895 case JAVASOCKOPT_MCAST_TTL: {
2896 if ((anOption >> 16) & BROKEN_MULTICAST_TTL) {
2897 return newJavaLangByte(env, 0);
2899 result = getsockopt(handle, IPPROTO_IP, IP_MULTICAST_TTL, &byteValue, &byteSize);
2901 throwSocketException(env, convertError(errno));
2904 return newJavaLangByte(env, (jbyte)(byteValue & 0xFF));
2906 case JAVASOCKOPT_MCAST_INTERFACE: {
2907 if ((anOption >> 16) & BROKEN_MULTICAST_IF) {
2910 result = getsockopt(handle, IPPROTO_IP, IP_MULTICAST_IF, &sockVal, &sockSize);
2912 throwSocketException(env, convertError(errno));
2915 return structInToInetAddress(env, &(sockVal.sin_addr));
2917 case JAVASOCKOPT_SO_SNDBUF: {
2918 result = getsockopt(handle, SOL_SOCKET, SO_SNDBUF, &intValue, &intSize);
2920 throwSocketException(env, convertError(errno));
2923 return newJavaLangInteger(env, intValue);
2925 case JAVASOCKOPT_SO_RCVBUF: {
2926 result = getsockopt(handle, SOL_SOCKET, SO_RCVBUF, &intValue, &intSize);
2928 throwSocketException(env, convertError(errno));
2931 return newJavaLangInteger(env, intValue);
2933 case JAVASOCKOPT_SO_BROADCAST: {
2934 result = getsockopt(handle, SOL_SOCKET, SO_BROADCAST, &intValue, &intSize);
2936 throwSocketException(env, convertError(errno));
2939 return newJavaLangBoolean(env, intValue);
2941 case JAVASOCKOPT_SO_REUSEADDR: {
2942 result = getsockopt(handle, SOL_SOCKET, SO_REUSEADDR, &intValue, &intSize);
2944 throwSocketException(env, convertError(errno));
2947 return newJavaLangBoolean(env, intValue);
2949 case JAVASOCKOPT_SO_KEEPALIVE: {
2950 result = getsockopt(handle, SOL_SOCKET, SO_KEEPALIVE, &intValue, &intSize);
2952 throwSocketException(env, convertError(errno));
2955 return newJavaLangBoolean(env, intValue);
2957 case JAVASOCKOPT_SO_OOBINLINE: {
2958 result = getsockopt(handle, SOL_SOCKET, SO_OOBINLINE, &intValue, &intSize);
2960 throwSocketException(env, convertError(errno));
2963 return newJavaLangBoolean(env, intValue);
2965 case JAVASOCKOPT_IP_MULTICAST_LOOP: {
2966 result = getsockopt(handle, IPPROTO_IP, IP_MULTICAST_LOOP, &intValue, &intSize);
2968 throwSocketException(env, convertError(errno));
2971 return newJavaLangBoolean(env, intValue);
2973 case JAVASOCKOPT_IP_TOS: {
2974 result = getsockopt(handle, IPPROTO_IP, IP_TOS, &intValue, &intSize);
2976 throwSocketException(env, convertError(errno));
2979 return newJavaLangInteger(env, intValue);
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);
2986 throwSocketException(env, convertError(errno));
2989 return newJavaLangInteger(env, timeout.tv_sec * 1000 + timeout.tv_usec/1000);
2992 throwSocketException(env, SOCKERR_OPTUNSUPP);
2999 static void osNetworkSystem_setSocketOptionImpl(JNIEnv* env, jclass clazz,
3000 jobject fileDescriptor, jint anOption, jobject optVal) {
3001 // LOGD("ENTER setSocketOptionImpl");
3004 int intVal, intSize = sizeof(int);
3005 unsigned char byteVal, byteSize = sizeof(unsigned char);
3006 struct sockaddr_in sockVal;
3007 int sockSize = sizeof(sockVal);
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);
3020 } else if (env->IsInstanceOf(optVal, gCachedFields.genericipmreq_class)) {
3021 // we'll use optVal directly
3023 throwSocketException(env, SOCKERR_OPTUNSUPP);
3027 handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
3028 if (handle == 0 || handle == -1) {
3029 throwSocketException(env, SOCKERR_BADSOCKET);
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));
3041 throwSocketException(env, convertError(errno));
3047 case JAVASOCKOPT_TCP_NODELAY: {
3048 if ((anOption >> 16) & BROKEN_TCP_NODELAY) {
3051 result = setsockopt(handle, IPPROTO_TCP, TCP_NODELAY, &intVal, intSize);
3053 throwSocketException(env, convertError(errno));
3059 case JAVASOCKOPT_MCAST_TTL: {
3060 if ((anOption >> 16) & BROKEN_MULTICAST_TTL) {
3063 result = setsockopt(handle, IPPROTO_IP, IP_MULTICAST_TTL, &byteVal, byteSize);
3065 throwSocketException(env, convertError(errno));
3071 case JAVASOCKOPT_MCAST_ADD_MEMBERSHIP: {
3072 mcastAddDropMembership(env, handle, optVal,
3073 (anOption >> 16) & BROKEN_MULTICAST_IF, IP_ADD_MEMBERSHIP);
3077 case JAVASOCKOPT_MCAST_DROP_MEMBERSHIP: {
3078 mcastAddDropMembership(env, handle, optVal,
3079 (anOption >> 16) & BROKEN_MULTICAST_IF, IP_DROP_MEMBERSHIP);
3083 case JAVASOCKOPT_MCAST_INTERFACE: {
3084 if ((anOption >> 16) & BROKEN_MULTICAST_IF) {
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));
3094 throwSocketException(env, convertError(errno));
3100 case JAVASOCKOPT_SO_SNDBUF: {
3101 result = setsockopt(handle, SOL_SOCKET, SO_SNDBUF, &intVal, intSize);
3103 throwSocketException(env, convertError(errno));
3109 case JAVASOCKOPT_SO_RCVBUF: {
3110 result = setsockopt(handle, SOL_SOCKET, SO_RCVBUF, &intVal, intSize);
3112 throwSocketException(env, convertError(errno));
3118 case JAVASOCKOPT_SO_BROADCAST: {
3119 result = setsockopt(handle, SOL_SOCKET, SO_BROADCAST, &intVal, intSize);
3121 throwSocketException(env, convertError(errno));
3127 case JAVASOCKOPT_SO_REUSEADDR: {
3128 result = setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, &intVal, intSize);
3130 throwSocketException(env, convertError(errno));
3135 case JAVASOCKOPT_SO_KEEPALIVE: {
3136 result = setsockopt(handle, SOL_SOCKET, SO_KEEPALIVE, &intVal, intSize);
3138 throwSocketException(env, convertError(errno));
3144 case JAVASOCKOPT_SO_OOBINLINE: {
3145 result = setsockopt(handle, SOL_SOCKET, SO_OOBINLINE, &intVal, intSize);
3147 throwSocketException(env, convertError(errno));
3153 case JAVASOCKOPT_IP_MULTICAST_LOOP: {
3154 result = setsockopt(handle, IPPROTO_IP, IP_MULTICAST_LOOP, &intVal, intSize);
3156 throwSocketException(env, convertError(errno));
3162 case JAVASOCKOPT_IP_TOS: {
3163 result = setsockopt(handle, IPPROTO_IP, IP_TOS, &intVal, intSize);
3165 throwSocketException(env, convertError(errno));
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);
3175 throwSocketException(env, convertError(errno));
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));
3188 throwSocketException(env, convertError(errno));
3195 throwSocketException(env, SOCKERR_OPTUNSUPP);
3200 static jint osNetworkSystem_getSocketFlagsImpl(JNIEnv* env, jclass clazz) {
3201 // LOGD("ENTER getSocketFlagsImpl");
3203 // Not implemented by harmony
3207 static void osNetworkSystem_socketCloseImpl(JNIEnv* env, jclass clazz,
3208 jobject fileDescriptor) {
3209 // LOGD("ENTER socketCloseImpl");
3211 int handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
3213 if (handle == 0 || handle == -1) {
3214 throwSocketException(env, SOCKERR_BADSOCKET);
3218 log_socket_close(handle, SOCKET_CLOSE_LOCAL);
3220 jniSetFileDescriptorOfFD(env, fileDescriptor, -1);
3225 static jobject osNetworkSystem_getHostByAddrImpl(JNIEnv* env, jclass clazz,
3226 jbyteArray addrStr) {
3227 // LOGD("ENTER getHostByAddrImpl");
3229 if (addrStr == NULL) {
3230 throwNullPointerException(env);
3234 jstring address = (jstring)newJavaLangString(env, addrStr);
3236 const char* addr = env->GetStringUTFChars(address, NULL);
3238 struct hostent* ent = gethostbyaddr(addr, strlen(addr), AF_INET);
3240 if (ent != NULL && ent->h_name != NULL) {
3241 result = env->NewStringUTF(ent->h_name);
3246 env->ReleaseStringUTFChars(address, addr);
3251 static jobject osNetworkSystem_getHostByNameImpl(JNIEnv* env, jclass clazz,
3252 jstring nameStr, jboolean preferIPv6Addresses) {
3253 // LOGD("ENTER getHostByNameImpl");
3255 if (nameStr == NULL) {
3256 throwNullPointerException(env);
3260 const char* name = env->GetStringUTFChars(nameStr, NULL);
3262 if (useAdbNetworking) {
3269 // LOGD("ADB networking: +gethostbyname '%s'", name);
3271 err = adb_networking_gethostbyname(name, &(outaddr.a));
3273 env->ReleaseStringUTFChars(nameStr, name);
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]);
3284 jbyteArray addr = env->NewByteArray(4);
3285 env->SetByteArrayRegion(addr, 0, 4, outaddr.j);
3290 // normal case...no adb networking
3291 struct hostent* ent = gethostbyname(name);
3293 env->ReleaseStringUTFChars(nameStr, name);
3295 if (ent != NULL && ent->h_length > 0) {
3296 jbyteArray addr = env->NewByteArray(4);
3298 memcpy(v, ent->h_addr, 4);
3299 env->SetByteArrayRegion(addr, 0, 4, v);
3307 static void osNetworkSystem_setInetAddressImpl(JNIEnv* env, jobject obj,
3308 jobject sender, jbyteArray address) {
3309 // LOGD("ENTER setInetAddressImpl");
3311 env->SetObjectField(sender, gCachedFields.iaddr_ipaddress, address);
3314 static jobject osNetworkSystem_inheritedChannelImpl(JNIEnv* env, jobject obj) {
3315 // LOGD("ENTER inheritedChannelImpl");
3319 socklen_t length = sizeof(opt);
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;
3333 jboolean jtrue = JNI_TRUE;
3335 if (0 != getsockopt(socket, SOL_SOCKET, SO_TYPE, &opt, &length)) {
3338 if (SOCK_STREAM !=opt && SOCK_DGRAM !=opt) {
3343 length = sizeof(struct sockaddr);
3344 if (0 != getsockname(socket, (struct sockaddr *)&local_addr, &length)) {
3347 if (AF_INET != local_addr.sin_family || length != sizeof(struct sockaddr)) {
3350 localAddr = (jbyte*) malloc(sizeof(jbyte)*4);
3351 if (NULL == localAddr) {
3354 memcpy (localAddr, &(local_addr.sin_addr.s_addr), 4);
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);
3362 if (AF_INET != remote_addr.sin_family
3363 || length != sizeof(struct sockaddr)) {
3366 address = (jbyte*) malloc(sizeof(jbyte)*4);
3367 memcpy (address, &(remote_addr.sin_addr.s_addr), 4);
3370 // analysis end, begin pack to java
3371 if (SOCK_STREAM == opt) {
3372 if (remote_addr.sin_port!=0) {
3374 channel_class = env->FindClass(
3375 "org/apache/harmony/nio/internal/SocketChannelImpl");
3376 if (NULL == channel_class) {
3380 channel_new = env->GetMethodID(channel_class, "<init>", "()V");
3381 if (NULL == channel_new) {
3384 channel_object = env->NewObject(channel_class, channel_new);
3385 if (NULL == channel_object) {
3388 // new and set FileDescript
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) {
3397 jniSetFileDescriptorOfFD(env, fd_object, socket);
3400 port_field = env->GetFieldID(channel_class, "localPort", "I");
3401 env->SetIntField(channel_object, port_field,
3402 ntohs(local_addr.sin_port));
3404 // new and set remote addr
3405 addr_object = env->NewObject(gCachedFields.iaddr_class,
3406 gCachedFields.iaddr_class_init);
3407 if (NULL == addr_object) {
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,
3415 if (NULL == socketaddr_object) {
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,
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,
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,
3441 env->SetObjectField(socketaddr_object, localAddr_field,
3443 if (NULL == localAddr_object) {
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,
3453 port_field = env->GetFieldID(socketaddr_class, "port", "I");
3454 env->SetIntField(socketaddr_object, port_field,
3455 ntohs(remote_addr.sin_port));
3458 if (0 != local_addr.sin_port) {
3459 bound_field = env->GetFieldID(channel_class, "isBound", "Z");
3460 env->SetBooleanField(channel_object, bound_field, jtrue);
3465 channel_class = env->FindClass(
3466 "org/apache/harmony/nio/internal/ServerSocketChannelImpl");
3467 if (NULL == channel_class) {
3471 channel_new = env->GetMethodID(channel_class, "<init>", "()V");
3472 if (NULL == channel_new) {
3475 channel_object = env->NewObject(channel_class, channel_new);
3476 if (NULL == channel_object) {
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);
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);
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,
3498 if (NULL == socketImpl_object) {
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) {
3509 env->SetObjectField(socketImpl_object, localAddr_field,
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);
3517 port_field = env->GetFieldID(socketImpl_class, "localport", "I");
3518 env->SetIntField(socketImpl_object, port_field,
3519 ntohs(local_addr.sin_port));
3523 // new DatagramChannel
3524 channel_class = env->FindClass(
3525 "org/apache/harmony/nio/internal/DatagramChannelImpl");
3526 if (NULL == channel_class) {
3530 channel_new = env->GetMethodID(channel_class, "<init>", "()V");
3531 if (NULL == channel_new) {
3534 channel_object = env->NewObject(channel_class, channel_new);
3535 if (NULL == channel_object) {
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) {
3546 jniSetFileDescriptorOfFD(env, fd_object, socket);
3548 port_field = env->GetFieldID(channel_class, "localPort", "I");
3549 env->SetIntField(channel_object, port_field, ntohs(local_addr.sin_port));
3551 // new and set remote addr
3552 addr_object = env->NewObject(gCachedFields.iaddr_class,
3553 gCachedFields.iaddr_class_init);
3554 if (NULL == addr_object) {
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) {
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);
3572 if (0 != local_addr.sin_port) {
3573 bound_field = env->GetFieldID(channel_class, "isBound", "Z");
3574 env->SetBooleanField(channel_object, bound_field, jtrue);
3580 return channel_object;
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 },
3637 int register_org_apache_harmony_luni_platform_OSNetworkSystem(JNIEnv* env) {
3638 return jniRegisterNativeMethods(env,
3639 "org/apache/harmony/luni/platform/OSNetworkSystem",