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 "AndroidSystemNatives.h"
38 // Temporary hack to build on systems that don't have up-to-date libc headers.
40 #define IPV6_TCLASS 67
45 * Error codes for socket operations
47 * @internal SOCKERR* range from -200 to -299 avoid overlap
49 #define SOCKERR_BADSOCKET -200 /* generic error */
50 #define SOCKERR_NOTINITIALIZED -201 /* socket library uninitialized */
51 #define SOCKERR_BADAF -202 /* bad address family */
52 #define SOCKERR_BADPROTO -203 /* bad protocol */
53 #define SOCKERR_BADTYPE -204 /* bad type */
54 #define SOCKERR_SYSTEMBUSY -205 /* system busy handling requests */
55 #define SOCKERR_SYSTEMFULL -206 /* too many sockets */
56 #define SOCKERR_NOTCONNECTED -207 /* socket is not connected */
57 #define SOCKERR_INTERRUPTED -208 /* the call was cancelled */
58 #define SOCKERR_TIMEOUT -209 /* the operation timed out */
59 #define SOCKERR_CONNRESET -210 /* the connection was reset */
60 #define SOCKERR_WOULDBLOCK -211 /* the socket is marked as nonblocking operation would block */
61 #define SOCKERR_ADDRNOTAVAIL -212 /* address not available */
62 #define SOCKERR_ADDRINUSE -213 /* address already in use */
63 #define SOCKERR_NOTBOUND -214 /* the socket is not bound */
64 #define SOCKERR_UNKNOWNSOCKET -215 /* resolution of fileDescriptor to socket failed */
65 #define SOCKERR_INVALIDTIMEOUT -216 /* the specified timeout is invalid */
66 #define SOCKERR_FDSETFULL -217 /* Unable to create an FDSET */
67 #define SOCKERR_TIMEVALFULL -218 /* Unable to create a TIMEVAL */
68 #define SOCKERR_REMSOCKSHUTDOWN -219 /* The remote socket has shutdown gracefully */
69 #define SOCKERR_NOTLISTENING -220 /* listen() was not invoked prior to accept() */
70 #define SOCKERR_NOTSTREAMSOCK -221 /* The socket does not support connection-oriented service */
71 #define SOCKERR_ALREADYBOUND -222 /* The socket is already bound to an address */
72 #define SOCKERR_NBWITHLINGER -223 /* The socket is marked non-blocking & SO_LINGER is non-zero */
73 #define SOCKERR_ISCONNECTED -224 /* The socket is already connected */
74 #define SOCKERR_NOBUFFERS -225 /* No buffer space is available */
75 #define SOCKERR_HOSTNOTFOUND -226 /* Authoritative Answer Host not found */
76 #define SOCKERR_NODATA -227 /* Valid name, no data record of requested type */
77 #define SOCKERR_BOUNDORCONN -228 /* The socket has not been bound or is already connected */
78 #define SOCKERR_OPNOTSUPP -229 /* The socket does not support the operation */
79 #define SOCKERR_OPTUNSUPP -230 /* The socket option is not supported */
80 #define SOCKERR_OPTARGSINVALID -231 /* The socket option arguments are invalid */
81 #define SOCKERR_SOCKLEVELINVALID -232 /* The socket level is invalid */
82 #define SOCKERR_TIMEOUTFAILURE -233
83 #define SOCKERR_SOCKADDRALLOCFAIL -234 /* Unable to allocate the sockaddr structure */
84 #define SOCKERR_FDSET_SIZEBAD -235 /* The calculated maximum size of the file descriptor set is bad */
85 #define SOCKERR_UNKNOWNFLAG -236 /* The flag is unknown */
86 #define SOCKERR_MSGSIZE -237 /* The datagram was too big to fit the specified buffer & was truncated. */
87 #define SOCKERR_NORECOVERY -238 /* The operation failed with no recovery possible */
88 #define SOCKERR_ARGSINVALID -239 /* The arguments are invalid */
89 #define SOCKERR_BADDESC -240 /* The socket argument is not a valid file descriptor */
90 #define SOCKERR_NOTSOCK -241 /* The socket argument is not a socket */
91 #define SOCKERR_HOSTENTALLOCFAIL -242 /* Unable to allocate the hostent structure */
92 #define SOCKERR_TIMEVALALLOCFAIL -243 /* Unable to allocate the timeval structure */
93 #define SOCKERR_LINGERALLOCFAIL -244 /* Unable to allocate the linger structure */
94 #define SOCKERR_IPMREQALLOCFAIL -245 /* Unable to allocate the ipmreq structure */
95 #define SOCKERR_FDSETALLOCFAIL -246 /* Unable to allocate the fdset structure */
96 #define SOCKERR_OPFAILED -247 /* Operation failed */
97 #define SOCKERR_VALUE_NULL -248 /* The value indexed was NULL */
98 #define SOCKERR_CONNECTION_REFUSED -249 /* connection was refused */
99 #define SOCKERR_ENETUNREACH -250 /* network is not reachable */
100 #define SOCKERR_EACCES -251 /* permissions do not allow action on socket */
101 #define SOCKERR_EHOSTUNREACH -252 /* no route to host */
102 #define SOCKERR_EPIPE -253 /* broken pipe */
104 #define JAVASOCKOPT_TCP_NODELAY 1
105 #define JAVASOCKOPT_IP_TOS 3
106 #define JAVASOCKOPT_SO_REUSEADDR 4
107 #define JAVASOCKOPT_SO_KEEPALIVE 8
108 #define JAVASOCKOPT_MCAST_TIME_TO_LIVE 10 /* Currently unused */
109 #define JAVASOCKOPT_SO_BINDADDR 15
110 #define JAVASOCKOPT_MCAST_INTERFACE 16
111 #define JAVASOCKOPT_MCAST_TTL 17
112 #define JAVASOCKOPT_IP_MULTICAST_LOOP 18
113 #define JAVASOCKOPT_MCAST_ADD_MEMBERSHIP 19
114 #define JAVASOCKOPT_MCAST_DROP_MEMBERSHIP 20
115 #define JAVASOCKOPT_IP_MULTICAST_IF2 31
116 #define JAVASOCKOPT_SO_BROADCAST 32
117 #define JAVASOCKOPT_SO_LINGER 128
118 #define JAVASOCKOPT_REUSEADDR_AND_REUSEPORT 10001
119 #define JAVASOCKOPT_SO_SNDBUF 4097
120 #define JAVASOCKOPT_SO_RCVBUF 4098
121 #define JAVASOCKOPT_SO_RCVTIMEOUT 4102
122 #define JAVASOCKOPT_SO_OOBINLINE 4099
124 /* constants for calling multi-call functions */
125 #define SOCKET_STEP_START 10
126 #define SOCKET_STEP_CHECK 20
127 #define SOCKET_STEP_DONE 30
129 #define BROKEN_MULTICAST_IF 1
130 #define BROKEN_MULTICAST_TTL 2
131 #define BROKEN_TCP_NODELAY 4
133 #define SOCKET_CONNECT_STEP_START 0
134 #define SOCKET_CONNECT_STEP_CHECK 1
136 #define SOCKET_OP_NONE 0
137 #define SOCKET_OP_READ 1
138 #define SOCKET_OP_WRITE 2
139 #define SOCKET_READ_WRITE 3
141 #define SOCKET_MSG_PEEK 1
142 #define SOCKET_MSG_OOB 2
144 #define SOCKET_NOFLAGS 0
147 #define BUFFERSIZE 2048
149 // wait for 500000 usec = 0.5 second
150 #define SEND_RETRY_TIME 500000
152 // Local constants for getOrSetSocketOption
153 #define SOCKOPT_GET 1
154 #define SOCKOPT_SET 2
156 struct CachedFields {
157 jfieldID fd_descriptor;
159 jmethodID iaddr_getbyaddress;
161 jmethodID i4addr_class_init;
162 jfieldID iaddr_ipaddress;
163 jclass genericipmreq_class;
164 jclass integer_class;
165 jmethodID integer_class_init;
166 jfieldID integer_class_value;
167 jclass boolean_class;
168 jmethodID boolean_class_init;
169 jfieldID boolean_class_value;
171 jmethodID byte_class_init;
172 jfieldID byte_class_value;
174 jmethodID string_class_init;
175 jclass socketimpl_class;
176 jfieldID socketimpl_address;
177 jfieldID socketimpl_port;
179 jfieldID dpack_address;
181 jfieldID dpack_length;
184 static int useAdbNetworking = 0;
186 /* needed for connecting with timeout */
187 typedef struct selectFDSet {
195 static const char * netLookupErrorString(int anErrorNum);
198 * Throws an SocketException with the message affiliated with the errorCode.
200 static void throwSocketException(JNIEnv *env, int errorCode) {
201 jniThrowException(env, "java/net/SocketException",
202 netLookupErrorString(errorCode));
206 * Throws an IOException with the given message.
208 static void throwIOExceptionStr(JNIEnv *env, const char *message) {
209 jniThrowException(env, "java/io/IOException", message);
213 * Throws a NullPointerException.
215 static void throwNullPointerException(JNIEnv *env) {
216 jniThrowException(env, "java/lang/NullPointerException", NULL);
220 * Converts a 4-byte array to a native address structure. Throws a
221 * NullPointerException or an IOException in case of error. This is
222 * signaled by a return value of -1. The normal return value is 0.
224 static int javaAddressToStructIn(
225 JNIEnv *env, jbyteArray java_address, struct in_addr *address) {
227 memset(address, 0, sizeof(address));
229 if (java_address == NULL) {
233 if (env->GetArrayLength(java_address) != sizeof(address->s_addr)) {
237 jbyte * java_address_bytes
238 = env->GetByteArrayElements(java_address, NULL);
240 memcpy(&(address->s_addr),
242 sizeof(address->s_addr));
244 env->ReleaseByteArrayElements(java_address, java_address_bytes, JNI_ABORT);
250 * Converts a native address structure to a Java byte array. Throws a
251 * NullPointerException or an IOException in case of error. This is
252 * signaled by a return value of -1. The normal return value is 0.
254 * @param address the sockaddr_storage structure to convert
256 * @exception SocketException the address family is unknown, or out of memory
259 static jbyteArray socketAddressToAddressBytes(JNIEnv *env,
260 struct sockaddr_storage *address) {
263 size_t addressLength;
264 if (address->ss_family == AF_INET) {
265 struct sockaddr_in *sin = (struct sockaddr_in *) address;
266 rawAddress = &sin->sin_addr.s_addr;
268 } else if (address->ss_family == AF_INET6) {
269 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) address;
270 rawAddress = &sin6->sin6_addr.s6_addr;
273 throwSocketException(env, SOCKERR_BADAF);
277 jbyteArray byteArray = env->NewByteArray(addressLength);
278 if (byteArray == NULL) {
279 throwSocketException(env, SOCKERR_NOBUFFERS);
282 env->SetByteArrayRegion(byteArray, 0, addressLength, (jbyte *) rawAddress);
288 * Returns the port number in a sockaddr_storage structure.
290 * @param address the sockaddr_storage structure to get the port from
292 * @return the port number, or -1 if the address family is unknown.
294 static int getSocketAddressPort(struct sockaddr_storage *address) {
295 switch (address->ss_family) {
297 return ntohs(((struct sockaddr_in *) address)->sin_port);
299 return ntohs(((struct sockaddr_in6 *) address)->sin6_port);
306 * Converts a native address structure to an InetAddress object.
307 * Throws a NullPointerException or an IOException in case of
308 * error. This is signaled by a return value of -1. The normal
311 * @param sockaddress the sockaddr_storage structure to convert
313 * @return a jobject representing an InetAddress
315 static jobject socketAddressToInetAddress(JNIEnv *env,
316 struct sockaddr_storage *sockaddress) {
318 jbyteArray byteArray = socketAddressToAddressBytes(env, sockaddress);
319 if (byteArray == NULL) // Exception has already been thrown.
322 return env->CallStaticObjectMethod(gCachedFields.iaddr_class,
323 gCachedFields.iaddr_getbyaddress, byteArray);
327 * Converts an InetAddress object and port number to a native address structure.
328 * Throws a NullPointerException or a SocketException in case of
329 * error. This is signaled by a return value of -1. The normal
332 * @param inetaddress the InetAddress object to convert
333 * @param port the port number
334 * @param sockaddress the sockaddr_storage structure to write to
336 * @return 0 on success, -1 on failure
338 * @exception SocketError if the address family is unknown
340 static int inetAddressToSocketAddress(JNIEnv *env,
341 jobject inetaddress, int port, struct sockaddr_storage *sockaddress) {
343 // Get the byte array that stores the IP address bytes in the InetAddress.
344 jbyteArray addressByteArray;
345 addressByteArray = (jbyteArray)env->GetObjectField(inetaddress,
346 gCachedFields.iaddr_ipaddress);
347 if (addressByteArray == NULL) {
348 throwNullPointerException(env);
352 // Get the raw IP address bytes.
353 jbyte *addressBytes = env->GetByteArrayElements(addressByteArray, NULL);
354 if (addressBytes == NULL) {
355 throwNullPointerException(env);
359 // Convert the IP address bytes to the proper IP address type.
360 size_t addressLength = env->GetArrayLength(addressByteArray);
362 if (addressLength == 4) {
364 struct sockaddr_in *sin = (struct sockaddr_in *) sockaddress;
365 memset(sin, 0, sizeof(struct sockaddr_in));
366 sin->sin_family = AF_INET;
367 sin->sin_port = htons(port);
368 memcpy(&sin->sin_addr.s_addr, addressBytes, 4);
369 } else if (addressLength == 16) {
371 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sockaddress;
372 memset(sin6, 0, sizeof(struct sockaddr_in6));
373 sin6->sin6_family = AF_INET6;
374 sin6->sin6_port = htons(port);
375 memcpy(&sin6->sin6_addr.s6_addr, addressBytes, 16);
377 // Unknown address family.
378 throwSocketException(env, SOCKERR_BADAF);
381 env->ReleaseByteArrayElements(addressByteArray, addressBytes, 0);
386 * Answer a new java.lang.Boolean object.
388 * @param env pointer to the JNI library
389 * @param anInt the Boolean constructor argument
391 * @return the new Boolean
394 jobject newJavaLangBoolean(JNIEnv * env, jint anInt) {
396 jmethodID tempMethod;
398 tempClass = gCachedFields.boolean_class;
399 tempMethod = gCachedFields.boolean_class_init;
400 return env->NewObject(tempClass, tempMethod, (jboolean) (anInt != 0));
404 * Answer a new java.lang.Byte object.
406 * @param env pointer to the JNI library
407 * @param anInt the Byte constructor argument
409 * @return the new Byte
412 jobject newJavaLangByte(JNIEnv * env, jbyte val) {
414 jmethodID tempMethod;
416 tempClass = gCachedFields.byte_class;
417 tempMethod = gCachedFields.byte_class_init;
418 return env->NewObject(tempClass, tempMethod, val);
422 * Answer a new java.lang.Integer object.
424 * @param env pointer to the JNI library
425 * @param anInt the Integer constructor argument
427 * @return the new Integer
430 jobject newJavaLangInteger(JNIEnv * env, jint anInt) {
432 jmethodID tempMethod;
434 tempClass = gCachedFields.integer_class;
435 tempMethod = gCachedFields.integer_class_init;
436 return env->NewObject(tempClass, tempMethod, anInt);
440 * Answer a new java.lang.String object.
442 * @param env pointer to the JNI library
443 * @param anInt the byte[] constructor argument
445 * @return the new String
448 jobject newJavaLangString(JNIEnv * env, jbyteArray bytes) {
450 jmethodID tempMethod;
452 tempClass = gCachedFields.string_class;
453 tempMethod = gCachedFields.string_class_init;
454 return env->NewObject(tempClass, tempMethod, (jbyteArray) bytes);
458 * Query OS for timestamp.
459 * Retrieve the current value of system clock and convert to milliseconds.
461 * @param[in] portLibrary The port library.
463 * @return 0 on failure, time value in milliseconds on success.
464 * @deprecated Use @ref time_hires_clock and @ref time_hires_delta
466 * technically, this should return I_64 since both timeval.tv_sec and
467 * timeval.tv_usec are long
470 static int time_msec_clock() {
474 gettimeofday(&tp, &tzp);
475 return (tp.tv_sec * 1000) + (tp.tv_usec / 1000);
479 * Check if the passed sockaddr_storage struct contains a localhost address
481 * @param address address pointer to the address to check
483 * @return 0 if the passed address isn't a localhost address
485 static int isLocalHost(struct sockaddr_storage *address) {
486 if (address->ss_family == AF_INET) {
487 struct sockaddr_in *sin = (struct sockaddr_in *) address;
488 return (sin->sin_addr.s_addr == htonl(INADDR_LOOPBACK));
489 } else if (address->ss_family == AF_INET6) {
490 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) address;
491 return IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr);
498 * Decide whether to use ADB networking for the given socket address.
500 * @param address pointer to sockaddr_storage structure to check
502 * @return true if ADB networking should be used, false otherwise.
504 static bool useAdbNetworkingForAddress(struct sockaddr_storage *address) {
505 return useAdbNetworking && !isLocalHost(address) &&
506 address->ss_family == AF_INET;
510 * Convert a sockaddr_storage structure to a string for logging purposes.
512 * @param address pointer to sockaddr_storage structure to print
514 * @return a string with the textual representation of the address.
516 * @note Returns a statically allocated buffer, so is not thread-safe.
518 static char *socketAddressToString(struct sockaddr_storage *address) {
519 static char invalidString[] = "<invalid>";
520 static char ipString[INET6_ADDRSTRLEN + sizeof("[]:65535")];
522 char tmp[INET6_ADDRSTRLEN];
524 // TODO: getnameinfo seems to want its length parameter to be exactly
525 // sizeof(sockaddr_in) for an IPv4 address and sizeof (sockaddr_in6) for an
526 // IPv6 address. Fix getnameinfo so it accepts sizeof(sockaddr_storage), and
527 // then remove this hack.
528 int size = (address->ss_family == AF_INET) ?
529 sizeof(sockaddr_in) : sizeof(sockaddr_in6);
530 int result = getnameinfo((struct sockaddr *)address,
531 size, tmp, sizeof(tmp), NULL, 0,
535 return invalidString;
537 if (address->ss_family == AF_INET6) {
538 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) address;
539 port = ntohs(sin6->sin6_port);
540 sprintf(ipString, "[%s]:%d", tmp, port);
542 } else if (address->ss_family == AF_INET) {
543 struct sockaddr_in *sin = (struct sockaddr_in *) address;
544 port = ntohs(sin->sin_port);
545 sprintf(ipString, "%s:%d", tmp, port);
548 return invalidString;
553 * Answer the errorString corresponding to the errorNumber, if available.
554 * This function will answer a default error string, if the errorNumber is not
557 * This function will have to be reworked to handle internationalization
558 * properly, removing the explicit strings.
560 * @param anErrorNum the error code to resolve to a human readable string
562 * @return a human readable error string
565 static const char * netLookupErrorString(int anErrorNum) {
566 switch (anErrorNum) {
567 case SOCKERR_BADSOCKET:
569 case SOCKERR_NOTINITIALIZED:
570 return "Socket library uninitialized";
572 return "Bad address family";
573 case SOCKERR_BADPROTO:
574 return "Bad protocol";
575 case SOCKERR_BADTYPE:
577 case SOCKERR_SYSTEMBUSY:
578 return "System busy handling requests";
579 case SOCKERR_SYSTEMFULL:
580 return "Too many sockets allocated";
581 case SOCKERR_NOTCONNECTED:
582 return "Socket is not connected";
583 case SOCKERR_INTERRUPTED:
584 return "The system call was cancelled";
585 case SOCKERR_TIMEOUT:
586 return "The operation timed out";
587 case SOCKERR_CONNRESET:
588 return "The connection was reset";
589 case SOCKERR_WOULDBLOCK:
590 return "The nonblocking operation would block";
591 case SOCKERR_ADDRNOTAVAIL:
592 return "The address is not available";
593 case SOCKERR_ADDRINUSE:
594 return "The address is already in use";
595 case SOCKERR_NOTBOUND:
596 return "The socket is not bound";
597 case SOCKERR_UNKNOWNSOCKET:
598 return "Resolution of the FileDescriptor to socket failed";
599 case SOCKERR_INVALIDTIMEOUT:
600 return "The specified timeout is invalid";
601 case SOCKERR_FDSETFULL:
602 return "Unable to create an FDSET";
603 case SOCKERR_TIMEVALFULL:
604 return "Unable to create a TIMEVAL";
605 case SOCKERR_REMSOCKSHUTDOWN:
606 return "The remote socket has shutdown gracefully";
607 case SOCKERR_NOTLISTENING:
608 return "Listen() was not invoked prior to accept()";
609 case SOCKERR_NOTSTREAMSOCK:
610 return "The socket does not support connection-oriented service";
611 case SOCKERR_ALREADYBOUND:
612 return "The socket is already bound to an address";
613 case SOCKERR_NBWITHLINGER:
614 return "The socket is marked non-blocking & SO_LINGER is non-zero";
615 case SOCKERR_ISCONNECTED:
616 return "The socket is already connected";
617 case SOCKERR_NOBUFFERS:
618 return "No buffer space is available";
619 case SOCKERR_HOSTNOTFOUND:
620 return "Authoritative Answer Host not found";
622 return "Valid name, no data record of requested type";
623 case SOCKERR_BOUNDORCONN:
624 return "The socket has not been bound or is already connected";
625 case SOCKERR_OPNOTSUPP:
626 return "The socket does not support the operation";
627 case SOCKERR_OPTUNSUPP:
628 return "The socket option is not supported";
629 case SOCKERR_OPTARGSINVALID:
630 return "The socket option arguments are invalid";
631 case SOCKERR_SOCKLEVELINVALID:
632 return "The socket level is invalid";
633 case SOCKERR_TIMEOUTFAILURE:
634 return "The timeout operation failed";
635 case SOCKERR_SOCKADDRALLOCFAIL:
636 return "Failed to allocate address structure";
637 case SOCKERR_FDSET_SIZEBAD:
638 return "The calculated maximum size of the file descriptor set is bad";
639 case SOCKERR_UNKNOWNFLAG:
640 return "The flag is unknown";
641 case SOCKERR_MSGSIZE:
642 return "The datagram was too big to fit the specified buffer, so truncated";
643 case SOCKERR_NORECOVERY:
644 return "The operation failed with no recovery possible";
645 case SOCKERR_ARGSINVALID:
646 return "The arguments are invalid";
647 case SOCKERR_BADDESC:
648 return "The socket argument is not a valid file descriptor";
649 case SOCKERR_NOTSOCK:
650 return "The socket argument is not a socket";
651 case SOCKERR_HOSTENTALLOCFAIL:
652 return "Unable to allocate the hostent structure";
653 case SOCKERR_TIMEVALALLOCFAIL:
654 return "Unable to allocate the timeval structure";
655 case SOCKERR_LINGERALLOCFAIL:
656 return "Unable to allocate the linger structure";
657 case SOCKERR_IPMREQALLOCFAIL:
658 return "Unable to allocate the ipmreq structure";
659 case SOCKERR_FDSETALLOCFAIL:
660 return "Unable to allocate the fdset structure";
661 case SOCKERR_OPFAILED:
662 return "Operation failed";
663 case SOCKERR_CONNECTION_REFUSED:
664 return "Connection refused";
665 case SOCKERR_ENETUNREACH:
666 return "Network unreachable";
667 case SOCKERR_EHOSTUNREACH:
668 return "No route to host";
670 return "Broken pipe";
672 return "Permission denied (maybe missing INTERNET permission)";
675 LOGE("unknown socket error %d", anErrorNum);
676 return "unknown error";
680 static int convertError(int errorCode) {
683 return SOCKERR_BADDESC;
685 return SOCKERR_NOBUFFERS;
687 return SOCKERR_OPNOTSUPP;
689 return SOCKERR_OPTUNSUPP;
691 return SOCKERR_SOCKLEVELINVALID;
693 return SOCKERR_NOTSOCK;
695 return SOCKERR_INTERRUPTED;
697 return SOCKERR_NOTCONNECTED;
699 return SOCKERR_BADAF;
700 /* note: CONNRESET not included because it has the same
701 * value as ECONNRESET and they both map to SOCKERR_CONNRESET */
703 return SOCKERR_CONNRESET;
705 return SOCKERR_WOULDBLOCK;
706 case EPROTONOSUPPORT:
707 return SOCKERR_BADPROTO;
709 return SOCKERR_ARGSINVALID;
711 return SOCKERR_TIMEOUT;
713 return SOCKERR_CONNECTION_REFUSED;
715 return SOCKERR_ENETUNREACH;
717 return SOCKERR_EACCES;
719 return SOCKERR_EPIPE;
721 return SOCKERR_EHOSTUNREACH;
723 return SOCKERR_ADDRINUSE;
725 return SOCKERR_ADDRNOTAVAIL;
727 return SOCKERR_MSGSIZE;
729 LOGE("unclassified errno %d (%s)", errorCode, strerror(errorCode));
730 return SOCKERR_OPFAILED;
734 static int sockSelect(int nfds, fd_set *readfds, fd_set *writefds,
735 fd_set *exceptfds, struct timeval *timeout) {
737 int result = select(nfds, readfds, writefds, exceptfds, timeout);
740 if (errno == EINTR) {
741 result = SOCKERR_INTERRUPTED;
743 result = SOCKERR_OPFAILED;
745 } else if (result == 0) {
746 result = SOCKERR_TIMEOUT;
751 #define SELECT_READ_TYPE 0
752 #define SELECT_WRITE_TYPE 1
754 static int selectWait(int handle, int uSecTime, int type) {
756 struct timeval time, *timePtr;
758 int size = handle + 1;
761 FD_SET(handle, &fdset);
764 /* Use a timeout if uSecTime >= 0 */
765 memset(&time, 0, sizeof(time));
766 time.tv_usec = uSecTime;
769 /* Infinite timeout if uSecTime < 0 */
773 if (type == SELECT_READ_TYPE) {
774 result = sockSelect(size, &fdset, NULL, NULL, timePtr);
776 result = sockSelect(size, NULL, &fdset, NULL, timePtr);
781 static int pollSelectWait(JNIEnv *env, jobject fileDescriptor, int timeout, int type) {
782 /* now try reading the socket for the timespan timeout.
783 * if timeout is 0 try forever until the soclets gets ready or until an
786 int pollTimeoutUSec = 100000, pollMsec = 100;
788 int timeLeft = timeout;
789 int hasTimeout = timeout > 0 ? 1 : 0;
794 finishTime = time_msec_clock() + timeout;
799 while (poll) { /* begin polling loop */
802 * Fetch the handle every time in case the socket is closed.
804 handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
806 if (handle == 0 || handle == -1) {
807 throwSocketException(env, SOCKERR_INTERRUPTED);
813 if (timeLeft - 10 < pollMsec) {
814 pollTimeoutUSec = timeLeft <= 0 ? 0 : (timeLeft * 1000);
817 result = selectWait(handle, pollTimeoutUSec, type);
820 * because we are polling at a time smaller than timeout
821 * (presumably) lets treat an interrupt and timeout the same - go
822 * see if we're done timewise, and then just try again if not.
824 if (SOCKERR_TIMEOUT == result ||
825 SOCKERR_INTERRUPTED == result) {
827 timeLeft = finishTime - time_msec_clock();
831 * Always throw the "timeout" message because that is
832 * effectively what has happened, even if we happen to
833 * have been interrupted.
835 jniThrowException(env, "java/net/SocketTimeoutException",
836 netLookupErrorString(SOCKERR_TIMEOUT));
838 continue; // try again
841 } else if (0 > result) {
842 throwSocketException(env, result);
846 } else { /* polling with no timeout (why would you do this?)*/
848 result = selectWait(handle, pollTimeoutUSec, type);
851 * if interrupted (or a timeout) just retry
853 if (SOCKERR_TIMEOUT == result ||
854 SOCKERR_INTERRUPTED == result) {
856 continue; // try again
857 } else if (0 > result) {
858 throwSocketException(env, result);
862 } /* end polling loop */
868 * Obtain the socket address family from an existing socket.
870 * @param socket the filedescriptor of the socket to examine
872 * @return an integer, the address family of the socket
874 static int getSocketAddressFamily(int socket) {
875 struct sockaddr_storage ss;
876 socklen_t namelen = sizeof(ss);
877 int ret = getsockname(socket, (struct sockaddr*) &ss, &namelen);
886 * A helper method, to set the connect context to a Long object.
888 * @param env pointer to the JNI library
889 * @param longclass Java Long Object
891 void setConnectContext(JNIEnv *env,jobject longclass,jbyte * context) {
892 jclass descriptorCLS;
893 jfieldID descriptorFID;
894 descriptorCLS = env->FindClass("java/lang/Long");
895 descriptorFID = env->GetFieldID(descriptorCLS, "value", "J");
896 env->SetLongField(longclass, descriptorFID, (jlong)((jint)context));
900 * A helper method, to get the connect context.
902 * @param env pointer to the JNI library
903 * @param longclass Java Long Object
905 jbyte *getConnectContext(JNIEnv *env, jobject longclass) {
906 jclass descriptorCLS;
907 jfieldID descriptorFID;
908 descriptorCLS = env->FindClass("java/lang/Long");
909 descriptorFID = env->GetFieldID(descriptorCLS, "value", "J");
910 return (jbyte*) ((jint)env->GetLongField(longclass, descriptorFID));
913 // typical ip checksum
914 unsigned short ip_checksum(unsigned short* buffer, int size) {
915 register unsigned short * buf = buffer;
916 register int bufleft = size;
917 register unsigned long sum = 0;
919 while (bufleft > 1) {
920 sum = sum + (*buf++);
921 bufleft = bufleft - sizeof(unsigned short );
924 sum = sum + (*(unsigned char*)buf);
926 sum = (sum >> 16) + (sum & 0xffff);
929 return (unsigned short )(~sum);
933 * Converts an IPv4 address to an IPv4-mapped IPv6 address. Performs no error
936 * @param address the address to convert. Must contain an IPv4 address.
937 * @param outputAddress the converted address. Will contain an IPv6 address.
938 * @param mapUnspecified if true, convert 0.0.0.0 to ::ffff:0:0; if false, to ::
940 static void ipv4ToMappedAddress(struct sockaddr_storage *address,
941 struct sockaddr_storage *outputAddress, bool mapUnspecified) {
942 memset(outputAddress, 0, sizeof(struct sockaddr_storage));
943 const struct sockaddr_in *sin = ((struct sockaddr_in *) address);
944 struct sockaddr_in6 *sin6 = ((struct sockaddr_in6 *) outputAddress);
945 sin6->sin6_family = AF_INET6;
946 sin6->sin6_addr.s6_addr32[3] = sin->sin_addr.s_addr;
947 if (sin->sin_addr.s_addr != 0 || mapUnspecified) {
948 sin6->sin6_addr.s6_addr32[2] = htonl(0xffff);
950 sin6->sin6_port = sin->sin_port;
954 * Wrapper for connect() that converts IPv4 addresses to IPv4-mapped IPv6
955 * addresses if necessary.
957 * @param socket the filedescriptor of the socket to connect
958 * @param socketAddress the address to connect to
960 static int doConnect(int socket, struct sockaddr_storage *socketAddress) {
961 struct sockaddr_storage mappedAddress;
962 struct sockaddr_storage *realAddress;
963 if (socketAddress->ss_family == AF_INET &&
964 getSocketAddressFamily(socket) == AF_INET6) {
965 ipv4ToMappedAddress(socketAddress, &mappedAddress, true);
966 realAddress = &mappedAddress;
968 realAddress = socketAddress;
972 ret = connect(socket, (struct sockaddr *) realAddress,
973 sizeof(struct sockaddr_storage));
974 } while (ret < 0 && errno == EINTR);
979 * Wrapper for bind() that converts IPv4 addresses to IPv4-mapped IPv6
980 * addresses if necessary.
982 * @param socket the filedescriptor of the socket to connect
983 * @param socketAddress the address to connect to
985 static int doBind(int socket, struct sockaddr_storage *socketAddress) {
986 struct sockaddr_storage mappedAddress;
987 struct sockaddr_storage *realAddress;
988 if (socketAddress->ss_family == AF_INET &&
989 getSocketAddressFamily(socket) == AF_INET6) {
990 ipv4ToMappedAddress(socketAddress, &mappedAddress, false);
991 realAddress = &mappedAddress;
993 realAddress = socketAddress;
997 ret = bind(socket, (struct sockaddr *) realAddress,
998 sizeof(struct sockaddr_storage));
999 } while (ret < 0 && errno == EINTR);
1004 * Establish a connection to a peer with a timeout. This function is called
1005 * repeatedly in order to carry out the connect and to allow other tasks to
1006 * proceed on certain platforms. The caller must first call with
1007 * step = SOCKET_STEP_START, if the result is SOCKERR_NOTCONNECTED it will then
1008 * call it with step = CHECK until either another error or 0 is returned to
1009 * indicate the connect is complete. Each time the function should sleep for no
1010 * more than timeout milliseconds. If the connect succeeds or an error occurs,
1011 * the caller must always end the process by calling the function with
1012 * step = SOCKET_STEP_DONE
1014 * @param[in] portLibrary The port library.
1015 * @param[in] sock pointer to the unconnected local socket.
1016 * @param[in] addr pointer to the sockaddr, specifying remote host/port.
1017 * @param[in] timeout the timeout in milliseconds. If timeout is negative,
1018 * perform a block operation.
1019 * @param[in,out] pointer to context pointer. Filled in on first call and then
1020 * to be passed into each subsequent call.
1022 * @return 0, if no errors occurred, otherwise the (negative) error code.
1024 static int sockConnectWithTimeout(int handle, struct sockaddr_storage addr,
1025 unsigned int timeout, unsigned int step, jbyte *ctxt) {
1027 struct timeval passedTimeout;
1029 socklen_t errorValLen = sizeof(int);
1030 struct selectFDSet *context = NULL;
1032 if (SOCKET_STEP_START == step) {
1034 context = (struct selectFDSet *) ctxt;
1036 context->sock = handle;
1037 context->nfds = handle + 1;
1039 if (useAdbNetworkingForAddress(&addr)) {
1041 // LOGD("+connect to address 0x%08x (via adb)",
1042 // addr.sin_addr.s_addr);
1043 rc = adb_networking_connect_fd(handle, (struct sockaddr_in *) &addr);
1044 // LOGD("-connect ret %d errno %d (via adb)", rc, errno);
1047 /* set the socket to non-blocking */
1048 int block = JNI_TRUE;
1049 rc = ioctl(handle, FIONBIO, &block);
1051 return convertError(rc);
1054 // LOGD("+connect to address 0x%08x (via normal) on handle %d",
1055 // addr.sin_addr.s_addr, handle);
1056 rc = doConnect(handle, &addr);
1057 // LOGD("-connect to address 0x%08x (via normal) returned %d",
1058 // addr.sin_addr.s_addr, (int) rc);
1066 return SOCKERR_ALREADYBOUND;
1069 return SOCKERR_NOTCONNECTED;
1071 return convertError(rc);
1075 /* we connected right off the bat so just return */
1078 } else if (SOCKET_STEP_CHECK == step) {
1079 /* now check if we have connected yet */
1081 context = (struct selectFDSet *) ctxt;
1084 * set the timeout value to be used. Because on some unix platforms we
1085 * don't get notified when a socket is closed we only sleep for 100ms
1088 passedTimeout.tv_sec = 0;
1089 if (timeout > 100) {
1090 passedTimeout.tv_usec = 100 * 1000;
1091 } else if ((int)timeout >= 0) {
1092 passedTimeout.tv_usec = timeout * 1000;
1095 /* initialize the FD sets for the select */
1096 FD_ZERO(&(context->exceptionSet));
1097 FD_ZERO(&(context->writeSet));
1098 FD_ZERO(&(context->readSet));
1099 FD_SET(context->sock, &(context->writeSet));
1100 FD_SET(context->sock, &(context->readSet));
1101 FD_SET(context->sock, &(context->exceptionSet));
1103 rc = select(context->nfds,
1104 &(context->readSet),
1105 &(context->writeSet),
1106 &(context->exceptionSet),
1107 (int)timeout >= 0 ? &passedTimeout : NULL);
1109 /* if there is at least one descriptor ready to be checked */
1111 /* if the descriptor is in the write set we connected or failed */
1112 if (FD_ISSET(context->sock, &(context->writeSet))) {
1114 if (!FD_ISSET(context->sock, &(context->readSet))) {
1115 /* ok we have connected ok */
1118 /* ok we have more work to do to figure it out */
1119 if (getsockopt(context->sock, SOL_SOCKET, SO_ERROR,
1120 &errorVal, &errorValLen) >= 0) {
1121 return errorVal ? convertError(errorVal) : 0;
1123 return convertError(errno);
1128 /* if the descriptor is in the exception set the connect failed */
1129 if (FD_ISSET(context->sock, &(context->exceptionSet))) {
1130 if (getsockopt(context->sock, SOL_SOCKET, SO_ERROR, &errorVal,
1131 &errorValLen) >= 0) {
1132 return errorVal ? convertError(errorVal) : 0;
1135 return convertError(rc);
1138 } else if (rc < 0) {
1139 /* something went wrong with the select call */
1142 /* if it was EINTR we can just try again. Return not connected */
1144 return SOCKERR_NOTCONNECTED;
1147 /* some other error occured so look it up and return */
1148 return convertError(rc);
1152 * if we get here the timeout expired or the connect had not yet
1153 * completed just indicate that the connect is not yet complete
1155 return SOCKERR_NOTCONNECTED;
1156 } else if (SOCKET_STEP_DONE == step) {
1157 /* we are done the connect or an error occured so clean up */
1159 int block = JNI_FALSE;
1160 ioctl(handle, FIONBIO, &block);
1164 return SOCKERR_ARGSINVALID;
1169 * Helper method to get or set socket options
1171 * @param action SOCKOPT_GET to get an option, SOCKOPT_SET to set it
1172 * @param socket the file descriptor of the socket to use
1173 * @param ipv4Option the option value to use for an IPv4 socket
1174 * @param ipv6Option the option value to use for an IPv6 socket
1175 * @param optionValue the value of the socket option to get or set
1176 * @param optionLength the length of the socket option to get or set
1178 * @return the value of the socket call, or -1 on failure inside this function
1180 * @note on internal failure, the errno variable will be set appropriately
1182 static int getOrSetSocketOption(int action, int socket, int ipv4Option,
1183 int ipv6Option, void *optionValue, socklen_t *optionLength) {
1186 int family = getSocketAddressFamily(socket);
1189 option = ipv4Option;
1190 protocol = IPPROTO_IP;
1193 option = ipv6Option;
1194 protocol = IPPROTO_IPV6;
1197 errno = EAFNOSUPPORT;
1200 if (action == SOCKOPT_GET) {
1201 return getsockopt(socket, protocol, option, &optionValue, optionLength);
1202 } else if (action == SOCKOPT_SET) {
1203 return setsockopt(socket, protocol, option, &optionValue,
1212 * Find the interface index that was set for this socket by the IP_MULTICAST_IF
1213 * or IPV6_MULTICAST_IF socket option.
1215 * @param socket the socket to examine
1217 * @return the interface index, or -1 on failure
1219 * @note on internal failure, the errno variable will be set appropriately
1221 static int interfaceIndexFromMulticastSocket(int socket) {
1222 int family = getSocketAddressFamily(socket);
1223 socklen_t requestLength;
1226 if (family == AF_INET) {
1227 // IP_MULTICAST_IF returns a pointer to a struct ip_mreqn.
1228 struct ip_mreqn tempRequest;
1229 requestLength = sizeof(tempRequest);
1230 result = getsockopt(socket, IPPROTO_IP, IP_MULTICAST_IF, &tempRequest,
1232 interfaceIndex = tempRequest.imr_ifindex;
1233 } else if (family == AF_INET6) {
1234 // IPV6_MULTICAST_IF returns a pointer to an integer.
1235 requestLength = sizeof(interfaceIndex);
1236 result = getsockopt(socket, IPPROTO_IPV6, IPV6_MULTICAST_IF,
1237 &interfaceIndex, &requestLength);
1239 errno = EAFNOSUPPORT;
1244 return interfaceIndex;
1251 * Join/Leave the nominated multicast group on the specified socket.
1252 * Implemented by setting the multicast 'add membership'/'drop membership'
1253 * option at the HY_IPPROTO_IP level on the socket.
1255 * Implementation note for multicast sockets in general:
1257 * - This code is untested, because at the time of this writing multicast can't
1258 * be properly tested on Android due to GSM routing restrictions. So it might
1259 * or might not work.
1261 * - The REUSEPORT socket option that Harmony employs is not supported on Linux
1262 * and thus also not supported on Android. It's is not needed for multicast
1263 * to work anyway (REUSEADDR should suffice).
1265 * @param env pointer to the JNI library.
1266 * @param socketP pointer to the hysocket to join/leave on.
1267 * @param optVal pointer to the InetAddress, the multicast group to join/drop.
1269 * @exception SocketException if an error occurs during the call
1271 static void mcastAddDropMembership (JNIEnv * env, int handle, jobject optVal,
1272 int ignoreIF, int setSockOptVal) {
1273 struct sockaddr_storage sockaddrP;
1275 // By default, let the system decide which interface to use.
1276 int interfaceIndex = 0;
1279 * Check whether we are getting an InetAddress or an Generic IPMreq. For now
1280 * we support both so that we will not break the tests. If an InetAddress
1281 * is passed in, only support IPv4 as obtaining an interface from an
1282 * InetAddress is complex and should be done by the Java caller.
1284 if (env->IsInstanceOf (optVal, gCachedFields.iaddr_class)) {
1286 * optVal is an InetAddress. Construct a multicast request structure
1287 * from this address. Support IPv4 only.
1289 struct ip_mreqn multicastRequest;
1290 socklen_t length = sizeof(multicastRequest);
1291 memset(&multicastRequest, 0, length);
1293 // If ignoreIF is false, determine the index of the interface to use.
1295 interfaceIndex = interfaceIndexFromMulticastSocket(handle);
1296 multicastRequest.imr_ifindex = interfaceIndex;
1297 if (interfaceIndex == -1) {
1298 throwSocketException(env, convertError(errno));
1303 // Convert the inetAddress to an IPv4 address structure.
1304 result = inetAddressToSocketAddress(env, optVal, 0, &sockaddrP);
1305 if (result < 0) // Exception has already been thrown.
1307 if (sockaddrP.ss_family != AF_INET) {
1308 throwSocketException(env, SOCKERR_BADAF);
1311 struct sockaddr_in *sin = (struct sockaddr_in *) &sockaddrP;
1312 multicastRequest.imr_multiaddr = sin->sin_addr;
1314 result = setsockopt(handle, IPPROTO_IP, setSockOptVal,
1315 &multicastRequest, length);
1317 throwSocketException (env, convertError(errno));
1322 * optVal is a GenericIPMreq object. Extract the relevant fields from
1323 * it and construct a multicast request structure from these. Support
1324 * both IPv4 and IPv6.
1327 jfieldID multiaddrID;
1328 jfieldID interfaceIdxID;
1331 // Get the multicast address to join or leave.
1332 cls = env->GetObjectClass(optVal);
1333 multiaddrID = env->GetFieldID(cls, "multiaddr", "Ljava/net/InetAddress;");
1334 multiaddr = env->GetObjectField(optVal, multiaddrID);
1336 // Get the interface index to use.
1338 interfaceIdxID = env->GetFieldID(cls, "interfaceIdx", "I");
1339 interfaceIndex = env->GetIntField(optVal, interfaceIdxID);
1342 result = inetAddressToSocketAddress(env, multiaddr, 0, &sockaddrP);
1343 if (result < 0) // Exception has already been thrown.
1346 struct ip_mreqn ipv4Request;
1347 struct ipv6_mreq ipv6Request;
1348 void *multicastRequest;
1349 socklen_t requestLength;
1351 int family = getSocketAddressFamily(handle);
1354 requestLength = sizeof(ipv4Request);
1355 memset(&ipv4Request, 0, requestLength);
1356 ipv4Request.imr_multiaddr =
1357 ((struct sockaddr_in *) &sockaddrP)->sin_addr;
1358 ipv4Request.imr_ifindex = interfaceIndex;
1359 multicastRequest = &ipv4Request;
1363 requestLength = sizeof(ipv6Request);
1364 memset(&ipv6Request, 0, requestLength);
1365 ipv6Request.ipv6mr_multiaddr =
1366 ((struct sockaddr_in6 *) &sockaddrP)->sin6_addr;
1367 ipv6Request.ipv6mr_interface = interfaceIndex;
1368 multicastRequest = &ipv6Request;
1369 level = IPPROTO_IPV6;
1372 throwSocketException (env, SOCKERR_BADAF);
1376 /* join/drop the multicast address */
1377 result = setsockopt(handle, level, setSockOptVal, multicastRequest,
1380 throwSocketException (env, convertError(errno));
1386 static void osNetworkSystem_oneTimeInitializationImpl(JNIEnv* env, jobject obj,
1387 jboolean jcl_supports_ipv6) {
1388 // LOGD("ENTER oneTimeInitializationImpl of OSNetworkSystem");
1390 char useAdbNetworkingProperty[PROPERTY_VALUE_MAX];
1391 char adbConnectedProperty[PROPERTY_VALUE_MAX];
1393 property_get("android.net.use-adb-networking", useAdbNetworkingProperty, "");
1394 property_get("adb.connected", adbConnectedProperty, "");
1396 if (strlen((char *)useAdbNetworkingProperty) > 0
1397 && strlen((char *)adbConnectedProperty) > 0) {
1398 useAdbNetworking = 1;
1401 memset(&gCachedFields, 0, sizeof(gCachedFields));
1402 struct CachedFields *c = &gCachedFields;
1408 {&c->iaddr_class, "java/net/InetAddress"},
1409 {&c->i4addr_class, "java/net/Inet4Address"},
1410 {&c->genericipmreq_class, "org/apache/harmony/luni/net/GenericIPMreq"},
1411 {&c->integer_class, "java/lang/Integer"},
1412 {&c->boolean_class, "java/lang/Boolean"},
1413 {&c->byte_class, "java/lang/Byte"},
1414 {&c->string_class, "java/lang/String"},
1415 {&c->socketimpl_class, "java/net/SocketImpl"},
1416 {&c->dpack_class, "java/net/DatagramPacket"}
1418 for (unsigned i = 0; i < sizeof(classes) / sizeof(classes[0]); i++) {
1419 classInfo c = classes[i];
1420 jclass tempClass = env->FindClass(c.name);
1421 if (tempClass == NULL) return;
1422 *c.clazz = (jclass) env->NewGlobalRef(tempClass);
1429 const char *signature;
1432 {&c->i4addr_class_init, c->i4addr_class, "<init>", "([B)V", false},
1433 {&c->integer_class_init, c->integer_class, "<init>", "(I)V", false},
1434 {&c->boolean_class_init, c->boolean_class, "<init>", "(Z)V", false},
1435 {&c->byte_class_init, c->byte_class, "<init>", "(B)V", false},
1436 {&c->string_class_init, c->string_class, "<init>", "([B)V", false},
1437 {&c->iaddr_getbyaddress, c->iaddr_class, "getByAddress",
1438 "([B)Ljava/net/InetAddress;", true}
1440 for (unsigned i = 0; i < sizeof(methods) / sizeof(methods[0]); i++) {
1441 methodInfo m = methods[i];
1443 *m.method = env->GetStaticMethodID(m.clazz, m.name, m.signature);
1445 *m.method = env->GetMethodID(m.clazz, m.name, m.signature);
1447 if (*m.method == NULL) return;
1456 {&c->iaddr_ipaddress, c->iaddr_class, "ipaddress", "[B"},
1457 {&c->integer_class_value, c->integer_class, "value", "I"},
1458 {&c->boolean_class_value, c->boolean_class, "value", "Z"},
1459 {&c->byte_class_value, c->byte_class, "value", "B"},
1460 {&c->socketimpl_port, c->socketimpl_class, "port", "I"},
1461 {&c->socketimpl_address, c->socketimpl_class, "address",
1462 "Ljava/net/InetAddress;"},
1463 {&c->dpack_address, c->dpack_class, "address",
1464 "Ljava/net/InetAddress;"},
1465 {&c->dpack_port, c->dpack_class, "port", "I"},
1466 {&c->dpack_length, c->dpack_class, "length", "I"}
1468 for (unsigned i = 0; i < sizeof(fields) / sizeof(fields[0]); i++) {
1469 fieldInfo f = fields[i];
1470 *f.field = env->GetFieldID(f.clazz, f.name, f.type);
1471 if (*f.field == NULL) return;
1476 * Helper function to create a socket of the specified type and bind it to a
1477 * Java file descriptor.
1479 * @param fileDescriptor the file descriptor to bind the socket to
1480 * @param type the socket type to create, e.g., SOCK_STREAM
1481 * @throws SocketException an error occurred when creating the socket
1483 * @return the socket file descriptor. On failure, an exception is thrown and
1484 * a negative value is returned.
1487 static int createSocketFileDescriptor(JNIEnv* env, jobject fileDescriptor,
1489 if (fileDescriptor == NULL) {
1490 throwNullPointerException(env);
1496 sock = socket(PF_INET6, type, 0);
1497 if (sock < 0 && errno == EAFNOSUPPORT) {
1498 sock = socket(PF_INET, type, 0);
1501 int err = convertError(errno);
1502 throwSocketException(env, err);
1505 jniSetFileDescriptorOfFD(env, fileDescriptor, sock);
1510 static void osNetworkSystem_createStreamSocketImpl(JNIEnv* env, jclass clazz,
1511 jobject fileDescriptor, jboolean preferIPv4Stack) {
1512 // LOGD("ENTER createSocketImpl");
1513 createSocketFileDescriptor(env, fileDescriptor, SOCK_STREAM);
1516 static void osNetworkSystem_createDatagramSocketImpl(JNIEnv* env, jclass clazz,
1517 jobject fileDescriptor, jboolean preferIPv4Stack) {
1518 // LOGD("ENTER createDatagramSocketImpl");
1519 createSocketFileDescriptor(env, fileDescriptor, SOCK_DGRAM);
1522 static jint osNetworkSystem_readSocketDirectImpl(JNIEnv* env, jclass clazz,
1523 jobject fileDescriptor, jint address, jint offset, jint count,
1525 // LOGD("ENTER readSocketDirectImpl");
1528 jbyte *message = (jbyte *)address + offset;
1529 int result, ret, localCount;
1531 handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
1533 if (handle == 0 || handle == -1) {
1534 throwSocketException(env, SOCKERR_BADSOCKET);
1538 result = selectWait(handle, timeout, SELECT_READ_TYPE);
1544 localCount = (count < 65536) ? count : 65536;
1547 ret = recv(handle, (jbyte *) message, localCount, SOCKET_NOFLAGS);
1548 } while (ret < 0 && errno == EINTR);
1552 } else if (ret == -1) {
1553 int err = convertError(errno);
1554 throwSocketException(env, err);
1560 static jint osNetworkSystem_readSocketImpl(JNIEnv* env, jclass clazz,
1561 jobject fileDescriptor, jbyteArray data, jint offset, jint count,
1563 // LOGD("ENTER readSocketImpl");
1566 int result, localCount;
1568 jbyte internalBuffer[BUFFERSIZE];
1570 localCount = (count < 65536) ? count : 65536;
1572 if (localCount > BUFFERSIZE) {
1573 message = (jbyte*)malloc(localCount * sizeof(jbyte));
1574 if (message == NULL) {
1575 jniThrowException(env, "java/lang/OutOfMemoryError",
1576 "couldn't allocate enough memory for readSocket");
1580 message = (jbyte *)internalBuffer;
1583 result = osNetworkSystem_readSocketDirectImpl(env, clazz, fileDescriptor,
1584 (jint) message, 0, localCount, timeout);
1587 env->SetByteArrayRegion(data, offset, result, (jbyte *)message);
1590 if (((jbyte *)message) != internalBuffer) {
1591 free(( jbyte *)message);
1597 static jint osNetworkSystem_writeSocketDirectImpl(JNIEnv* env, jclass clazz,
1598 jobject fileDescriptor, jint address, jint offset, jint count) {
1599 // LOGD("ENTER writeSocketDirectImpl");
1602 jbyte *message = (jbyte *)address + offset;
1603 int result = 0, sent = 0;
1609 handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
1611 if (handle == 0 || handle == -1) {
1612 throwSocketException(env, SOCKERR_BADSOCKET);
1616 result = send(handle, (jbyte *) message, (int) count, SOCKET_NOFLAGS);
1618 int err = convertError(errno);
1620 if (SOCKERR_WOULDBLOCK == err){
1621 jclass socketExClass,errorCodeExClass;
1622 jmethodID errorCodeExConstructor, socketExConstructor,socketExCauseMethod;
1623 jobject errorCodeEx, socketEx;
1624 const char* errorMessage = netLookupErrorString(err);
1625 jstring errorMessageString = env->NewStringUTF(errorMessage);
1627 errorCodeExClass = env->FindClass("org/apache/harmony/luni/util/ErrorCodeException");
1628 if (!errorCodeExClass){
1631 errorCodeExConstructor = env->GetMethodID(errorCodeExClass,"<init>","(I)V");
1632 if (!errorCodeExConstructor){
1635 errorCodeEx = env->NewObject(errorCodeExClass,errorCodeExConstructor,err);
1637 socketExClass = env->FindClass("java/net/SocketException");
1638 if (!socketExClass) {
1641 socketExConstructor = env->GetMethodID(socketExClass,"<init>","(Ljava/lang/String;)V");
1642 if (!socketExConstructor) {
1645 socketEx = env->NewObject(socketExClass, socketExConstructor, errorMessageString);
1646 socketExCauseMethod = env->GetMethodID(socketExClass,"initCause","(Ljava/lang/Throwable;)Ljava/lang/Throwable;");
1647 env->CallObjectMethod(socketEx,socketExCauseMethod,errorCodeEx);
1648 env->Throw((jthrowable)socketEx);
1651 throwSocketException(env, err);
1658 static jint osNetworkSystem_writeSocketImpl(JNIEnv* env, jclass clazz,
1659 jobject fileDescriptor, jbyteArray data, jint offset, jint count) {
1660 // LOGD("ENTER writeSocketImpl");
1666 /* TODO: ARRAY PINNING */
1667 #define INTERNAL_SEND_BUFFER_MAX 512
1668 jbyte internalBuffer[INTERNAL_SEND_BUFFER_MAX];
1670 if (count > INTERNAL_SEND_BUFFER_MAX) {
1671 message = (jbyte*)malloc(count * sizeof( jbyte));
1672 if (message == NULL) {
1673 jniThrowException(env, "java/lang/OutOfMemoryError",
1674 "couldn't allocate enough memory for writeSocket");
1678 message = (jbyte *)internalBuffer;
1681 env->GetByteArrayRegion(data, offset, count, message);
1683 result = osNetworkSystem_writeSocketDirectImpl(env, clazz, fileDescriptor,
1684 (jint) message, 0, count);
1686 if (( jbyte *)message != internalBuffer) {
1687 free(( jbyte *)message);
1689 #undef INTERNAL_SEND_BUFFER_MAX
1693 static void osNetworkSystem_setNonBlockingImpl(JNIEnv* env, jclass clazz,
1694 jobject fileDescriptor, jboolean nonblocking) {
1695 // LOGD("ENTER setNonBlockingImpl");
1700 handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
1702 if (handle == 0 || handle == -1) {
1703 throwSocketException(env, SOCKERR_BADSOCKET);
1707 int block = nonblocking;
1709 result = ioctl(handle, FIONBIO, &block);
1712 throwSocketException(env, convertError(errno));
1716 static jint osNetworkSystem_connectSocketImpl(JNIEnv* env, jclass clazz,
1717 jobject fileDescriptor, jint trafficClass, jobject inetAddr, jint port);
1719 static jint osNetworkSystem_connectWithTimeoutSocketImpl(JNIEnv* env,
1720 jclass clazz, jobject fileDescriptor, jint timeout, jint trafficClass,
1721 jobject inetAddr, jint port, jint step, jbyteArray passContext) {
1722 // LOGD("ENTER connectWithTimeoutSocketImpl");
1726 struct sockaddr_storage address;
1727 jbyte *context = NULL;
1729 result = inetAddressToSocketAddress(env, inetAddr, port, &address);
1733 // Check if we're using adb networking and redirect in case it is used.
1734 if (useAdbNetworkingForAddress(&address)) {
1735 return osNetworkSystem_connectSocketImpl(env, clazz, fileDescriptor,
1736 trafficClass, inetAddr, port);
1739 handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
1740 if (handle == 0 || handle == -1) {
1741 throwSocketException(env, SOCKERR_BADDESC);
1745 context = (jbyte *)env->GetPrimitiveArrayCritical(passContext, NULL);
1748 case SOCKET_CONNECT_STEP_START:
1749 result = sockConnectWithTimeout(handle, address, 0,
1750 SOCKET_STEP_START, context);
1752 case SOCKET_CONNECT_STEP_CHECK:
1753 result = sockConnectWithTimeout(handle, address, timeout,
1754 SOCKET_STEP_CHECK, context);
1758 env->ReleasePrimitiveArrayCritical(passContext, context, JNI_ABORT);
1761 /* connected , so stop here */
1762 sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_DONE, NULL);
1763 } else if (result != SOCKERR_NOTCONNECTED) {
1764 /* can not connect... */
1765 sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_DONE, NULL);
1766 if (result == SOCKERR_EACCES) {
1767 jniThrowException(env, "java/lang/SecurityException",
1768 netLookupErrorString(result));
1770 jniThrowException(env, "java/net/ConnectException",
1771 netLookupErrorString(result));
1778 static void osNetworkSystem_connectStreamWithTimeoutSocketImpl(JNIEnv* env,
1779 jclass clazz, jobject fileDescriptor, jint remotePort, jint timeout,
1780 jint trafficClass, jobject inetAddr) {
1781 // LOGD("ENTER connectStreamWithTimeoutSocketImpl");
1785 struct sockaddr_storage address;
1786 jbyte *context = NULL;
1787 int remainingTimeout = timeout;
1788 int passedTimeout = 0;
1791 char hasTimeout = timeout > 0;
1793 /* if a timeout was specified calculate the finish time value */
1795 finishTime = time_msec_clock() + (int) timeout;
1798 handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
1799 if (handle == 0 || handle == -1) {
1800 throwSocketException(env, SOCKERR_BADDESC);
1804 result = inetAddressToSocketAddress(env, inetAddr, remotePort, &address);
1805 if (result < 0) // Exception has already been thrown.
1808 // Check if we're using adb networking and redirect in case it is used.
1809 if (useAdbNetworkingForAddress(&address)) {
1810 int retVal = osNetworkSystem_connectSocketImpl(env, clazz,
1811 fileDescriptor, trafficClass, inetAddr, remotePort);
1813 throwSocketException(env, SOCKERR_BADSOCKET);
1819 * we will be looping checking for when we are connected so allocate
1820 * the descriptor sets that we will use
1822 context =(jbyte *) malloc(sizeof(struct selectFDSet));
1823 if (NULL == context) {
1824 throwSocketException(env, SOCKERR_NOBUFFERS);
1828 result = sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_START, context);
1830 /* ok we connected right away so we are done */
1831 sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_DONE, context);
1833 } else if (result != SOCKERR_NOTCONNECTED) {
1834 sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_DONE,
1836 /* we got an error other than NOTCONNECTED so we cannot continue */
1837 if (SOCKERR_EACCES == result) {
1838 jniThrowException(env, "java/lang/SecurityException",
1839 netLookupErrorString(result));
1841 throwSocketException(env, result);
1846 while (SOCKERR_NOTCONNECTED == result) {
1847 passedTimeout = remainingTimeout;
1850 * ok now try and connect. Depending on the platform this may sleep
1851 * for up to passedTimeout milliseconds
1853 result = sockConnectWithTimeout(handle, address, passedTimeout,
1854 SOCKET_STEP_CHECK, context);
1857 * now check if the socket is still connected.
1858 * Do it here as some platforms seem to think they
1859 * are connected if the socket is closed on them.
1861 handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
1862 if (handle == 0 || handle == -1) {
1863 sockConnectWithTimeout(handle, address, 0,
1864 SOCKET_STEP_DONE, context);
1865 throwSocketException(env, SOCKERR_BADSOCKET);
1870 * check if we are now connected,
1871 * if so we can finish the process and return
1874 sockConnectWithTimeout(handle, address, 0,
1875 SOCKET_STEP_DONE, context);
1880 * if the error is SOCKERR_NOTCONNECTED then we have not yet
1881 * connected and we may not be done yet
1883 if (SOCKERR_NOTCONNECTED == result) {
1884 /* check if the timeout has expired */
1886 remainingTimeout = finishTime - time_msec_clock();
1887 if (remainingTimeout <= 0) {
1888 sockConnectWithTimeout(handle, address, 0,
1889 SOCKET_STEP_DONE, context);
1890 jniThrowException(env,
1891 "java/net/SocketTimeoutException",
1892 netLookupErrorString(result));
1896 remainingTimeout = 100;
1899 sockConnectWithTimeout(handle, address, remainingTimeout,
1900 SOCKET_STEP_DONE, context);
1901 if ((SOCKERR_CONNRESET == result) ||
1902 (SOCKERR_CONNECTION_REFUSED == result) ||
1903 (SOCKERR_ADDRNOTAVAIL == result) ||
1904 (SOCKERR_ADDRINUSE == result) ||
1905 (SOCKERR_ENETUNREACH == result)) {
1906 jniThrowException(env, "java/net/ConnectException",
1907 netLookupErrorString(result));
1908 } else if (SOCKERR_EACCES == result) {
1909 jniThrowException(env, "java/lang/SecurityException",
1910 netLookupErrorString(result));
1912 throwSocketException(env, result);
1920 /* free the memory for the FD set */
1921 if (context != NULL) {
1926 static jint osNetworkSystem_connectSocketImpl(JNIEnv* env, jclass clazz,
1927 jobject fileDescriptor, jint trafficClass, jobject inetAddr, jint port) {
1928 //LOGD("ENTER direct-call connectSocketImpl\n");
1930 struct sockaddr_storage address;
1934 ret = inetAddressToSocketAddress(env, inetAddr, port, &address);
1938 handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
1939 if (handle == 0 || handle == -1) {
1940 throwSocketException(env, SOCKERR_BADDESC);
1944 if (useAdbNetworkingForAddress(&address)) {
1946 // LOGD("+connect to address 0x%08x port %d (via adb)",
1947 // address.sin_addr.s_addr, (int) port);
1948 ret = adb_networking_connect_fd(handle, (struct sockaddr_in *) &address);
1949 // LOGD("-connect ret %d errno %d (via adb)", ret, errno);
1953 // call this method with a timeout of zero
1954 osNetworkSystem_connectStreamWithTimeoutSocketImpl(env, clazz,
1955 fileDescriptor, port, 0, trafficClass, inetAddr);
1956 if (env->ExceptionOccurred() != 0) {
1965 jniThrowException(env, "java/net/ConnectException",
1966 netLookupErrorString(convertError(errno)));
1973 static void osNetworkSystem_socketBindImpl(JNIEnv* env, jclass clazz,
1974 jobject fileDescriptor, jint port, jobject inetAddress) {
1975 // LOGD("ENTER socketBindImpl");
1977 struct sockaddr_storage sockaddress;
1981 ret = inetAddressToSocketAddress(env, inetAddress, port, &sockaddress);
1985 handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
1986 if (handle == 0 || handle == -1) {
1987 throwSocketException(env, SOCKERR_BADDESC);
1991 ret = doBind(handle, &sockaddress);
1993 jniThrowException(env, "java/net/BindException",
1994 netLookupErrorString(convertError(errno)));
1999 static void osNetworkSystem_listenStreamSocketImpl(JNIEnv* env, jclass clazz,
2000 jobject fileDescriptor, jint backlog) {
2001 // LOGD("ENTER listenStreamSocketImpl");
2006 handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
2008 if (handle == 0 || handle == -1) {
2009 throwSocketException(env, SOCKERR_BADSOCKET);
2013 ret = listen(handle, backlog);
2016 int err = convertError(errno);
2017 throwSocketException(env, err);
2022 static jint osNetworkSystem_availableStreamImpl(JNIEnv* env, jclass clazz,
2023 jobject fileDescriptor) {
2024 // LOGD("ENTER availableStreamImpl");
2027 char message[BUFFERSIZE];
2031 handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
2032 if (handle == 0 || handle == -1) {
2033 throwSocketException(env, SOCKERR_BADDESC);
2038 result = selectWait(handle, 1, SELECT_READ_TYPE);
2040 if (SOCKERR_TIMEOUT == result) {
2041 // The read operation timed out, so answer 0 bytes available
2043 } else if (SOCKERR_INTERRUPTED == result) {
2045 } else if (0 > result) {
2046 throwSocketException(env, result);
2049 } while (SOCKERR_INTERRUPTED == result);
2051 result = recv(handle, (jbyte *) message, BUFFERSIZE, MSG_PEEK);
2054 int err = convertError(errno);
2055 throwSocketException(env, err);
2061 static void osNetworkSystem_acceptSocketImpl(JNIEnv* env, jclass clazz,
2062 jobject fdServer, jobject newSocket, jobject fdnewSocket, jint timeout) {
2063 // LOGD("ENTER acceptSocketImpl");
2065 struct sockaddr_storage sa;
2073 if (newSocket == NULL) {
2074 throwNullPointerException(env);
2078 result = pollSelectWait(env, fdServer, timeout, SELECT_READ_TYPE);
2083 handle = jniGetFDFromFileDescriptor(env, fdServer);
2084 if (handle == 0 || handle == -1) {
2085 throwSocketException(env, SOCKERR_BADDESC);
2090 addrlen = sizeof(sa);
2091 ret = accept(handle, (struct sockaddr *) &sa, &addrlen);
2092 } while (ret < 0 && errno == EINTR);
2095 int err = convertError(errno);
2096 throwSocketException(env, err);
2103 * For network sockets, put the peer address and port in instance variables.
2104 * We don't bother to do this for UNIX domain sockets, since most peers are
2107 if (sa.ss_family == AF_INET || sa.ss_family == AF_INET6) {
2108 jobject inetAddress = socketAddressToInetAddress(env, &sa);
2111 newSocket = NULL; // Exception has already been thrown.
2115 env->SetObjectField(newSocket,
2116 gCachedFields.socketimpl_address, inetAddress);
2118 int port = getSocketAddressPort(&sa);
2119 env->SetIntField(newSocket, gCachedFields.socketimpl_port, port);
2122 jniSetFileDescriptorOfFD(env, fdnewSocket, retFD);
2125 static jboolean osNetworkSystem_supportsUrgentDataImpl(JNIEnv* env,
2126 jclass clazz, jobject fileDescriptor) {
2127 // LOGD("ENTER supportsUrgentDataImpl");
2131 handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
2132 if (handle == 0 || handle == -1) {
2139 static void osNetworkSystem_sendUrgentDataImpl(JNIEnv* env, jclass clazz,
2140 jobject fileDescriptor, jbyte value) {
2141 // LOGD("ENTER sendUrgentDataImpl");
2146 handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
2147 if (handle == 0 || handle == -1) {
2148 throwSocketException(env, SOCKERR_BADSOCKET);
2152 result = send(handle, (jbyte *) &value, 1, MSG_OOB);
2154 int err = convertError(errno);
2155 throwSocketException(env, err);
2159 static void osNetworkSystem_connectDatagramImpl2(JNIEnv* env, jclass clazz,
2160 jobject fd, jint port, jint trafficClass, jobject inetAddress) {
2161 // LOGD("ENTER connectDatagramImpl2");
2163 int handle = jniGetFDFromFileDescriptor(env, fd);
2165 struct sockaddr_storage sockAddr;
2168 ret = inetAddressToSocketAddress(env, inetAddress, port, &sockAddr);
2169 if (ret < 0) // Exception has already been thrown.
2172 ret = doConnect(handle, &sockAddr);
2174 int err = convertError(errno);
2175 throwSocketException(env, err);
2179 static void osNetworkSystem_disconnectDatagramImpl(JNIEnv* env, jclass clazz,
2181 // LOGD("ENTER disconnectDatagramImpl");
2183 int handle = jniGetFDFromFileDescriptor(env, fd);
2185 struct sockaddr_storage sockAddr;
2186 memset(&sockAddr, 0, sizeof(sockAddr));
2187 sockAddr.ss_family = AF_UNSPEC;
2189 int result = doConnect(handle, &sockAddr);
2191 int err = convertError(errno);
2192 throwSocketException(env, err);
2196 static jint osNetworkSystem_peekDatagramImpl(JNIEnv* env, jclass clazz,
2197 jobject fd, jobject sender, jint receiveTimeout) {
2198 // LOGD("ENTER peekDatagramImpl");
2202 int result = pollSelectWait (env, fd, receiveTimeout, SELECT_READ_TYPE);
2207 int handle = jniGetFDFromFileDescriptor(env, fd);
2208 if (handle == 0 || handle == -1) {
2209 throwSocketException(env, SOCKERR_BADDESC);
2213 struct sockaddr_storage sockAddr;
2214 socklen_t sockAddrLen = sizeof(sockAddr);
2217 length = recvfrom(handle, NULL, 0, MSG_PEEK,
2218 (struct sockaddr *)&sockAddr, &sockAddrLen);
2219 } while (length < 0 && errno == EINTR);
2221 int err = convertError(errno);
2222 throwSocketException(env, err);
2226 sender = socketAddressToInetAddress(env, &sockAddr);
2227 if (sender == NULL) // Exception has already been thrown.
2230 port = getSocketAddressPort(&sockAddr);
2234 static jint osNetworkSystem_receiveDatagramDirectImpl(JNIEnv* env, jclass clazz,
2235 jobject fd, jobject packet, jint address, jint offset, jint length,
2236 jint receiveTimeout, jboolean peek) {
2237 // LOGD("ENTER receiveDatagramDirectImpl");
2239 int result = pollSelectWait (env, fd, receiveTimeout, SELECT_READ_TYPE);
2244 int handle = jniGetFDFromFileDescriptor(env, fd);
2245 if (handle == 0 || handle == -1) {
2246 throwSocketException(env, SOCKERR_BADDESC);
2250 struct sockaddr_storage sockAddr;
2251 socklen_t sockAddrLen = sizeof(sockAddr);
2253 int mode = peek ? MSG_PEEK : 0;
2255 ssize_t actualLength;
2257 actualLength = recvfrom(handle, (char*)(address + offset), length, mode,
2258 (struct sockaddr *)&sockAddr, &sockAddrLen);
2259 } while (actualLength < 0 && errno == EINTR);
2260 if (actualLength < 0) {
2261 int err = convertError(errno);
2262 throwSocketException(env, err);
2266 if (packet != NULL) {
2267 jbyteArray addr = socketAddressToAddressBytes(env, &sockAddr);
2268 if (addr == NULL) // Exception has already been thrown.
2270 int port = getSocketAddressPort(&sockAddr);
2271 jobject sender = env->CallStaticObjectMethod(
2272 gCachedFields.iaddr_class, gCachedFields.iaddr_getbyaddress,
2274 env->SetObjectField(packet, gCachedFields.dpack_address, sender);
2275 env->SetIntField(packet, gCachedFields.dpack_port, port);
2276 env->SetIntField(packet, gCachedFields.dpack_length,
2277 (jint) actualLength);
2279 return (jint) actualLength;
2282 static jint osNetworkSystem_receiveDatagramImpl(JNIEnv* env, jclass clazz,
2283 jobject fd, jobject packet, jbyteArray data, jint offset, jint length,
2284 jint receiveTimeout, jboolean peek) {
2285 // LOGD("ENTER receiveDatagramImpl");
2287 int localLength = (length < 65536) ? length : 65536;
2288 jbyte *bytes = (jbyte*) malloc(localLength);
2289 if (bytes == NULL) {
2290 jniThrowException(env, "java/lang/OutOfMemoryError",
2291 "couldn't allocate enough memory for receiveDatagram");
2295 int actualLength = osNetworkSystem_receiveDatagramDirectImpl(env, clazz, fd,
2296 packet, (jint)bytes, 0, localLength, receiveTimeout, peek);
2298 if (actualLength > 0) {
2299 env->SetByteArrayRegion(data, offset, actualLength, bytes);
2303 return actualLength;
2306 static jint osNetworkSystem_recvConnectedDatagramDirectImpl(JNIEnv* env,
2307 jclass clazz, jobject fd, jobject packet, jint address, jint offset,
2308 jint length, jint receiveTimeout, jboolean peek) {
2309 // LOGD("ENTER receiveConnectedDatagramDirectImpl");
2311 int result = pollSelectWait (env, fd, receiveTimeout, SELECT_READ_TYPE);
2317 int handle = jniGetFDFromFileDescriptor(env, fd);
2319 if (handle == 0 || handle == -1) {
2320 throwSocketException(env, SOCKERR_BADSOCKET);
2324 int mode = peek ? MSG_PEEK : 0;
2326 int actualLength = recvfrom(handle,
2327 (char*)(address + offset), length, mode, NULL, NULL);
2329 if (actualLength < 0) {
2330 jniThrowException(env, "java/net/PortUnreachableException", "");
2334 if ( packet != NULL) {
2335 env->SetIntField(packet, gCachedFields.dpack_length, actualLength);
2337 return actualLength;
2340 static jint osNetworkSystem_recvConnectedDatagramImpl(JNIEnv* env, jclass clazz,
2341 jobject fd, jobject packet, jbyteArray data, jint offset, jint length,
2342 jint receiveTimeout, jboolean peek) {
2343 // LOGD("ENTER receiveConnectedDatagramImpl");
2345 int localLength = (length < 65536) ? length : 65536;
2346 jbyte *bytes = (jbyte*) malloc(localLength);
2347 if (bytes == NULL) {
2348 jniThrowException(env, "java/lang/OutOfMemoryError",
2349 "couldn't allocate enough memory for recvConnectedDatagram");
2353 int actualLength = osNetworkSystem_recvConnectedDatagramDirectImpl(env,
2354 clazz, fd, packet, (jint)bytes, 0, localLength,
2355 receiveTimeout, peek);
2357 if (actualLength > 0) {
2358 env->SetByteArrayRegion(data, offset, actualLength, bytes);
2362 return actualLength;
2365 static jint osNetworkSystem_sendDatagramDirectImpl(JNIEnv* env, jclass clazz,
2366 jobject fd, jint address, jint offset, jint length, jint port,
2367 jboolean bindToDevice, jint trafficClass, jobject inetAddress) {
2368 // LOGD("ENTER sendDatagramDirectImpl");
2370 int handle = jniGetFDFromFileDescriptor(env, fd);
2372 if (handle == 0 || handle == -1) {
2373 throwSocketException(env, SOCKERR_BADSOCKET);
2377 struct sockaddr_storage receiver;
2378 if (inetAddressToSocketAddress(env, inetAddress, port, &receiver) < 0) {
2379 // Exception has already been thrown.
2385 result = sendto(handle, (char*)(address + offset), length,
2386 SOCKET_NOFLAGS, (struct sockaddr*)&receiver, sizeof(receiver));
2387 } while (result < 0 && errno == EINTR);
2389 int err = convertError(errno);
2390 if ((SOCKERR_CONNRESET == err)
2391 || (SOCKERR_CONNECTION_REFUSED == err)) {
2394 throwSocketException(env, err);
2398 return (jint) result;
2401 static jint osNetworkSystem_sendDatagramImpl(JNIEnv* env, jclass clazz,
2402 jobject fd, jbyteArray data, jint offset, jint length, jint port,
2403 jboolean bindToDevice, jint trafficClass, jobject inetAddress) {
2404 // LOGD("ENTER sendDatagramImpl");
2406 jbyte *bytes = env->GetByteArrayElements(data, NULL);
2407 int actualLength = osNetworkSystem_sendDatagramDirectImpl(env, clazz, fd,
2408 (jint)bytes, offset, length, port, bindToDevice, trafficClass,
2410 env->ReleaseByteArrayElements(data, bytes, JNI_ABORT);
2412 return actualLength;
2415 static jint osNetworkSystem_sendConnectedDatagramDirectImpl(JNIEnv* env,
2416 jclass clazz, jobject fd, jint address, jint offset, jint length,
2417 jboolean bindToDevice) {
2418 // LOGD("ENTER sendConnectedDatagramDirectImpl");
2420 int handle = jniGetFDFromFileDescriptor(env, fd);
2422 if (handle == 0 || handle == -1) {
2423 throwSocketException(env, SOCKERR_BADSOCKET);
2427 int result = send(handle, (char*)(address + offset), length, 0);
2430 int err = convertError(errno);
2431 if ((SOCKERR_CONNRESET == err) || (SOCKERR_CONNECTION_REFUSED == err)) {
2434 throwSocketException(env, err);
2441 static jint osNetworkSystem_sendConnectedDatagramImpl(JNIEnv* env, jclass clazz,
2442 jobject fd, jbyteArray data, jint offset, jint length,
2443 jboolean bindToDevice) {
2444 // LOGD("ENTER sendConnectedDatagramImpl");
2446 jbyte *bytes = env->GetByteArrayElements(data, NULL);
2447 int actualLength = osNetworkSystem_sendConnectedDatagramDirectImpl(env,
2448 clazz, fd, (jint)bytes, offset, length, bindToDevice);
2449 env->ReleaseByteArrayElements(data, bytes, JNI_ABORT);
2451 return actualLength;
2454 static void osNetworkSystem_createServerStreamSocketImpl(JNIEnv* env,
2455 jclass clazz, jobject fileDescriptor, jboolean preferIPv4Stack) {
2456 // LOGD("ENTER createServerStreamSocketImpl");
2458 int handle = createSocketFileDescriptor(env, fileDescriptor, SOCK_STREAM);
2463 setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(int));
2467 * @param timeout in milliseconds. If zero, block until data received
2469 static jint osNetworkSystem_receiveStreamImpl(JNIEnv* env, jclass clazz,
2470 jobject fileDescriptor, jbyteArray data, jint offset, jint count,
2472 // LOGD("ENTER receiveStreamImpl");
2475 int handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
2477 if (handle == 0 || handle == -1) {
2478 throwSocketException(env, SOCKERR_BADSOCKET);
2482 // Cap read length to available buf size
2483 int spaceAvailable = env->GetArrayLength(data) - offset;
2484 int localCount = count < spaceAvailable? count : spaceAvailable;
2487 jbyte *body = env->GetByteArrayElements(data, &isCopy);
2491 tv.tv_sec = timeout / 1000;
2492 tv.tv_usec = (timeout % 1000) * 1000;
2493 setsockopt(handle, SOL_SOCKET, SO_RCVTIMEO, (struct timeval *)&tv,
2494 sizeof(struct timeval));
2497 result = recv(handle, body + offset, localCount, SOCKET_NOFLAGS);
2498 } while (result < 0 && errno == EINTR);
2500 env->ReleaseByteArrayElements(data, body, 0);
2503 * If no bytes are read, return -1 to signal 'endOfFile'
2504 * to the Java input stream
2508 } else if (0 == result) {
2511 // If EAGAIN or EWOULDBLOCK, read timed out
2512 if (errno == EAGAIN || errno == EWOULDBLOCK) {
2513 jniThrowException(env, "java/net/SocketTimeoutException",
2514 netLookupErrorString(SOCKERR_TIMEOUT));
2516 int err = convertError(errno);
2517 throwSocketException(env, err);
2523 static jint osNetworkSystem_sendStreamImpl(JNIEnv* env, jclass clazz,
2524 jobject fileDescriptor, jbyteArray data, jint offset, jint count) {
2525 // LOGD("ENTER sendStreamImpl");
2528 int result = 0, sent = 0;
2531 jbyte *message = env->GetByteArrayElements(data, &isCopy);
2533 // Cap write length to available buf size
2534 int spaceAvailable = env->GetArrayLength(data) - offset;
2535 if (count > spaceAvailable) count = spaceAvailable;
2537 while (sent < count) {
2539 handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
2540 if (handle == 0 || handle == -1) {
2541 throwSocketException(env,
2542 sent == 0 ? SOCKERR_BADSOCKET : SOCKERR_INTERRUPTED);
2543 env->ReleaseByteArrayElements(data, message, 0);
2547 // LOGD("before select %d", count);
2548 selectWait(handle, SEND_RETRY_TIME, SELECT_WRITE_TYPE);
2549 result = send(handle, (jbyte *)message + offset + sent,
2550 (int) count - sent, SOCKET_NOFLAGS);
2554 if (result == EAGAIN ||result == EWOULDBLOCK) {
2555 // LOGD("write blocked %d", sent);
2558 env->ReleaseByteArrayElements(data, message, 0);
2559 int err = convertError(result);
2560 throwSocketException(env, err);
2566 env->ReleaseByteArrayElements(data, message, 0);
2570 static void osNetworkSystem_shutdownInputImpl(JNIEnv* env, jobject obj,
2571 jobject fileDescriptor) {
2572 // LOGD("ENTER shutdownInputImpl");
2577 handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
2579 if (handle == 0 || handle == -1) {
2580 throwSocketException(env, SOCKERR_BADSOCKET);
2584 ret = shutdown(handle, SHUT_RD);
2587 int err = convertError(errno);
2588 throwSocketException(env, err);
2593 static void osNetworkSystem_shutdownOutputImpl(JNIEnv* env, jobject obj,
2594 jobject fileDescriptor) {
2595 // LOGD("ENTER shutdownOutputImpl");
2600 handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
2602 if (handle == 0 || handle == -1) {
2606 ret = shutdown(handle, SHUT_WR);
2609 int err = convertError(errno);
2610 throwSocketException(env, err);
2615 static jint osNetworkSystem_sendDatagramImpl2(JNIEnv* env, jclass clazz,
2616 jobject fd, jbyteArray data, jint offset, jint length, jint port,
2617 jobject inetAddress) {
2618 // LOGD("ENTER sendDatagramImpl2");
2621 unsigned short nPort;
2622 int ret = 0, sent = 0;
2624 struct sockaddr_storage sockaddrP;
2626 if (inetAddress != NULL) {
2627 ret = inetAddressToSocketAddress(env, inetAddress, port, &sockaddrP);
2628 if (ret < 0) // Exception has already been thrown.
2631 handle = jniGetFDFromFileDescriptor(env, fd);
2632 if (handle == 0 || handle == -1) {
2633 throwSocketException(env, SOCKERR_BADDESC);
2638 message = (jbyte*) malloc(length * sizeof(jbyte));
2639 if (message == NULL) {
2640 jniThrowException(env, "java/lang/OutOfMemoryError",
2641 "couldn't allocate enough memory for readSocket");
2645 env->GetByteArrayRegion(data, offset, length, message);
2647 while (sent < length) {
2648 handle = jniGetFDFromFileDescriptor(env, fd);
2650 if (handle == 0 || handle == -1) {
2651 throwSocketException(env,
2652 sent == 0 ? SOCKERR_BADDESC : SOCKERR_INTERRUPTED);
2659 result = sendto(handle, (char *) (message + sent),
2660 (int) (length - sent), SOCKET_NOFLAGS,
2661 (struct sockaddr *) &sockaddrP, sizeof(sockaddrP));
2662 } while (result < 0 && errno == EINTR);
2664 int err = convertError(errno);
2665 throwSocketException(env, err);
2677 static jint osNetworkSystem_selectImpl(JNIEnv* env, jclass clazz,
2678 jobjectArray readFDArray, jobjectArray writeFDArray, jint countReadC,
2679 jint countWriteC, jintArray outFlags, jlong timeout) {
2680 // LOGD("ENTER selectImpl");
2682 struct timeval timeP;
2686 fd_set *fdset_read,*fdset_write;
2691 unsigned int time_sec = (unsigned int)timeout/1000;
2692 unsigned int time_msec = (unsigned int)(timeout%1000);
2694 fdset_read = (fd_set *)malloc(sizeof(fd_set));
2695 fdset_write = (fd_set *)malloc(sizeof(fd_set));
2697 FD_ZERO(fdset_read);
2698 FD_ZERO(fdset_write);
2700 for (val = 0; val<countReadC; val++) {
2702 gotFD = env->GetObjectArrayElement(readFDArray,val);
2704 handle = jniGetFDFromFileDescriptor(env, gotFD);
2706 FD_SET(handle, fdset_read);
2708 if (0 > (size - handle)) {
2713 for (val = 0; val<countWriteC; val++) {
2715 gotFD = env->GetObjectArrayElement(writeFDArray,val);
2717 handle = jniGetFDFromFileDescriptor(env, gotFD);
2719 FD_SET(handle, fdset_write);
2721 if (0 > (size - handle)) {
2726 /* the size is the max_fd + 1 */
2730 result = SOCKERR_FDSET_SIZEBAD;
2732 /* only set when timeout >= 0 (non-block)*/
2735 timeP.tv_sec = time_sec;
2736 timeP.tv_usec = time_msec*1000;
2738 result = sockSelect(size, fdset_read, fdset_write, NULL, &timeP);
2741 result = sockSelect(size, fdset_read, fdset_write, NULL, NULL);
2746 /*output the result to a int array*/
2747 flagArray = env->GetIntArrayElements(outFlags, &isCopy);
2749 for (val=0; val<countReadC; val++) {
2750 gotFD = env->GetObjectArrayElement(readFDArray,val);
2752 handle = jniGetFDFromFileDescriptor(env, gotFD);
2754 if (FD_ISSET(handle,fdset_read)) {
2755 flagArray[val] = SOCKET_OP_READ;
2757 flagArray[val] = SOCKET_OP_NONE;
2761 for (val=0; val<countWriteC; val++) {
2763 gotFD = env->GetObjectArrayElement(writeFDArray,val);
2765 handle = jniGetFDFromFileDescriptor(env, gotFD);
2767 if (FD_ISSET(handle,fdset_write)) {
2768 flagArray[val+countReadC] = SOCKET_OP_WRITE;
2770 flagArray[val+countReadC] = SOCKET_OP_NONE;
2774 env->ReleaseIntArrayElements(outFlags, flagArray, 0);
2780 /* return both correct and error result, let java handle the exception*/
2784 static jobject osNetworkSystem_getSocketLocalAddressImpl(JNIEnv* env,
2785 jclass clazz, jobject fileDescriptor, jboolean preferIPv6Addresses) {
2786 // LOGD("ENTER getSocketLocalAddressImpl");
2788 struct sockaddr_storage addr;
2789 socklen_t addrLen = sizeof(addr);
2791 memset(&addr, 0, addrLen);
2794 int handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
2795 if (handle == 0 || handle == -1) {
2796 throwSocketException(env, SOCKERR_UNKNOWNSOCKET);
2801 result = getsockname(handle, (struct sockaddr *)&addr, &addrLen);
2803 // Spec says ignore all errors
2804 return socketAddressToInetAddress(env, &addr);
2807 static jint osNetworkSystem_getSocketLocalPortImpl(JNIEnv* env, jclass clazz,
2808 jobject fileDescriptor, jboolean preferIPv6Addresses) {
2809 // LOGD("ENTER getSocketLocalPortImpl");
2811 struct sockaddr_storage addr;
2812 socklen_t addrLen = sizeof(addr);
2814 int handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
2817 if (handle == 0 || handle == -1) {
2818 throwSocketException(env, SOCKERR_UNKNOWNSOCKET);
2822 result = getsockname(handle, (struct sockaddr *)&addr, &addrLen);
2825 // The java spec does not indicate any exceptions on this call
2828 return getSocketAddressPort(&addr);
2832 static jobject osNetworkSystem_getSocketOptionImpl(JNIEnv* env, jclass clazz,
2833 jobject fileDescriptor, jint anOption) {
2834 // LOGD("ENTER getSocketOptionImpl");
2838 socklen_t intSize = sizeof(int);
2839 unsigned char byteValue = 0;
2840 socklen_t byteSize = sizeof(unsigned char);
2842 struct sockaddr_storage sockVal;
2843 socklen_t sockSize = sizeof(sockVal);
2845 handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
2846 if (handle == 0 || handle == -1) {
2847 throwSocketException(env, SOCKERR_BADDESC);
2851 switch ((int) anOption & 0xffff) {
2852 case JAVASOCKOPT_SO_LINGER: {
2853 struct linger lingr;
2854 socklen_t size = sizeof(struct linger);
2855 result = getsockopt(handle, SOL_SOCKET, SO_LINGER, &lingr, &size);
2857 throwSocketException(env, convertError(errno));
2860 if (!lingr.l_onoff) {
2863 intValue = lingr.l_linger;
2865 return newJavaLangInteger(env, intValue);
2867 case JAVASOCKOPT_TCP_NODELAY: {
2868 if ((anOption >> 16) & BROKEN_TCP_NODELAY) {
2871 result = getsockopt(handle, IPPROTO_TCP, TCP_NODELAY, &intValue, &intSize);
2873 throwSocketException(env, convertError(errno));
2876 return newJavaLangBoolean(env, intValue);
2878 case JAVASOCKOPT_MCAST_TTL: {
2879 if ((anOption >> 16) & BROKEN_MULTICAST_TTL) {
2880 return newJavaLangByte(env, 0);
2882 result = getOrSetSocketOption(SOCKOPT_GET, handle, IP_MULTICAST_TTL,
2883 IPV6_MULTICAST_HOPS, &byteValue,
2886 throwSocketException(env, convertError(errno));
2889 return newJavaLangByte(env, (jbyte)(byteValue & 0xFF));
2891 case JAVASOCKOPT_MCAST_INTERFACE: {
2892 if ((anOption >> 16) & BROKEN_MULTICAST_IF) {
2895 result = getsockopt(handle, IPPROTO_IP, IP_MULTICAST_IF, &sockVal, &sockSize);
2897 throwSocketException(env, convertError(errno));
2900 // This option is IPv4-only.
2901 sockVal.ss_family = AF_INET;
2902 return socketAddressToInetAddress(env, &sockVal);
2904 case JAVASOCKOPT_IP_MULTICAST_IF2: {
2905 if ((anOption >> 16) & BROKEN_MULTICAST_IF) {
2908 struct ip_mreqn multicastRequest;
2910 socklen_t optionLength;
2911 int addressFamily = getSocketAddressFamily(handle);
2912 switch (addressFamily) {
2914 optionLength = sizeof(multicastRequest);
2915 result = getsockopt(handle, IPPROTO_IP, IP_MULTICAST_IF,
2916 &multicastRequest, &optionLength);
2918 interfaceIndex = multicastRequest.imr_ifindex;
2921 optionLength = sizeof(interfaceIndex);
2922 result = getsockopt(handle, IPPROTO_IPV6, IPV6_MULTICAST_IF,
2923 &interfaceIndex, &optionLength);
2926 throwSocketException(env, SOCKERR_BADAF);
2931 throwSocketException(env, convertError(errno));
2935 return newJavaLangInteger(env, interfaceIndex);
2937 case JAVASOCKOPT_SO_SNDBUF: {
2938 result = getsockopt(handle, SOL_SOCKET, SO_SNDBUF, &intValue, &intSize);
2940 throwSocketException(env, convertError(errno));
2943 return newJavaLangInteger(env, intValue);
2945 case JAVASOCKOPT_SO_RCVBUF: {
2946 result = getsockopt(handle, SOL_SOCKET, SO_RCVBUF, &intValue, &intSize);
2948 throwSocketException(env, convertError(errno));
2951 return newJavaLangInteger(env, intValue);
2953 case JAVASOCKOPT_SO_BROADCAST: {
2954 result = getsockopt(handle, SOL_SOCKET, SO_BROADCAST, &intValue, &intSize);
2956 throwSocketException(env, convertError(errno));
2959 return newJavaLangBoolean(env, intValue);
2961 case JAVASOCKOPT_SO_REUSEADDR: {
2962 result = getsockopt(handle, SOL_SOCKET, SO_REUSEADDR, &intValue, &intSize);
2964 throwSocketException(env, convertError(errno));
2967 return newJavaLangBoolean(env, intValue);
2969 case JAVASOCKOPT_SO_KEEPALIVE: {
2970 result = getsockopt(handle, SOL_SOCKET, SO_KEEPALIVE, &intValue, &intSize);
2972 throwSocketException(env, convertError(errno));
2975 return newJavaLangBoolean(env, intValue);
2977 case JAVASOCKOPT_SO_OOBINLINE: {
2978 result = getsockopt(handle, SOL_SOCKET, SO_OOBINLINE, &intValue, &intSize);
2980 throwSocketException(env, convertError(errno));
2983 return newJavaLangBoolean(env, intValue);
2985 case JAVASOCKOPT_IP_MULTICAST_LOOP: {
2986 result = getOrSetSocketOption(SOCKOPT_GET, handle,
2988 IPV6_MULTICAST_LOOP, &intValue,
2991 throwSocketException(env, convertError(errno));
2994 return newJavaLangBoolean(env, intValue);
2996 case JAVASOCKOPT_IP_TOS: {
2997 result = getOrSetSocketOption(SOCKOPT_GET, handle, IP_TOS,
2998 IPV6_TCLASS, &intValue, &intSize);
3000 throwSocketException(env, convertError(errno));
3003 return newJavaLangInteger(env, intValue);
3005 case JAVASOCKOPT_SO_RCVTIMEOUT: {
3006 struct timeval timeout;
3007 socklen_t size = sizeof(timeout);
3008 result = getsockopt(handle, SOL_SOCKET, SO_RCVTIMEO, &timeout, &size);
3010 throwSocketException(env, convertError(errno));
3013 return newJavaLangInteger(env, timeout.tv_sec * 1000 + timeout.tv_usec/1000);
3016 throwSocketException(env, SOCKERR_OPTUNSUPP);
3023 static void osNetworkSystem_setSocketOptionImpl(JNIEnv* env, jclass clazz,
3024 jobject fileDescriptor, jint anOption, jobject optVal) {
3025 // LOGD("ENTER setSocketOptionImpl");
3029 socklen_t intSize = sizeof(int);
3030 unsigned char byteVal;
3031 socklen_t byteSize = sizeof(unsigned char);
3032 struct sockaddr_storage sockVal;
3033 int sockSize = sizeof(sockVal);
3035 if (env->IsInstanceOf(optVal, gCachedFields.integer_class)) {
3036 intVal = (int) env->GetIntField(optVal, gCachedFields.integer_class_value);
3037 } else if (env->IsInstanceOf(optVal, gCachedFields.boolean_class)) {
3038 intVal = (int) env->GetBooleanField(optVal, gCachedFields.boolean_class_value);
3039 } else if (env->IsInstanceOf(optVal, gCachedFields.byte_class)) {
3040 byteVal = (int) env->GetByteField(optVal, gCachedFields.byte_class_value);
3041 } else if (env->IsInstanceOf(optVal, gCachedFields.iaddr_class)) {
3042 if (inetAddressToSocketAddress(env, optVal, 0, &sockVal) < 0) {
3043 // Exception has already been thrown.
3046 } else if (env->IsInstanceOf(optVal, gCachedFields.genericipmreq_class)) {
3047 // we'll use optVal directly
3049 throwSocketException(env, SOCKERR_OPTUNSUPP);
3053 handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
3054 if (handle == 0 || handle == -1) {
3055 throwSocketException(env, SOCKERR_BADDESC);
3059 switch ((int) anOption & 0xffff) {
3060 case JAVASOCKOPT_SO_LINGER: {
3061 struct linger lingr;
3062 lingr.l_onoff = intVal > 0 ? 1 : 0;
3063 lingr.l_linger = intVal;
3064 result = setsockopt(handle, SOL_SOCKET, SO_LINGER, &lingr,
3065 sizeof(struct linger));
3067 throwSocketException(env, convertError(errno));
3073 case JAVASOCKOPT_TCP_NODELAY: {
3074 if ((anOption >> 16) & BROKEN_TCP_NODELAY) {
3077 result = setsockopt(handle, IPPROTO_TCP, TCP_NODELAY, &intVal, intSize);
3079 throwSocketException(env, convertError(errno));
3085 case JAVASOCKOPT_MCAST_TTL: {
3086 if ((anOption >> 16) & BROKEN_MULTICAST_TTL) {
3089 result = getOrSetSocketOption(SOCKOPT_SET, handle, IP_MULTICAST_TTL,
3090 IPV6_MULTICAST_HOPS, &byteVal,
3093 throwSocketException(env, convertError(errno));
3099 case JAVASOCKOPT_MCAST_ADD_MEMBERSHIP: {
3100 mcastAddDropMembership(env, handle, optVal,
3101 (anOption >> 16) & BROKEN_MULTICAST_IF, IP_ADD_MEMBERSHIP);
3105 case JAVASOCKOPT_MCAST_DROP_MEMBERSHIP: {
3106 mcastAddDropMembership(env, handle, optVal,
3107 (anOption >> 16) & BROKEN_MULTICAST_IF, IP_DROP_MEMBERSHIP);
3111 case JAVASOCKOPT_MCAST_INTERFACE: {
3112 if ((anOption >> 16) & BROKEN_MULTICAST_IF) {
3115 // This call is IPv4 only.
3116 if (getSocketAddressFamily(handle) != AF_INET) {
3117 throwSocketException(env, SOCKERR_BADAF);
3120 struct ip_mreqn mcast_req;
3121 memset(&mcast_req, 0, sizeof(mcast_req));
3122 struct sockaddr_in *sin = (struct sockaddr_in *) &sockVal;
3123 mcast_req.imr_address = sin->sin_addr;
3124 result = setsockopt(handle, IPPROTO_IP, IP_MULTICAST_IF,
3125 &mcast_req, sizeof(mcast_req));
3127 throwSocketException(env, convertError(errno));
3133 case JAVASOCKOPT_IP_MULTICAST_IF2: {
3134 if ((anOption >> 16) & BROKEN_MULTICAST_IF) {
3137 int addressFamily = getSocketAddressFamily(handle);
3138 int interfaceIndex = intVal;
3140 socklen_t optionLength;
3141 struct ip_mreqn multicastRequest;
3142 switch (addressFamily) {
3144 // IP_MULTICAST_IF expects a pointer to a struct ip_mreqn.
3145 memset(&multicastRequest, 0, sizeof(multicastRequest));
3146 multicastRequest.imr_ifindex = interfaceIndex;
3147 optionValue = &multicastRequest;
3148 optionLength = sizeof(multicastRequest);
3151 // IPV6_MULTICAST_IF expects a pointer to an integer.
3152 optionValue = &interfaceIndex;
3153 optionLength = sizeof(interfaceIndex);
3156 throwSocketException(env, SOCKERR_BADAF);
3159 result = getOrSetSocketOption(SOCKOPT_SET, handle,
3160 IP_MULTICAST_IF, IPV6_MULTICAST_IF, optionValue,
3163 throwSocketException(env, convertError(errno));
3169 case JAVASOCKOPT_SO_SNDBUF: {
3170 result = setsockopt(handle, SOL_SOCKET, SO_SNDBUF, &intVal, intSize);
3172 throwSocketException(env, convertError(errno));
3178 case JAVASOCKOPT_SO_RCVBUF: {
3179 result = setsockopt(handle, SOL_SOCKET, SO_RCVBUF, &intVal, intSize);
3181 throwSocketException(env, convertError(errno));
3187 case JAVASOCKOPT_SO_BROADCAST: {
3188 result = setsockopt(handle, SOL_SOCKET, SO_BROADCAST, &intVal, intSize);
3190 throwSocketException(env, convertError(errno));
3196 case JAVASOCKOPT_SO_REUSEADDR: {
3197 result = setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, &intVal, intSize);
3199 throwSocketException(env, convertError(errno));
3204 case JAVASOCKOPT_SO_KEEPALIVE: {
3205 result = setsockopt(handle, SOL_SOCKET, SO_KEEPALIVE, &intVal, intSize);
3207 throwSocketException(env, convertError(errno));
3213 case JAVASOCKOPT_SO_OOBINLINE: {
3214 result = setsockopt(handle, SOL_SOCKET, SO_OOBINLINE, &intVal, intSize);
3216 throwSocketException(env, convertError(errno));
3222 case JAVASOCKOPT_IP_MULTICAST_LOOP: {
3223 result = getOrSetSocketOption(SOCKOPT_SET, handle,
3225 IPV6_MULTICAST_LOOP, &intVal,
3228 throwSocketException(env, convertError(errno));
3234 case JAVASOCKOPT_IP_TOS: {
3235 result = getOrSetSocketOption(SOCKOPT_SET, handle, IP_TOS,
3236 IPV6_TCLASS, &intVal, &intSize);
3238 throwSocketException(env, convertError(errno));
3244 case JAVASOCKOPT_REUSEADDR_AND_REUSEPORT: {
3245 // SO_REUSEPORT doesn't need to get set on this System
3246 result = setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, &intVal, intSize);
3248 throwSocketException(env, convertError(errno));
3254 case JAVASOCKOPT_SO_RCVTIMEOUT: {
3255 struct timeval timeout;
3256 timeout.tv_sec = intVal / 1000;
3257 timeout.tv_usec = (intVal % 1000) * 1000;
3258 result = setsockopt(handle, SOL_SOCKET, SO_RCVTIMEO, &timeout,
3259 sizeof(struct timeval));
3261 throwSocketException(env, convertError(errno));
3268 throwSocketException(env, SOCKERR_OPTUNSUPP);
3273 static jint osNetworkSystem_getSocketFlagsImpl(JNIEnv* env, jclass clazz) {
3274 // LOGD("ENTER getSocketFlagsImpl");
3276 // Not implemented by harmony
3280 static void osNetworkSystem_socketCloseImpl(JNIEnv* env, jclass clazz,
3281 jobject fileDescriptor) {
3282 // LOGD("ENTER socketCloseImpl");
3284 int handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
3286 if (handle == 0 || handle == -1) {
3287 throwSocketException(env, SOCKERR_BADSOCKET);
3291 jniSetFileDescriptorOfFD(env, fileDescriptor, -1);
3296 static void osNetworkSystem_setInetAddressImpl(JNIEnv* env, jobject obj,
3297 jobject sender, jbyteArray address) {
3298 // LOGD("ENTER setInetAddressImpl");
3300 env->SetObjectField(sender, gCachedFields.iaddr_ipaddress, address);
3303 // TODO: rewrite this method in Java and make it support IPv6.
3304 static jobject osNetworkSystem_inheritedChannelImpl(JNIEnv* env, jobject obj) {
3305 // LOGD("ENTER inheritedChannelImpl");
3309 socklen_t length = sizeof(opt);
3311 struct sockaddr_in local_addr;
3312 struct sockaddr_in remote_addr;
3313 jclass channel_class, socketaddr_class, serverSocket_class, socketImpl_class;
3314 jobject channel_object = NULL, socketaddr_object, serverSocket_object;
3315 jobject fd_object, addr_object, localAddr_object, socketImpl_object;
3316 jfieldID port_field, socketaddr_field, bound_field, fd_field;
3317 jfieldID serverSocket_field, socketImpl_field, addr_field, localAddr_field;
3318 jmethodID channel_new;
3319 jbyteArray addr_array;
3320 struct sockaddr_in *sock;
3323 jboolean jtrue = JNI_TRUE;
3325 if (0 != getsockopt(socket, SOL_SOCKET, SO_TYPE, &opt, &length)) {
3328 if (SOCK_STREAM !=opt && SOCK_DGRAM !=opt) {
3333 length = sizeof(struct sockaddr);
3334 if (0 != getsockname(socket, (struct sockaddr *)&local_addr, &length)) {
3337 if (AF_INET != local_addr.sin_family || length != sizeof(struct sockaddr)) {
3340 localAddr = (jbyte*) malloc(sizeof(jbyte)*4);
3341 if (NULL == localAddr) {
3344 memcpy (localAddr, &(local_addr.sin_addr.s_addr), 4);
3346 if (0 != getpeername(socket, (struct sockaddr *)&remote_addr, &length)) {
3347 remote_addr.sin_port = 0;
3348 remote_addr.sin_addr.s_addr = 0;
3349 address = (jbyte*) malloc(sizeof(jbyte)*4);
3350 bzero(address, sizeof(jbyte)*4);
3352 if (AF_INET != remote_addr.sin_family
3353 || length != sizeof(struct sockaddr)) {
3356 address = (jbyte*) malloc(sizeof(jbyte)*4);
3357 memcpy (address, &(remote_addr.sin_addr.s_addr), 4);
3360 // analysis end, begin pack to java
3361 if (SOCK_STREAM == opt) {
3362 if (remote_addr.sin_port!=0) {
3364 channel_class = env->FindClass(
3365 "org/apache/harmony/nio/internal/SocketChannelImpl");
3366 if (NULL == channel_class) {
3370 channel_new = env->GetMethodID(channel_class, "<init>", "()V");
3371 if (NULL == channel_new) {
3374 channel_object = env->NewObject(channel_class, channel_new);
3375 if (NULL == channel_object) {
3378 // new and set FileDescript
3380 fd_field = env->GetFieldID(channel_class, "fd",
3381 "java/io/FielDescriptor");
3382 fd_object = env->GetObjectField(channel_object, fd_field);
3383 if (NULL == fd_object) {
3387 jniSetFileDescriptorOfFD(env, fd_object, socket);
3390 port_field = env->GetFieldID(channel_class, "localPort", "I");
3391 env->SetIntField(channel_object, port_field,
3392 ntohs(local_addr.sin_port));
3394 // new and set remote addr
3395 addr_array = env->NewByteArray((jsize)4);
3396 env->SetByteArrayRegion(addr_array, (jsize)0, (jsize)4, address);
3397 addr_object = env->NewObject(gCachedFields.i4addr_class,
3398 gCachedFields.i4addr_class_init, addr_array);
3399 if (NULL == addr_object) {
3402 socketaddr_class = env->FindClass("java/net/InetSocketAddress");
3403 socketaddr_field = env->GetFieldID(channel_class, "connectAddress",
3404 "Ljava/net/InetSocketAddress;");
3405 socketaddr_object = env->GetObjectField(channel_object,
3407 if (NULL == socketaddr_object) {
3412 socketaddr_class = env->FindClass("java/net/InetSocketAddress");
3413 socketaddr_field = env->GetFieldID(channel_class, "connectAddress",
3414 "Ljava/net/InetSocketAddress;");
3415 socketaddr_object = env->GetObjectField(channel_object,
3418 localAddr_field = env->GetFieldID(channel_class, "localAddress",
3419 "Ljava/net/Inet4Address;");
3420 addr_array = env->NewByteArray((jsize)4);
3421 env->SetByteArrayRegion(addr_array, (jsize)0, (jsize)4, localAddr);
3422 localAddr_object = env->NewObject(gCachedFields.i4addr_class,
3423 gCachedFields.i4addr_class_init, addr_array);
3424 jfieldID socketaddr_field = env->GetFieldID(channel_class,
3425 "connectAddress", "Ljava/net/InetSocketAddress;");
3426 jobject socketaddr_object = env->GetObjectField(channel_object,
3428 env->SetObjectField(socketaddr_object, localAddr_field,
3430 if (NULL == localAddr_object) {
3436 port_field = env->GetFieldID(socketaddr_class, "port", "I");
3437 env->SetIntField(socketaddr_object, port_field,
3438 ntohs(remote_addr.sin_port));
3441 if (0 != local_addr.sin_port) {
3442 bound_field = env->GetFieldID(channel_class, "isBound", "Z");
3443 env->SetBooleanField(channel_object, bound_field, jtrue);
3448 channel_class = env->FindClass(
3449 "org/apache/harmony/nio/internal/ServerSocketChannelImpl");
3450 if (NULL == channel_class) {
3454 channel_new = env->GetMethodID(channel_class, "<init>", "()V");
3455 if (NULL == channel_new) {
3458 channel_object = env->NewObject(channel_class, channel_new);
3459 if (NULL == channel_object) {
3463 serverSocket_field = env->GetFieldID(channel_class, "socket",
3464 "Ljava/net/ServerSocket;");
3465 serverSocket_class = env->FindClass("Ljava/net/ServerSocket;");
3466 serverSocket_object = env->GetObjectField(channel_object,
3467 serverSocket_field);
3469 if (0 != local_addr.sin_port) {
3470 bound_field = env->GetFieldID(channel_class, "isBound", "Z");
3471 env->SetBooleanField(channel_object, bound_field, jtrue);
3472 bound_field = env->GetFieldID(serverSocket_class, "isBound", "Z");
3473 env->SetBooleanField(serverSocket_object, bound_field, jtrue);
3476 socketImpl_class = env->FindClass("java/net/SocketImpl");
3477 socketImpl_field = env->GetFieldID(channel_class, "impl",
3478 "Ljava/net/SocketImpl;");
3479 socketImpl_object = env->GetObjectField(channel_object,
3481 if (NULL == socketImpl_object) {
3485 addr_array = env->NewByteArray((jsize)4);
3486 localAddr_field = env->GetFieldID(channel_class, "localAddress",
3487 "Ljava/net/InetAddress;");
3488 memset(address, 0, 4);
3489 env->SetByteArrayRegion(addr_array, (jsize)0, (jsize)4, address);
3490 localAddr_object = env->NewObject(gCachedFields.i4addr_class,
3491 gCachedFields.i4addr_class_init, addr_array);
3492 if (NULL == localAddr_object) {
3495 env->SetObjectField(socketImpl_object, localAddr_field,
3497 addr_array = env->NewByteArray((jsize)4);
3498 env->SetByteArrayRegion(addr_array, (jsize)0, (jsize)4, localAddr);
3499 env->SetObjectField(localAddr_object,
3500 gCachedFields.iaddr_ipaddress, addr_array);
3503 port_field = env->GetFieldID(socketImpl_class, "localport", "I");
3504 env->SetIntField(socketImpl_object, port_field,
3505 ntohs(local_addr.sin_port));
3509 // new DatagramChannel
3510 channel_class = env->FindClass(
3511 "org/apache/harmony/nio/internal/DatagramChannelImpl");
3512 if (NULL == channel_class) {
3516 channel_new = env->GetMethodID(channel_class, "<init>", "()V");
3517 if (NULL == channel_new) {
3520 channel_object = env->NewObject(channel_class, channel_new);
3521 if (NULL == channel_object) {
3525 // new and set FileDescript
3526 fd_field = env->GetFieldID(channel_class, "fd", "java/io/FileDescriptor");
3527 fd_object = env->GetObjectField(channel_object, fd_field);
3528 if (NULL == fd_object) {
3532 jniSetFileDescriptorOfFD(env, fd_object, socket);
3534 port_field = env->GetFieldID(channel_class, "localPort", "I");
3535 env->SetIntField(channel_object, port_field, ntohs(local_addr.sin_port));
3537 // new and set remote addr
3538 addr_array = env->NewByteArray((jsize)4);
3539 env->SetByteArrayRegion(addr_array, (jsize)0, (jsize)4, address);
3540 addr_object = env->NewObject(gCachedFields.iaddr_class,
3541 gCachedFields.i4addr_class_init, addr_array);
3542 if (NULL == addr_object) {
3545 socketaddr_class = env->FindClass("java/net/InetSocketAddress");
3546 socketaddr_field = env->GetFieldID(channel_class, "connectAddress",
3547 "Ljava/net/InetSocketAddress;");
3548 socketaddr_object = env->GetObjectField(channel_object, socketaddr_field);
3549 if (NULL == socketaddr_object) {
3554 if (0 != local_addr.sin_port) {
3555 bound_field = env->GetFieldID(channel_class, "isBound", "Z");
3556 env->SetBooleanField(channel_object, bound_field, jtrue);
3562 return channel_object;
3568 static JNINativeMethod gMethods[] = {
3569 /* name, signature, funcPtr */
3570 { "oneTimeInitializationImpl", "(Z)V", (void*) osNetworkSystem_oneTimeInitializationImpl },
3571 { "createStreamSocketImpl", "(Ljava/io/FileDescriptor;Z)V", (void*) osNetworkSystem_createStreamSocketImpl },
3572 { "createDatagramSocketImpl", "(Ljava/io/FileDescriptor;Z)V", (void*) osNetworkSystem_createDatagramSocketImpl },
3573 { "readSocketImpl", "(Ljava/io/FileDescriptor;[BIII)I", (void*) osNetworkSystem_readSocketImpl },
3574 { "readSocketDirectImpl", "(Ljava/io/FileDescriptor;IIII)I", (void*) osNetworkSystem_readSocketDirectImpl },
3575 { "writeSocketImpl", "(Ljava/io/FileDescriptor;[BII)I", (void*) osNetworkSystem_writeSocketImpl },
3576 { "writeSocketDirectImpl", "(Ljava/io/FileDescriptor;III)I", (void*) osNetworkSystem_writeSocketDirectImpl },
3577 { "setNonBlockingImpl", "(Ljava/io/FileDescriptor;Z)V", (void*) osNetworkSystem_setNonBlockingImpl },
3578 { "connectSocketImpl", "(Ljava/io/FileDescriptor;ILjava/net/InetAddress;I)I", (void*) osNetworkSystem_connectSocketImpl },
3579 { "connectWithTimeoutSocketImpl", "(Ljava/io/FileDescriptor;IILjava/net/InetAddress;II[B)I", (void*) osNetworkSystem_connectWithTimeoutSocketImpl },
3580 { "connectStreamWithTimeoutSocketImpl","(Ljava/io/FileDescriptor;IIILjava/net/InetAddress;)V", (void*) osNetworkSystem_connectStreamWithTimeoutSocketImpl },
3581 { "socketBindImpl", "(Ljava/io/FileDescriptor;ILjava/net/InetAddress;)V", (void*) osNetworkSystem_socketBindImpl },
3582 { "listenStreamSocketImpl", "(Ljava/io/FileDescriptor;I)V", (void*) osNetworkSystem_listenStreamSocketImpl },
3583 { "availableStreamImpl", "(Ljava/io/FileDescriptor;)I", (void*) osNetworkSystem_availableStreamImpl },
3584 { "acceptSocketImpl", "(Ljava/io/FileDescriptor;Ljava/net/SocketImpl;Ljava/io/FileDescriptor;I)V",(void*) osNetworkSystem_acceptSocketImpl },
3585 { "supportsUrgentDataImpl", "(Ljava/io/FileDescriptor;)Z", (void*) osNetworkSystem_supportsUrgentDataImpl },
3586 { "sendUrgentDataImpl", "(Ljava/io/FileDescriptor;B)V", (void*) osNetworkSystem_sendUrgentDataImpl },
3587 { "connectDatagramImpl2", "(Ljava/io/FileDescriptor;IILjava/net/InetAddress;)V", (void*) osNetworkSystem_connectDatagramImpl2 },
3588 { "disconnectDatagramImpl", "(Ljava/io/FileDescriptor;)V", (void*) osNetworkSystem_disconnectDatagramImpl },
3589 { "peekDatagramImpl", "(Ljava/io/FileDescriptor;Ljava/net/InetAddress;I)I", (void*) osNetworkSystem_peekDatagramImpl },
3590 { "receiveDatagramImpl", "(Ljava/io/FileDescriptor;Ljava/net/DatagramPacket;[BIIIZ)I", (void*) osNetworkSystem_receiveDatagramImpl },
3591 { "receiveDatagramDirectImpl", "(Ljava/io/FileDescriptor;Ljava/net/DatagramPacket;IIIIZ)I", (void*) osNetworkSystem_receiveDatagramDirectImpl },
3592 { "recvConnectedDatagramImpl", "(Ljava/io/FileDescriptor;Ljava/net/DatagramPacket;[BIIIZ)I", (void*) osNetworkSystem_recvConnectedDatagramImpl },
3593 { "recvConnectedDatagramDirectImpl", "(Ljava/io/FileDescriptor;Ljava/net/DatagramPacket;IIIIZ)I", (void*) osNetworkSystem_recvConnectedDatagramDirectImpl },
3594 { "sendDatagramImpl", "(Ljava/io/FileDescriptor;[BIIIZILjava/net/InetAddress;)I", (void*) osNetworkSystem_sendDatagramImpl },
3595 { "sendDatagramDirectImpl", "(Ljava/io/FileDescriptor;IIIIZILjava/net/InetAddress;)I", (void*) osNetworkSystem_sendDatagramDirectImpl },
3596 { "sendConnectedDatagramImpl", "(Ljava/io/FileDescriptor;[BIIZ)I", (void*) osNetworkSystem_sendConnectedDatagramImpl },
3597 { "sendConnectedDatagramDirectImpl", "(Ljava/io/FileDescriptor;IIIZ)I", (void*) osNetworkSystem_sendConnectedDatagramDirectImpl },
3598 { "createServerStreamSocketImpl", "(Ljava/io/FileDescriptor;Z)V", (void*) osNetworkSystem_createServerStreamSocketImpl },
3599 { "receiveStreamImpl", "(Ljava/io/FileDescriptor;[BIII)I", (void*) osNetworkSystem_receiveStreamImpl },
3600 { "sendStreamImpl", "(Ljava/io/FileDescriptor;[BII)I", (void*) osNetworkSystem_sendStreamImpl },
3601 { "shutdownInputImpl", "(Ljava/io/FileDescriptor;)V", (void*) osNetworkSystem_shutdownInputImpl },
3602 { "shutdownOutputImpl", "(Ljava/io/FileDescriptor;)V", (void*) osNetworkSystem_shutdownOutputImpl },
3603 { "sendDatagramImpl2", "(Ljava/io/FileDescriptor;[BIIILjava/net/InetAddress;)I", (void*) osNetworkSystem_sendDatagramImpl2 },
3604 { "selectImpl", "([Ljava/io/FileDescriptor;[Ljava/io/FileDescriptor;II[IJ)I", (void*) osNetworkSystem_selectImpl },
3605 { "getSocketLocalAddressImpl", "(Ljava/io/FileDescriptor;Z)Ljava/net/InetAddress;", (void*) osNetworkSystem_getSocketLocalAddressImpl },
3606 { "getSocketLocalPortImpl", "(Ljava/io/FileDescriptor;Z)I", (void*) osNetworkSystem_getSocketLocalPortImpl },
3607 { "getSocketOptionImpl", "(Ljava/io/FileDescriptor;I)Ljava/lang/Object;", (void*) osNetworkSystem_getSocketOptionImpl },
3608 { "setSocketOptionImpl", "(Ljava/io/FileDescriptor;ILjava/lang/Object;)V", (void*) osNetworkSystem_setSocketOptionImpl },
3609 { "getSocketFlagsImpl", "()I", (void*) osNetworkSystem_getSocketFlagsImpl },
3610 { "socketCloseImpl", "(Ljava/io/FileDescriptor;)V", (void*) osNetworkSystem_socketCloseImpl },
3611 { "setInetAddressImpl", "(Ljava/net/InetAddress;[B)V", (void*) osNetworkSystem_setInetAddressImpl },
3612 { "inheritedChannelImpl", "()Ljava/nio/channels/Channel;", (void*) osNetworkSystem_inheritedChannelImpl },
3615 int register_org_apache_harmony_luni_platform_OSNetworkSystem(JNIEnv* env) {
3616 return jniRegisterNativeMethods(env,
3617 "org/apache/harmony/luni/platform/OSNetworkSystem",