blob: afad49df49f555e16fc9509f63e590646b04c9b6 [file] [log] [blame]
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Lorenzo Colittie8596902009-09-18 15:25:06 -070017// BEGIN android-changed
18//
19// This file has been substantially reworked in order to provide more IPv6
20// support and to move functionality from Java to native code where it made
21// sense (e.g. when converting between IP addresses, socket structures, and
22// strings, for which there exist fast and robust native implementations).
23
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080024#define LOG_TAG "OSNetworkSystem"
25
26#include "JNIHelp.h"
Elliott Hughes845ce3c2009-11-13 17:07:00 -080027#include "LocalArray.h"
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080028#include "jni.h"
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080029
Elliott Hughesfc354fe2009-10-16 17:25:34 -070030#include <arpa/inet.h>
31#include <assert.h>
32#include <errno.h>
33#include <netdb.h>
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080034#include <netinet/in.h>
35#include <netinet/tcp.h>
Elliott Hughesfc354fe2009-10-16 17:25:34 -070036#include <stdio.h>
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080037#include <stdlib.h>
Dan Bornstein31ba2332009-10-26 16:30:39 -070038#include <string.h>
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080039#include <sys/ioctl.h>
Elliott Hughesfc354fe2009-10-16 17:25:34 -070040#include <sys/socket.h>
41#include <sys/time.h>
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080042#include <sys/un.h>
Elliott Hughesfc354fe2009-10-16 17:25:34 -070043#include <unistd.h>
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080044
Lorenzo Colittie35dd522009-06-04 16:32:29 -070045// Temporary hack to build on systems that don't have up-to-date libc headers.
46#ifndef IPV6_TCLASS
Dan Bornstein033eddd2009-10-29 10:15:42 -070047#ifdef __linux__
48#define IPV6_TCLASS 67 // Linux
49#else
50#define IPV6_TCLASS -1 // BSD(-like); TODO: Something better than this!
51#endif
Lorenzo Colittie35dd522009-06-04 16:32:29 -070052#endif
53
Dan Bornsteinfef88752009-11-04 15:34:14 -080054/*
Dan Bornsteinfef88752009-11-04 15:34:14 -080055 * TODO: The multicast code is highly platform-dependent, and for now
56 * we just punt on anything but Linux.
57 */
58#ifdef __linux__
59#define ENABLE_MULTICAST
60#endif
61
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080062#define JAVASOCKOPT_TCP_NODELAY 1
63#define JAVASOCKOPT_IP_TOS 3
64#define JAVASOCKOPT_SO_REUSEADDR 4
65#define JAVASOCKOPT_SO_KEEPALIVE 8
Elliott Hughesa9a57f22009-10-30 17:54:32 -070066#define JAVASOCKOPT_IP_MULTICAST_IF 16
Elliott Hughes4401c752010-05-04 09:47:02 -070067#define JAVASOCKOPT_MULTICAST_TTL 17
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080068#define JAVASOCKOPT_IP_MULTICAST_LOOP 18
69#define JAVASOCKOPT_MCAST_ADD_MEMBERSHIP 19
70#define JAVASOCKOPT_MCAST_DROP_MEMBERSHIP 20
71#define JAVASOCKOPT_IP_MULTICAST_IF2 31
72#define JAVASOCKOPT_SO_BROADCAST 32
73#define JAVASOCKOPT_SO_LINGER 128
74#define JAVASOCKOPT_REUSEADDR_AND_REUSEPORT 10001
75#define JAVASOCKOPT_SO_SNDBUF 4097
76#define JAVASOCKOPT_SO_RCVBUF 4098
77#define JAVASOCKOPT_SO_RCVTIMEOUT 4102
78#define JAVASOCKOPT_SO_OOBINLINE 4099
79
80/* constants for calling multi-call functions */
81#define SOCKET_STEP_START 10
82#define SOCKET_STEP_CHECK 20
83#define SOCKET_STEP_DONE 30
84
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080085#define SOCKET_CONNECT_STEP_START 0
86#define SOCKET_CONNECT_STEP_CHECK 1
87
88#define SOCKET_OP_NONE 0
89#define SOCKET_OP_READ 1
90#define SOCKET_OP_WRITE 2
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080091
92#define SOCKET_NOFLAGS 0
93
Elliott Hughes4d8e9332010-05-03 14:31:03 -070094static struct CachedFields {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080095 jfieldID fd_descriptor;
96 jclass iaddr_class;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080097 jmethodID iaddr_getbyaddress;
Lorenzo Colitti02936f32009-09-02 13:52:54 -070098 jclass i4addr_class;
99 jmethodID i4addr_class_init;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800100 jfieldID iaddr_ipaddress;
101 jclass genericipmreq_class;
102 jclass integer_class;
103 jmethodID integer_class_init;
104 jfieldID integer_class_value;
105 jclass boolean_class;
106 jmethodID boolean_class_init;
107 jfieldID boolean_class_value;
108 jclass byte_class;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800109 jfieldID byte_class_value;
Lorenzo Colitti1790dd32009-09-08 18:30:56 -0700110 jclass socketimpl_class;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800111 jfieldID socketimpl_address;
112 jfieldID socketimpl_port;
113 jclass dpack_class;
114 jfieldID dpack_address;
115 jfieldID dpack_port;
116 jfieldID dpack_length;
117} gCachedFields;
118
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800119/* needed for connecting with timeout */
Elliott Hughes87527682009-10-06 14:08:53 -0700120struct selectFDSet {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800121 int nfds;
122 int sock;
123 fd_set writeSet;
124 fd_set readSet;
125 fd_set exceptionSet;
Elliott Hughes87527682009-10-06 14:08:53 -0700126};
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800127
Elliott Hughes24912e02009-10-19 16:36:13 -0700128// TODO(enh): move to JNIHelp.h
Elliott Hughesb375c0c2010-05-04 18:06:21 -0700129static void jniThrowExceptionWithErrno(JNIEnv* env, const char* exceptionClassName, int error) {
Elliott Hughesa9a57f22009-10-30 17:54:32 -0700130 char buf[BUFSIZ];
Elliott Hughesb375c0c2010-05-04 18:06:21 -0700131 jniThrowException(env, exceptionClassName, jniStrError(error, buf, sizeof(buf)));
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800132}
133
Elliott Hughesba563a42009-11-05 13:50:06 -0800134static void jniThrowBindException(JNIEnv* env, int error) {
135 jniThrowExceptionWithErrno(env, "java/net/BindException", error);
136}
137
Elliott Hughesb375c0c2010-05-04 18:06:21 -0700138static void jniThrowConnectException(JNIEnv* env, int error) {
139 jniThrowExceptionWithErrno(env, "java/net/ConnectException", error);
140}
141
142static void jniThrowSecurityException(JNIEnv* env, int error) {
143 jniThrowExceptionWithErrno(env, "java/lang/SecurityException", error);
144}
145
Elliott Hughesba563a42009-11-05 13:50:06 -0800146static void jniThrowSocketException(JNIEnv* env, int error) {
147 jniThrowExceptionWithErrno(env, "java/net/SocketException", error);
148}
149
150static void jniThrowSocketTimeoutException(JNIEnv* env, int error) {
151 jniThrowExceptionWithErrno(env, "java/net/SocketTimeoutException", error);
152}
153
Elliott Hughesfc354fe2009-10-16 17:25:34 -0700154// Used by functions that shouldn't throw SocketException. (These functions
155// aren't meant to see bad addresses, so seeing one really does imply an
156// internal error.)
Elliott Hughesa9a57f22009-10-30 17:54:32 -0700157// TODO: fix the code (native and Java) so we don't paint ourselves into this corner.
Elliott Hughesfc354fe2009-10-16 17:25:34 -0700158static void jniThrowBadAddressFamily(JNIEnv* env) {
Elliott Hughesa9a57f22009-10-30 17:54:32 -0700159 jniThrowException(env, "java/lang/IllegalArgumentException", "Bad address family");
Elliott Hughesfc354fe2009-10-16 17:25:34 -0700160}
161
Elliott Hughes24912e02009-10-19 16:36:13 -0700162static bool jniGetFd(JNIEnv* env, jobject fileDescriptor, int& fd) {
163 fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
164 if (fd == -1) {
Elliott Hughesa9a57f22009-10-30 17:54:32 -0700165 jniThrowSocketException(env, EBADF);
Elliott Hughes24912e02009-10-19 16:36:13 -0700166 return false;
167 }
168 return true;
169}
170
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800171/**
Elliott Hughesfc354fe2009-10-16 17:25:34 -0700172 * Converts a native address structure to a Java byte array.
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800173 */
Elliott Hughesb375c0c2010-05-04 18:06:21 -0700174static jbyteArray socketAddressToByteArray(JNIEnv *env, struct sockaddr_storage *address) {
Lorenzo Colitti65663e12009-05-26 15:51:50 -0700175 void *rawAddress;
176 size_t addressLength;
177 if (address->ss_family == AF_INET) {
178 struct sockaddr_in *sin = (struct sockaddr_in *) address;
179 rawAddress = &sin->sin_addr.s_addr;
180 addressLength = 4;
181 } else if (address->ss_family == AF_INET6) {
182 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) address;
183 rawAddress = &sin6->sin6_addr.s6_addr;
184 addressLength = 16;
185 } else {
Elliott Hughesfc354fe2009-10-16 17:25:34 -0700186 jniThrowBadAddressFamily(env);
Lorenzo Colitti65663e12009-05-26 15:51:50 -0700187 return NULL;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800188 }
189
Lorenzo Colitti65663e12009-05-26 15:51:50 -0700190 jbyteArray byteArray = env->NewByteArray(addressLength);
191 if (byteArray == NULL) {
Lorenzo Colitti65663e12009-05-26 15:51:50 -0700192 return NULL;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800193 }
Lorenzo Colitti65663e12009-05-26 15:51:50 -0700194 env->SetByteArrayRegion(byteArray, 0, addressLength, (jbyte *) rawAddress);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800195
Lorenzo Colitti65663e12009-05-26 15:51:50 -0700196 return byteArray;
197}
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800198
Lorenzo Colitti65663e12009-05-26 15:51:50 -0700199/**
Lorenzo Colitti65663e12009-05-26 15:51:50 -0700200 * Returns the port number in a sockaddr_storage structure.
201 *
202 * @param address the sockaddr_storage structure to get the port from
203 *
204 * @return the port number, or -1 if the address family is unknown.
205 */
206static int getSocketAddressPort(struct sockaddr_storage *address) {
207 switch (address->ss_family) {
208 case AF_INET:
209 return ntohs(((struct sockaddr_in *) address)->sin_port);
210 case AF_INET6:
211 return ntohs(((struct sockaddr_in6 *) address)->sin6_port);
212 default:
213 return -1;
214 }
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800215}
216
217/**
Elliott Hughesf5eafc52009-11-05 10:00:02 -0800218 * Obtain the socket address family from an existing socket.
219 *
220 * @param socket the file descriptor of the socket to examine
221 * @return an integer, the address family of the socket
Lorenzo Colittie8596902009-09-18 15:25:06 -0700222 */
Elliott Hughesf5eafc52009-11-05 10:00:02 -0800223static int getSocketAddressFamily(int socket) {
224 sockaddr_storage ss;
225 socklen_t namelen = sizeof(ss);
226 int ret = getsockname(socket, (sockaddr*) &ss, &namelen);
227 if (ret != 0) {
228 return AF_UNSPEC;
229 } else {
230 return ss.ss_family;
Lorenzo Colittie8596902009-09-18 15:25:06 -0700231 }
Lorenzo Colittie8596902009-09-18 15:25:06 -0700232}
233
Elliott Hughes4d8e9332010-05-03 14:31:03 -0700234static jobject byteArrayToInetAddress(JNIEnv* env, jbyteArray byteArray) {
Elliott Hughesa9a57f22009-10-30 17:54:32 -0700235 if (byteArray == NULL) {
236 return NULL;
237 }
238 return env->CallStaticObjectMethod(gCachedFields.iaddr_class,
239 gCachedFields.iaddr_getbyaddress, byteArray);
240}
241
Lorenzo Colittie8596902009-09-18 15:25:06 -0700242/**
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800243 * Converts a native address structure to an InetAddress object.
244 * Throws a NullPointerException or an IOException in case of
Lorenzo Colitti511ab052009-09-19 11:06:31 -0700245 * error.
Lorenzo Colitti65663e12009-05-26 15:51:50 -0700246 *
Elliott Hughesb150dcd2009-10-20 22:58:23 -0700247 * @param sockAddress the sockaddr_storage structure to convert
Lorenzo Colitti65663e12009-05-26 15:51:50 -0700248 *
249 * @return a jobject representing an InetAddress
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800250 */
Elliott Hughes5be11d72009-10-02 17:20:00 -0700251jobject socketAddressToInetAddress(JNIEnv* env, sockaddr_storage* sockAddress) {
252 jbyteArray byteArray = socketAddressToByteArray(env, sockAddress);
Elliott Hughesa9a57f22009-10-30 17:54:32 -0700253 return byteArrayToInetAddress(env, byteArray);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800254}
255
Elliott Hughes722a27e2010-03-05 20:37:25 -0800256// Handles translating between IPv4 and IPv6 addresses so -- where possible --
257// we can use either class of address with either an IPv4 or IPv6 socket.
258class CompatibleSocketAddress {
259public:
260 // Constructs an address corresponding to 'ss' that's compatible with 'fd'.
261 CompatibleSocketAddress(int fd, const sockaddr_storage& ss, bool mapUnspecified) {
262 const int desiredFamily = getSocketAddressFamily(fd);
263 if (ss.ss_family == AF_INET6) {
264 if (desiredFamily == AF_INET6) {
265 // Nothing to do.
266 mCompatibleAddress = reinterpret_cast<const sockaddr*>(&ss);
267 } else {
268 sockaddr_in* sin = reinterpret_cast<sockaddr_in*>(&mTmp);
269 const sockaddr_in6* sin6 = reinterpret_cast<const sockaddr_in6*>(&ss);
270 memset(sin, 0, sizeof(*sin));
271 sin->sin_family = AF_INET;
272 sin->sin_port = sin6->sin6_port;
273 if (IN6_IS_ADDR_V4COMPAT(&sin6->sin6_addr)) {
274 // We have an IPv6-mapped IPv4 address, but need plain old IPv4.
275 // Unmap the mapped address in ss into an IPv6 address in mTmp.
276 memcpy(&sin->sin_addr.s_addr, &sin6->sin6_addr.s6_addr[12], 4);
277 mCompatibleAddress = reinterpret_cast<const sockaddr*>(&mTmp);
278 } else if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr)) {
279 // Translate the IPv6 loopback address to the IPv4 one.
280 sin->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
281 mCompatibleAddress = reinterpret_cast<const sockaddr*>(&mTmp);
282 } else {
283 // We can't help you. We return what you gave us, and assume you'll
284 // get a sensible error when you use the address.
285 mCompatibleAddress = reinterpret_cast<const sockaddr*>(&ss);
286 }
287 }
288 } else /* ss.ss_family == AF_INET */ {
289 if (desiredFamily == AF_INET) {
290 // Nothing to do.
291 mCompatibleAddress = reinterpret_cast<const sockaddr*>(&ss);
292 } else {
293 // We have IPv4 and need IPv6.
294 // Map the IPv4 address in ss into an IPv6 address in mTmp.
295 const sockaddr_in* sin = reinterpret_cast<const sockaddr_in*>(&ss);
296 sockaddr_in6* sin6 = reinterpret_cast<sockaddr_in6*>(&mTmp);
297 memset(sin6, 0, sizeof(*sin6));
298 sin6->sin6_family = AF_INET6;
299 sin6->sin6_port = sin->sin_port;
300 // TODO: mapUnspecified was introduced because kernels < 2.6.31 don't allow
301 // you to bind to ::ffff:0.0.0.0. When we move to something >= 2.6.31, we
302 // should make the code behave as if mapUnspecified were always true, and
303 // remove the parameter.
304 if (sin->sin_addr.s_addr != 0 || mapUnspecified) {
305 memset(&(sin6->sin6_addr.s6_addr[10]), 0xff, 2);
306 }
307 memcpy(&sin6->sin6_addr.s6_addr[12], &sin->sin_addr.s_addr, 4);
308 mCompatibleAddress = reinterpret_cast<const sockaddr*>(&mTmp);
309 }
310 }
Elliott Hughesf5eafc52009-11-05 10:00:02 -0800311 }
Elliott Hughes722a27e2010-03-05 20:37:25 -0800312 // Returns a pointer to an address compatible with the socket.
313 const sockaddr* get() const {
314 return mCompatibleAddress;
Elliott Hughesf5eafc52009-11-05 10:00:02 -0800315 }
Elliott Hughes722a27e2010-03-05 20:37:25 -0800316private:
317 const sockaddr* mCompatibleAddress;
318 sockaddr_storage mTmp;
319};
Lorenzo Colittie8596902009-09-18 15:25:06 -0700320
321/**
Lorenzo Colitti65663e12009-05-26 15:51:50 -0700322 * Converts an InetAddress object and port number to a native address structure.
323 * Throws a NullPointerException or a SocketException in case of
Elliott Hughesfc354fe2009-10-16 17:25:34 -0700324 * error.
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800325 */
Elliott Hughesfc354fe2009-10-16 17:25:34 -0700326static bool byteArrayToSocketAddress(JNIEnv *env,
Lorenzo Colitti511ab052009-09-19 11:06:31 -0700327 jbyteArray addressBytes, int port, sockaddr_storage *sockaddress) {
Lorenzo Colitti65663e12009-05-26 15:51:50 -0700328 if (addressBytes == NULL) {
Elliott Hughesda4f31d2010-01-28 13:43:39 -0800329 jniThrowNullPointerException(env, NULL);
Elliott Hughesfc354fe2009-10-16 17:25:34 -0700330 return false;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800331 }
Lorenzo Colittie8596902009-09-18 15:25:06 -0700332
333 // Convert the IP address bytes to the proper IP address type.
Elliott Hughesfc354fe2009-10-16 17:25:34 -0700334 size_t addressLength = env->GetArrayLength(addressBytes);
Elliott Hughesa9a57f22009-10-30 17:54:32 -0700335 memset(sockaddress, 0, sizeof(*sockaddress));
Lorenzo Colitti65663e12009-05-26 15:51:50 -0700336 if (addressLength == 4) {
337 // IPv4 address.
Lorenzo Colitti511ab052009-09-19 11:06:31 -0700338 sockaddr_in *sin = reinterpret_cast<sockaddr_in*>(sockaddress);
Lorenzo Colitti65663e12009-05-26 15:51:50 -0700339 sin->sin_family = AF_INET;
340 sin->sin_port = htons(port);
Elliott Hughes44550df2009-09-08 19:44:54 -0700341 jbyte* dst = reinterpret_cast<jbyte*>(&sin->sin_addr.s_addr);
342 env->GetByteArrayRegion(addressBytes, 0, 4, dst);
Lorenzo Colitti65663e12009-05-26 15:51:50 -0700343 } else if (addressLength == 16) {
344 // IPv6 address.
Lorenzo Colitti511ab052009-09-19 11:06:31 -0700345 sockaddr_in6 *sin6 = reinterpret_cast<sockaddr_in6*>(sockaddress);
Lorenzo Colitti65663e12009-05-26 15:51:50 -0700346 sin6->sin6_family = AF_INET6;
347 sin6->sin6_port = htons(port);
Elliott Hughes44550df2009-09-08 19:44:54 -0700348 jbyte* dst = reinterpret_cast<jbyte*>(&sin6->sin6_addr.s6_addr);
349 env->GetByteArrayRegion(addressBytes, 0, 16, dst);
Lorenzo Colitti65663e12009-05-26 15:51:50 -0700350 } else {
Elliott Hughesfc354fe2009-10-16 17:25:34 -0700351 jniThrowBadAddressFamily(env);
352 return false;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800353 }
Elliott Hughesfc354fe2009-10-16 17:25:34 -0700354 return true;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800355}
356
357/**
Lorenzo Colitti511ab052009-09-19 11:06:31 -0700358 * Converts an InetAddress object and port number to a native address structure.
Lorenzo Colitti511ab052009-09-19 11:06:31 -0700359 */
Elliott Hughesfc354fe2009-10-16 17:25:34 -0700360static bool inetAddressToSocketAddress(JNIEnv *env, jobject inetaddress,
Lorenzo Colitti511ab052009-09-19 11:06:31 -0700361 int port, sockaddr_storage *sockaddress) {
362 // Get the byte array that stores the IP address bytes in the InetAddress.
363 if (inetaddress == NULL) {
Elliott Hughesda4f31d2010-01-28 13:43:39 -0800364 jniThrowNullPointerException(env, NULL);
Elliott Hughesfc354fe2009-10-16 17:25:34 -0700365 return false;
Lorenzo Colitti511ab052009-09-19 11:06:31 -0700366 }
367 jbyteArray addressBytes =
368 reinterpret_cast<jbyteArray>(env->GetObjectField(inetaddress,
369 gCachedFields.iaddr_ipaddress));
370
371 return byteArrayToSocketAddress(env, addressBytes, port, sockaddress);
372}
373
374/**
Lorenzo Colitti511ab052009-09-19 11:06:31 -0700375 * Convert a Java byte array representing an IP address to a Java string.
376 *
377 * @param addressByteArray the byte array to convert.
378 *
379 * @return a string with the textual representation of the address.
Lorenzo Colitti511ab052009-09-19 11:06:31 -0700380 */
Elliott Hughesd9d26302010-03-15 16:40:21 -0700381static jstring osNetworkSystem_byteArrayToIpString(JNIEnv* env, jobject,
Lorenzo Colitti511ab052009-09-19 11:06:31 -0700382 jbyteArray byteArray) {
Lorenzo Colitti511ab052009-09-19 11:06:31 -0700383 if (byteArray == NULL) {
Elliott Hughesda4f31d2010-01-28 13:43:39 -0800384 jniThrowNullPointerException(env, NULL);
Lorenzo Colitti511ab052009-09-19 11:06:31 -0700385 return NULL;
386 }
Elliott Hughesb150dcd2009-10-20 22:58:23 -0700387 sockaddr_storage ss;
Elliott Hughesfc354fe2009-10-16 17:25:34 -0700388 if (!byteArrayToSocketAddress(env, byteArray, 0, &ss)) {
Lorenzo Colitti511ab052009-09-19 11:06:31 -0700389 return NULL;
390 }
Elliott Hughesa9a57f22009-10-30 17:54:32 -0700391 // TODO: getnameinfo seems to want its length parameter to be exactly
392 // sizeof(sockaddr_in) for an IPv4 address and sizeof (sockaddr_in6) for an
393 // IPv6 address. Fix getnameinfo so it accepts sizeof(sockaddr_storage), and
394 // then remove this hack.
395 int sa_size;
396 if (ss.ss_family == AF_INET) {
397 sa_size = sizeof(sockaddr_in);
398 } else if (ss.ss_family == AF_INET6) {
399 sa_size = sizeof(sockaddr_in6);
400 } else {
401 jniThrowBadAddressFamily(env);
402 return NULL;
403 }
Lorenzo Colitti511ab052009-09-19 11:06:31 -0700404 char ipString[INET6_ADDRSTRLEN];
Elliott Hughesa9a57f22009-10-30 17:54:32 -0700405 int rc = getnameinfo(reinterpret_cast<sockaddr*>(&ss), sa_size,
406 ipString, sizeof(ipString), NULL, 0, NI_NUMERICHOST);
407 if (rc != 0) {
408 jniThrowException(env, "java/net/UnknownHostException", gai_strerror(rc));
Lorenzo Colitti511ab052009-09-19 11:06:31 -0700409 return NULL;
410 }
411 return env->NewStringUTF(ipString);
412}
413
414/**
Lorenzo Colittie8596902009-09-18 15:25:06 -0700415 * Convert a Java string representing an IP address to a Java byte array.
416 * The formats accepted are:
417 * - IPv4:
418 * - 1.2.3.4
419 * - 1.2.4
420 * - 1.4
421 * - 4
422 * - IPv6
423 * - Compressed form (2001:db8::1)
424 * - Uncompressed form (2001:db8:0:0:0:0:0:1)
425 * - IPv4-compatible (::192.0.2.0)
426 * - With an embedded IPv4 address (2001:db8::192.0.2.0).
427 * IPv6 addresses may appear in square brackets.
428 *
429 * @param addressByteArray the byte array to convert.
430 *
431 * @return a string with the textual representation of the address.
432 *
433 * @throws UnknownHostException the IP address was invalid.
434 */
Elliott Hughesd9d26302010-03-15 16:40:21 -0700435static jbyteArray osNetworkSystem_ipStringToByteArray(JNIEnv* env, jobject,
Lorenzo Colittie8596902009-09-18 15:25:06 -0700436 jstring javaString) {
437 if (javaString == NULL) {
Elliott Hughesda4f31d2010-01-28 13:43:39 -0800438 jniThrowNullPointerException(env, NULL);
Lorenzo Colitti6dbbfbd2009-10-02 12:45:21 -0700439 return NULL;
Lorenzo Colittie8596902009-09-18 15:25:06 -0700440 }
441
Elliott Hughes845ce3c2009-11-13 17:07:00 -0800442 // Convert the String to UTF bytes.
Elliott Hughesc00b8a42009-11-11 21:55:42 -0800443 size_t byteCount = env->GetStringUTFLength(javaString);
Elliott Hughes845ce3c2009-11-13 17:07:00 -0800444 LocalArray<INET6_ADDRSTRLEN> bytes(byteCount + 1);
445 char* ipString = &bytes[0];
Elliott Hughesc00b8a42009-11-11 21:55:42 -0800446 env->GetStringUTFRegion(javaString, 0, env->GetStringLength(javaString), ipString);
Lorenzo Colittie8596902009-09-18 15:25:06 -0700447
448 // Accept IPv6 addresses (only) in square brackets for compatibility.
Elliott Hughesc00b8a42009-11-11 21:55:42 -0800449 if (ipString[0] == '[' && ipString[byteCount - 1] == ']' &&
Carl Shapiro22ff07e2010-03-16 15:18:53 -0700450 strchr(ipString, ':') != NULL) {
Elliott Hughesc00b8a42009-11-11 21:55:42 -0800451 memmove(ipString, ipString + 1, byteCount - 2);
452 ipString[byteCount - 2] = '\0';
Lorenzo Colittie8596902009-09-18 15:25:06 -0700453 }
454
455 jbyteArray result = NULL;
Lorenzo Colitti6dbbfbd2009-10-02 12:45:21 -0700456 addrinfo hints;
Lorenzo Colittie8596902009-09-18 15:25:06 -0700457 memset(&hints, 0, sizeof(hints));
458 hints.ai_flags = AI_NUMERICHOST;
Lorenzo Colitti6dbbfbd2009-10-02 12:45:21 -0700459
Elliott Hughesf5eafc52009-11-05 10:00:02 -0800460 sockaddr_storage ss;
461 memset(&ss, 0, sizeof(ss));
462
463 addrinfo* res = NULL;
Lorenzo Colittie8596902009-09-18 15:25:06 -0700464 int ret = getaddrinfo(ipString, NULL, &hints, &res);
465 if (ret == 0 && res) {
Elliott Hughesf5eafc52009-11-05 10:00:02 -0800466 // Convert IPv4-mapped addresses to IPv4 addresses.
467 // The RI states "Java will never return an IPv4-mapped address".
468 sockaddr_in6* sin6 = reinterpret_cast<sockaddr_in6*>(res->ai_addr);
469 if (res->ai_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
470 sockaddr_in* sin = reinterpret_cast<sockaddr_in*>(&ss);
471 sin->sin_family = AF_INET;
472 sin->sin_port = sin6->sin6_port;
473 memcpy(&sin->sin_addr.s_addr, &sin6->sin6_addr.s6_addr[12], 4);
474 result = socketAddressToByteArray(env, &ss);
Lorenzo Colittie8596902009-09-18 15:25:06 -0700475 } else {
Elliott Hughesf5eafc52009-11-05 10:00:02 -0800476 result = socketAddressToByteArray(env, reinterpret_cast<sockaddr_storage*>(res->ai_addr));
Lorenzo Colittie8596902009-09-18 15:25:06 -0700477 }
478 } else {
479 // For backwards compatibility, deal with address formats that
480 // getaddrinfo does not support. For example, 1.2.3, 1.3, and even 3 are
481 // valid IPv4 addresses according to the Java API. If getaddrinfo fails,
482 // try to use inet_aton.
Elliott Hughesf5eafc52009-11-05 10:00:02 -0800483 sockaddr_in* sin = reinterpret_cast<sockaddr_in*>(&ss);
484 if (inet_aton(ipString, &sin->sin_addr)) {
485 sin->sin_family = AF_INET;
486 sin->sin_port = 0;
487 result = socketAddressToByteArray(env, &ss);
Lorenzo Colittie8596902009-09-18 15:25:06 -0700488 }
489 }
490
491 if (res) {
492 freeaddrinfo(res);
493 }
494
Elliott Hughesb375c0c2010-05-04 18:06:21 -0700495 if (!result) {
Lorenzo Colittie8596902009-09-18 15:25:06 -0700496 env->ExceptionClear();
Elliott Hughesb375c0c2010-05-04 18:06:21 -0700497 jniThrowException(env, "java/net/UnknownHostException", gai_strerror(ret));
Lorenzo Colittie8596902009-09-18 15:25:06 -0700498 }
499
500 return result;
501}
502
503/**
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800504 * Answer a new java.lang.Boolean object.
505 *
506 * @param env pointer to the JNI library
507 * @param anInt the Boolean constructor argument
508 *
509 * @return the new Boolean
510 */
Elliott Hughesc83e55b2009-10-06 10:18:34 -0700511static jobject newJavaLangBoolean(JNIEnv * env, jint anInt) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800512 jclass tempClass;
513 jmethodID tempMethod;
514
515 tempClass = gCachedFields.boolean_class;
516 tempMethod = gCachedFields.boolean_class_init;
517 return env->NewObject(tempClass, tempMethod, (jboolean) (anInt != 0));
518}
519
520/**
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800521 * Answer a new java.lang.Integer object.
522 *
523 * @param env pointer to the JNI library
524 * @param anInt the Integer constructor argument
525 *
526 * @return the new Integer
527 */
Elliott Hughesa9a57f22009-10-30 17:54:32 -0700528static jobject newJavaLangInteger(JNIEnv* env, jint anInt) {
529 return env->NewObject(gCachedFields.integer_class, gCachedFields.integer_class_init, anInt);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800530}
531
Elliott Hughes42d8ce72009-09-17 18:32:07 -0700532// Converts a number of milliseconds to a timeval.
533static timeval toTimeval(long ms) {
534 timeval tv;
535 tv.tv_sec = ms / 1000;
536 tv.tv_usec = (ms - tv.tv_sec*1000) * 1000;
537 return tv;
538}
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800539
Elliott Hughes42d8ce72009-09-17 18:32:07 -0700540// Converts a timeval to a number of milliseconds.
541static long toMs(const timeval& tv) {
542 return tv.tv_sec * 1000 + tv.tv_usec / 1000;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800543}
544
545/**
546 * Query OS for timestamp.
547 * Retrieve the current value of system clock and convert to milliseconds.
548 *
549 * @param[in] portLibrary The port library.
550 *
551 * @return 0 on failure, time value in milliseconds on success.
552 * @deprecated Use @ref time_hires_clock and @ref time_hires_delta
553 *
554 * technically, this should return I_64 since both timeval.tv_sec and
555 * timeval.tv_usec are long
556 */
557
558static int time_msec_clock() {
Elliott Hughes42d8ce72009-09-17 18:32:07 -0700559 timeval tp;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800560 struct timezone tzp;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800561 gettimeofday(&tp, &tzp);
Elliott Hughes42d8ce72009-09-17 18:32:07 -0700562 return toMs(tp);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800563}
564
Elliott Hughesba563a42009-11-05 13:50:06 -0800565static int selectWait(int fd, int uSecTime) {
566 timeval tv;
567 timeval* tvp;
568 if (uSecTime >= 0) {
569 /* Use a timeout if uSecTime >= 0 */
570 memset(&tv, 0, sizeof(tv));
571 tv.tv_usec = uSecTime;
572 tvp = &tv;
573 } else {
574 /* Infinite timeout if uSecTime < 0 */
575 tvp = NULL;
576 }
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800577
Elliott Hughesba563a42009-11-05 13:50:06 -0800578 fd_set readFds;
579 FD_ZERO(&readFds);
580 FD_SET(fd, &readFds);
581 int result = select(fd + 1, &readFds, NULL, NULL, tvp);
582 if (result == -1) {
Elliott Hughesb375c0c2010-05-04 18:06:21 -0700583 return -errno;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800584 } else if (result == 0) {
Elliott Hughesb375c0c2010-05-04 18:06:21 -0700585 return -ETIMEDOUT;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800586 }
587 return result;
588}
589
Elliott Hughes24912e02009-10-19 16:36:13 -0700590// Returns 0 on success, not obviously meaningful negative values on error.
Elliott Hughesba563a42009-11-05 13:50:06 -0800591static int pollSelectWait(JNIEnv *env, jobject fileDescriptor, int timeout) {
Elliott Hughes24912e02009-10-19 16:36:13 -0700592 /* now try reading the socket for the timeout.
593 * if timeout is 0 try forever until the sockets gets ready or until an
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800594 * exception occurs.
595 */
596 int pollTimeoutUSec = 100000, pollMsec = 100;
597 int finishTime = 0;
598 int timeLeft = timeout;
Elliott Hughesb375c0c2010-05-04 18:06:21 -0700599 bool hasTimeout = timeout > 0;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800600 int result = 0;
601 int handle;
602
603 if (hasTimeout) {
604 finishTime = time_msec_clock() + timeout;
605 }
606
607 int poll = 1;
608
609 while (poll) { /* begin polling loop */
610
611 /*
612 * Fetch the handle every time in case the socket is closed.
613 */
614 handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
Elliott Hughes24912e02009-10-19 16:36:13 -0700615 if (handle == -1) {
Elliott Hughesa9a57f22009-10-30 17:54:32 -0700616 jniThrowSocketException(env, EINTR);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800617 return -1;
618 }
619
620 if (hasTimeout) {
621
622 if (timeLeft - 10 < pollMsec) {
623 pollTimeoutUSec = timeLeft <= 0 ? 0 : (timeLeft * 1000);
624 }
625
Elliott Hughesba563a42009-11-05 13:50:06 -0800626 result = selectWait(handle, pollTimeoutUSec);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800627
628 /*
629 * because we are polling at a time smaller than timeout
630 * (presumably) lets treat an interrupt and timeout the same - go
631 * see if we're done timewise, and then just try again if not.
632 */
Elliott Hughesb375c0c2010-05-04 18:06:21 -0700633 if (result == -ETIMEDOUT || result == -EINTR) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800634 timeLeft = finishTime - time_msec_clock();
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800635 if (timeLeft <= 0) {
636 /*
637 * Always throw the "timeout" message because that is
638 * effectively what has happened, even if we happen to
639 * have been interrupted.
640 */
Elliott Hughesba563a42009-11-05 13:50:06 -0800641 jniThrowSocketTimeoutException(env, ETIMEDOUT);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800642 } else {
643 continue; // try again
644 }
645
Elliott Hughesb375c0c2010-05-04 18:06:21 -0700646 } else if (result < 0) {
647 jniThrowSocketException(env, -result);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800648 }
649 poll = 0;
650
651 } else { /* polling with no timeout (why would you do this?)*/
652
Elliott Hughesba563a42009-11-05 13:50:06 -0800653 result = selectWait(handle, pollTimeoutUSec);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800654
655 /*
656 * if interrupted (or a timeout) just retry
657 */
Elliott Hughesb375c0c2010-05-04 18:06:21 -0700658 if (result == -ETIMEDOUT || result == -EINTR) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800659 continue; // try again
Elliott Hughesb375c0c2010-05-04 18:06:21 -0700660 } else if (result < 0) {
661 jniThrowSocketException(env, -result);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800662 }
663 poll = 0;
664 }
665 } /* end polling loop */
666
667 return result;
668}
669
670/**
Lorenzo Colittidcfdc982009-06-15 11:02:24 -0700671 * Wrapper for connect() that converts IPv4 addresses to IPv4-mapped IPv6
672 * addresses if necessary.
673 *
Elliott Hughesb150dcd2009-10-20 22:58:23 -0700674 * @param socket the file descriptor of the socket to connect
Lorenzo Colittidcfdc982009-06-15 11:02:24 -0700675 * @param socketAddress the address to connect to
676 */
Elliott Hughesf5eafc52009-11-05 10:00:02 -0800677static int doConnect(int fd, const sockaddr_storage* socketAddress) {
Elliott Hughes722a27e2010-03-05 20:37:25 -0800678 const CompatibleSocketAddress compatibleAddress(fd, *socketAddress, true);
679 return TEMP_FAILURE_RETRY(connect(fd, compatibleAddress.get(), sizeof(sockaddr_storage)));
Lorenzo Colittidcfdc982009-06-15 11:02:24 -0700680}
681
682/**
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800683 * Establish a connection to a peer with a timeout. This function is called
684 * repeatedly in order to carry out the connect and to allow other tasks to
685 * proceed on certain platforms. The caller must first call with
Elliott Hughesb375c0c2010-05-04 18:06:21 -0700686 * step = SOCKET_STEP_START, if the result is -EINPROGRESS it will then
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800687 * call it with step = CHECK until either another error or 0 is returned to
688 * indicate the connect is complete. Each time the function should sleep for no
689 * more than timeout milliseconds. If the connect succeeds or an error occurs,
690 * the caller must always end the process by calling the function with
691 * step = SOCKET_STEP_DONE
692 *
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800693 * @param[in] timeout the timeout in milliseconds. If timeout is negative,
694 * perform a block operation.
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800695 *
Elliott Hughesb375c0c2010-05-04 18:06:21 -0700696 * @return 0, if no errors occurred, otherwise -errno. TODO: use +errno.
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800697 */
Elliott Hughesb375c0c2010-05-04 18:06:21 -0700698static int sockConnectWithTimeout(int fd, const sockaddr_storage& addr, int timeout, unsigned int step, selectFDSet* context) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800699 int errorVal;
700 socklen_t errorValLen = sizeof(int);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800701
Elliott Hughesb375c0c2010-05-04 18:06:21 -0700702 if (step == SOCKET_STEP_START) {
703 context->sock = fd;
704 context->nfds = fd + 1;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800705
Elliott Hughese9bb15a2009-09-30 13:26:11 -0700706 /* set the socket to non-blocking */
707 int block = JNI_TRUE;
Elliott Hughesb375c0c2010-05-04 18:06:21 -0700708 if (ioctl(fd, FIONBIO, &block) == -1) {
709 LOGE("ioctl(fd, FIONBIO, true) failed: %s %i", strerror(errno), errno);
710 return -errno;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800711 }
712
Elliott Hughesb375c0c2010-05-04 18:06:21 -0700713 if (doConnect(fd, &addr) == -1) {
714 return -errno;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800715 }
716
717 /* we connected right off the bat so just return */
Elliott Hughesb375c0c2010-05-04 18:06:21 -0700718 return 0;
719 } else if (step == SOCKET_STEP_CHECK) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800720 /* now check if we have connected yet */
721
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800722 /*
723 * set the timeout value to be used. Because on some unix platforms we
724 * don't get notified when a socket is closed we only sleep for 100ms
725 * at a time
Elliott Hughes42d8ce72009-09-17 18:32:07 -0700726 *
727 * TODO: is this relevant for Android?
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800728 */
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800729 if (timeout > 100) {
Elliott Hughes42d8ce72009-09-17 18:32:07 -0700730 timeout = 100;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800731 }
Elliott Hughes42d8ce72009-09-17 18:32:07 -0700732 timeval passedTimeout(toTimeval(timeout));
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800733
734 /* initialize the FD sets for the select */
735 FD_ZERO(&(context->exceptionSet));
736 FD_ZERO(&(context->writeSet));
737 FD_ZERO(&(context->readSet));
738 FD_SET(context->sock, &(context->writeSet));
739 FD_SET(context->sock, &(context->readSet));
740 FD_SET(context->sock, &(context->exceptionSet));
741
Elliott Hughesb375c0c2010-05-04 18:06:21 -0700742 int rc = TEMP_FAILURE_RETRY(select(context->nfds,
743 &(context->readSet), &(context->writeSet), &(context->exceptionSet),
744 timeout >= 0 ? &passedTimeout : NULL));
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800745
746 /* if there is at least one descriptor ready to be checked */
Elliott Hughesb375c0c2010-05-04 18:06:21 -0700747 if (rc > 0) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800748 /* if the descriptor is in the write set we connected or failed */
749 if (FD_ISSET(context->sock, &(context->writeSet))) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800750 if (!FD_ISSET(context->sock, &(context->readSet))) {
751 /* ok we have connected ok */
752 return 0;
753 } else {
754 /* ok we have more work to do to figure it out */
Elliott Hughesb375c0c2010-05-04 18:06:21 -0700755 if (getsockopt(context->sock, SOL_SOCKET, SO_ERROR, &errorVal, &errorValLen) >= 0) {
756 return errorVal ? -errorVal : 0;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800757 } else {
Elliott Hughesb375c0c2010-05-04 18:06:21 -0700758 return -errno;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800759 }
760 }
761 }
762
763 /* if the descriptor is in the exception set the connect failed */
764 if (FD_ISSET(context->sock, &(context->exceptionSet))) {
Elliott Hughesb375c0c2010-05-04 18:06:21 -0700765 if (getsockopt(context->sock, SOL_SOCKET, SO_ERROR, &errorVal, &errorValLen) >= 0) {
766 return errorVal ? -errorVal : 0;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800767 }
Elliott Hughesb375c0c2010-05-04 18:06:21 -0700768 return -errno;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800769 }
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800770 } else if (rc < 0) {
Elliott Hughesb375c0c2010-05-04 18:06:21 -0700771 /* some other error occurred */
772 return -errno;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800773 }
774
775 /*
776 * if we get here the timeout expired or the connect had not yet
777 * completed just indicate that the connect is not yet complete
778 */
Elliott Hughesb375c0c2010-05-04 18:06:21 -0700779 return -EINPROGRESS;
780 } else if (step == SOCKET_STEP_DONE) {
781 /* we are done the connect or an error occurred so clean up */
782 if (fd != -1) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800783 int block = JNI_FALSE;
Elliott Hughesb375c0c2010-05-04 18:06:21 -0700784 ioctl(fd, FIONBIO, &block);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800785 }
786 return 0;
787 }
Elliott Hughesb375c0c2010-05-04 18:06:21 -0700788 return -EFAULT;
Lorenzo Colitti65663e12009-05-26 15:51:50 -0700789}
790
Dan Bornsteinfef88752009-11-04 15:34:14 -0800791#ifdef ENABLE_MULTICAST
Lorenzo Colitti65663e12009-05-26 15:51:50 -0700792/*
793 * Find the interface index that was set for this socket by the IP_MULTICAST_IF
794 * or IPV6_MULTICAST_IF socket option.
795 *
796 * @param socket the socket to examine
797 *
798 * @return the interface index, or -1 on failure
799 *
800 * @note on internal failure, the errno variable will be set appropriately
801 */
802static int interfaceIndexFromMulticastSocket(int socket) {
803 int family = getSocketAddressFamily(socket);
Lorenzo Colitti65663e12009-05-26 15:51:50 -0700804 if (family == AF_INET) {
805 // IP_MULTICAST_IF returns a pointer to a struct ip_mreqn.
806 struct ip_mreqn tempRequest;
Elliott Hughesa9a57f22009-10-30 17:54:32 -0700807 socklen_t requestLength = sizeof(tempRequest);
Elliott Hughes4d8e9332010-05-03 14:31:03 -0700808 int rc = getsockopt(socket, IPPROTO_IP, IP_MULTICAST_IF, &tempRequest, &requestLength);
809 return (rc == -1) ? -1 : tempRequest.imr_ifindex;
Lorenzo Colitti65663e12009-05-26 15:51:50 -0700810 } else if (family == AF_INET6) {
811 // IPV6_MULTICAST_IF returns a pointer to an integer.
Elliott Hughes4d8e9332010-05-03 14:31:03 -0700812 int interfaceIndex;
Elliott Hughesa9a57f22009-10-30 17:54:32 -0700813 socklen_t requestLength = sizeof(interfaceIndex);
Elliott Hughes4d8e9332010-05-03 14:31:03 -0700814 int rc = getsockopt(socket, IPPROTO_IPV6, IPV6_MULTICAST_IF, &interfaceIndex, &requestLength);
815 return (rc == -1) ? -1 : interfaceIndex;
Lorenzo Colitti65663e12009-05-26 15:51:50 -0700816 } else {
817 errno = EAFNOSUPPORT;
818 return -1;
819 }
Lorenzo Colitti65663e12009-05-26 15:51:50 -0700820}
821
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800822/**
823 * Join/Leave the nominated multicast group on the specified socket.
824 * Implemented by setting the multicast 'add membership'/'drop membership'
825 * option at the HY_IPPROTO_IP level on the socket.
826 *
827 * Implementation note for multicast sockets in general:
828 *
829 * - This code is untested, because at the time of this writing multicast can't
830 * be properly tested on Android due to GSM routing restrictions. So it might
831 * or might not work.
832 *
833 * - The REUSEPORT socket option that Harmony employs is not supported on Linux
834 * and thus also not supported on Android. It's is not needed for multicast
835 * to work anyway (REUSEADDR should suffice).
836 *
837 * @param env pointer to the JNI library.
838 * @param socketP pointer to the hysocket to join/leave on.
839 * @param optVal pointer to the InetAddress, the multicast group to join/drop.
840 *
841 * @exception SocketException if an error occurs during the call
842 */
Elliott Hughes4d8e9332010-05-03 14:31:03 -0700843static void mcastAddDropMembership(JNIEnv *env, int handle, jobject optVal, int setSockOptVal) {
Lorenzo Colitti65663e12009-05-26 15:51:50 -0700844 struct sockaddr_storage sockaddrP;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800845 int result;
Lorenzo Colitti65663e12009-05-26 15:51:50 -0700846 // By default, let the system decide which interface to use.
847 int interfaceIndex = 0;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800848
849 /*
Lorenzo Colitti65663e12009-05-26 15:51:50 -0700850 * Check whether we are getting an InetAddress or an Generic IPMreq. For now
851 * we support both so that we will not break the tests. If an InetAddress
852 * is passed in, only support IPv4 as obtaining an interface from an
853 * InetAddress is complex and should be done by the Java caller.
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800854 */
Elliott Hughes4d8e9332010-05-03 14:31:03 -0700855 if (env->IsInstanceOf(optVal, gCachedFields.iaddr_class)) {
Lorenzo Colitti65663e12009-05-26 15:51:50 -0700856 /*
857 * optVal is an InetAddress. Construct a multicast request structure
858 * from this address. Support IPv4 only.
859 */
860 struct ip_mreqn multicastRequest;
861 socklen_t length = sizeof(multicastRequest);
862 memset(&multicastRequest, 0, length);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800863
Elliott Hughes4d8e9332010-05-03 14:31:03 -0700864 interfaceIndex = interfaceIndexFromMulticastSocket(handle);
865 multicastRequest.imr_ifindex = interfaceIndex;
866 if (interfaceIndex == -1) {
867 jniThrowSocketException(env, errno);
868 return;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800869 }
870
Lorenzo Colitti65663e12009-05-26 15:51:50 -0700871 // Convert the inetAddress to an IPv4 address structure.
Elliott Hughesfc354fe2009-10-16 17:25:34 -0700872 if (!inetAddressToSocketAddress(env, optVal, 0, &sockaddrP)) {
Lorenzo Colitti65663e12009-05-26 15:51:50 -0700873 return;
Elliott Hughesfc354fe2009-10-16 17:25:34 -0700874 }
Lorenzo Colitti65663e12009-05-26 15:51:50 -0700875 if (sockaddrP.ss_family != AF_INET) {
Elliott Hughesa9a57f22009-10-30 17:54:32 -0700876 jniThrowSocketException(env, EAFNOSUPPORT);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800877 return;
878 }
Lorenzo Colitti65663e12009-05-26 15:51:50 -0700879 struct sockaddr_in *sin = (struct sockaddr_in *) &sockaddrP;
880 multicastRequest.imr_multiaddr = sin->sin_addr;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800881
Dan Bornstein033eddd2009-10-29 10:15:42 -0700882 result = setsockopt(handle, IPPROTO_IP, setSockOptVal,
Lorenzo Colitti65663e12009-05-26 15:51:50 -0700883 &multicastRequest, length);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800884 if (0 != result) {
Elliott Hughesa9a57f22009-10-30 17:54:32 -0700885 jniThrowSocketException(env, errno);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800886 return;
887 }
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800888 } else {
Lorenzo Colitti65663e12009-05-26 15:51:50 -0700889 /*
890 * optVal is a GenericIPMreq object. Extract the relevant fields from
891 * it and construct a multicast request structure from these. Support
892 * both IPv4 and IPv6.
893 */
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800894
Lorenzo Colitti65663e12009-05-26 15:51:50 -0700895 // Get the multicast address to join or leave.
Elliott Hughes4d8e9332010-05-03 14:31:03 -0700896 jclass cls = env->GetObjectClass(optVal);
897 jfieldID multiaddrID = env->GetFieldID(cls, "multiaddr", "Ljava/net/InetAddress;");
898 jobject multiaddr = env->GetObjectField(optVal, multiaddrID);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800899
Lorenzo Colitti65663e12009-05-26 15:51:50 -0700900 // Get the interface index to use.
Elliott Hughes4d8e9332010-05-03 14:31:03 -0700901 jfieldID interfaceIdxID = env->GetFieldID(cls, "interfaceIdx", "I");
902 interfaceIndex = env->GetIntField(optVal, interfaceIdxID);
Elliott Hughesb5fc5ec2009-11-19 18:32:43 -0800903 LOGI("mcastAddDropMembership interfaceIndex=%i", interfaceIndex);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800904
Elliott Hughesfc354fe2009-10-16 17:25:34 -0700905 if (!inetAddressToSocketAddress(env, multiaddr, 0, &sockaddrP)) {
Lorenzo Colitti65663e12009-05-26 15:51:50 -0700906 return;
Elliott Hughesfc354fe2009-10-16 17:25:34 -0700907 }
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800908
Lorenzo Colittie3259182009-09-30 15:49:22 -0700909 int family = getSocketAddressFamily(handle);
910
911 // Handle IPv4 multicast on an IPv6 socket.
912 if (family == AF_INET6 && sockaddrP.ss_family == AF_INET) {
913 family = AF_INET;
914 }
915
Lorenzo Colitti65663e12009-05-26 15:51:50 -0700916 struct ip_mreqn ipv4Request;
917 struct ipv6_mreq ipv6Request;
918 void *multicastRequest;
919 socklen_t requestLength;
920 int level;
Lorenzo Colitti65663e12009-05-26 15:51:50 -0700921 switch (family) {
922 case AF_INET:
923 requestLength = sizeof(ipv4Request);
924 memset(&ipv4Request, 0, requestLength);
925 ipv4Request.imr_multiaddr =
926 ((struct sockaddr_in *) &sockaddrP)->sin_addr;
927 ipv4Request.imr_ifindex = interfaceIndex;
928 multicastRequest = &ipv4Request;
Dan Bornstein033eddd2009-10-29 10:15:42 -0700929 level = IPPROTO_IP;
Lorenzo Colitti65663e12009-05-26 15:51:50 -0700930 break;
931 case AF_INET6:
Lorenzo Colittie3259182009-09-30 15:49:22 -0700932 // setSockOptVal is passed in by the caller and may be IPv4-only
933 if (setSockOptVal == IP_ADD_MEMBERSHIP) {
934 setSockOptVal = IPV6_ADD_MEMBERSHIP;
935 }
936 if (setSockOptVal == IP_DROP_MEMBERSHIP) {
Elliott Hughes18f8a702010-04-26 13:45:16 -0700937 setSockOptVal = IPV6_DROP_MEMBERSHIP;
Lorenzo Colittie3259182009-09-30 15:49:22 -0700938 }
Lorenzo Colitti65663e12009-05-26 15:51:50 -0700939 requestLength = sizeof(ipv6Request);
940 memset(&ipv6Request, 0, requestLength);
941 ipv6Request.ipv6mr_multiaddr =
942 ((struct sockaddr_in6 *) &sockaddrP)->sin6_addr;
Lorenzo Colittic0ff7792009-06-11 19:35:46 -0700943 ipv6Request.ipv6mr_interface = interfaceIndex;
Lorenzo Colitti65663e12009-05-26 15:51:50 -0700944 multicastRequest = &ipv6Request;
Dan Bornstein033eddd2009-10-29 10:15:42 -0700945 level = IPPROTO_IPV6;
Lorenzo Colitti65663e12009-05-26 15:51:50 -0700946 break;
947 default:
Elliott Hughesa9a57f22009-10-30 17:54:32 -0700948 jniThrowSocketException(env, EAFNOSUPPORT);
949 return;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800950 }
951
952 /* join/drop the multicast address */
Lorenzo Colitti65663e12009-05-26 15:51:50 -0700953 result = setsockopt(handle, level, setSockOptVal, multicastRequest,
954 requestLength);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800955 if (0 != result) {
Elliott Hughesa9a57f22009-10-30 17:54:32 -0700956 jniThrowSocketException(env, errno);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800957 return;
958 }
959 }
960}
Dan Bornsteinfef88752009-11-04 15:34:14 -0800961#endif // def ENABLE_MULTICAST
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800962
Elliott Hughes7861ea92009-11-12 12:23:05 -0800963static bool initCachedFields(JNIEnv* env) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800964 memset(&gCachedFields, 0, sizeof(gCachedFields));
Lorenzo Colitti1790dd32009-09-08 18:30:56 -0700965 struct CachedFields *c = &gCachedFields;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800966
Lorenzo Colitti1790dd32009-09-08 18:30:56 -0700967 struct classInfo {
968 jclass *clazz;
969 const char *name;
970 } classes[] = {
971 {&c->iaddr_class, "java/net/InetAddress"},
972 {&c->i4addr_class, "java/net/Inet4Address"},
973 {&c->genericipmreq_class, "org/apache/harmony/luni/net/GenericIPMreq"},
974 {&c->integer_class, "java/lang/Integer"},
975 {&c->boolean_class, "java/lang/Boolean"},
976 {&c->byte_class, "java/lang/Byte"},
Lorenzo Colitti1790dd32009-09-08 18:30:56 -0700977 {&c->socketimpl_class, "java/net/SocketImpl"},
978 {&c->dpack_class, "java/net/DatagramPacket"}
979 };
980 for (unsigned i = 0; i < sizeof(classes) / sizeof(classes[0]); i++) {
981 classInfo c = classes[i];
982 jclass tempClass = env->FindClass(c.name);
Elliott Hughes7861ea92009-11-12 12:23:05 -0800983 if (tempClass == NULL) return false;
Lorenzo Colitti1790dd32009-09-08 18:30:56 -0700984 *c.clazz = (jclass) env->NewGlobalRef(tempClass);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800985 }
986
Lorenzo Colitti1790dd32009-09-08 18:30:56 -0700987 struct methodInfo {
988 jmethodID *method;
989 jclass clazz;
990 const char *name;
991 const char *signature;
992 bool isStatic;
993 } methods[] = {
994 {&c->i4addr_class_init, c->i4addr_class, "<init>", "([B)V", false},
995 {&c->integer_class_init, c->integer_class, "<init>", "(I)V", false},
996 {&c->boolean_class_init, c->boolean_class, "<init>", "(Z)V", false},
Lorenzo Colitti1790dd32009-09-08 18:30:56 -0700997 {&c->iaddr_getbyaddress, c->iaddr_class, "getByAddress",
998 "([B)Ljava/net/InetAddress;", true}
999 };
1000 for (unsigned i = 0; i < sizeof(methods) / sizeof(methods[0]); i++) {
1001 methodInfo m = methods[i];
1002 if (m.isStatic) {
1003 *m.method = env->GetStaticMethodID(m.clazz, m.name, m.signature);
1004 } else {
1005 *m.method = env->GetMethodID(m.clazz, m.name, m.signature);
1006 }
Elliott Hughes7861ea92009-11-12 12:23:05 -08001007 if (*m.method == NULL) return false;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001008 }
1009
Lorenzo Colitti1790dd32009-09-08 18:30:56 -07001010 struct fieldInfo {
1011 jfieldID *field;
1012 jclass clazz;
1013 const char *name;
1014 const char *type;
1015 } fields[] = {
1016 {&c->iaddr_ipaddress, c->iaddr_class, "ipaddress", "[B"},
1017 {&c->integer_class_value, c->integer_class, "value", "I"},
1018 {&c->boolean_class_value, c->boolean_class, "value", "Z"},
1019 {&c->byte_class_value, c->byte_class, "value", "B"},
1020 {&c->socketimpl_port, c->socketimpl_class, "port", "I"},
1021 {&c->socketimpl_address, c->socketimpl_class, "address",
1022 "Ljava/net/InetAddress;"},
1023 {&c->dpack_address, c->dpack_class, "address",
1024 "Ljava/net/InetAddress;"},
1025 {&c->dpack_port, c->dpack_class, "port", "I"},
1026 {&c->dpack_length, c->dpack_class, "length", "I"}
1027 };
1028 for (unsigned i = 0; i < sizeof(fields) / sizeof(fields[0]); i++) {
1029 fieldInfo f = fields[i];
1030 *f.field = env->GetFieldID(f.clazz, f.name, f.type);
Elliott Hughes7861ea92009-11-12 12:23:05 -08001031 if (*f.field == NULL) return false;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001032 }
Elliott Hughes7861ea92009-11-12 12:23:05 -08001033 return true;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001034}
1035
Lorenzo Colitti65663e12009-05-26 15:51:50 -07001036/**
1037 * Helper function to create a socket of the specified type and bind it to a
1038 * Java file descriptor.
1039 *
1040 * @param fileDescriptor the file descriptor to bind the socket to
1041 * @param type the socket type to create, e.g., SOCK_STREAM
Lorenzo Colitti2d97a2b2009-09-04 13:35:10 -07001042 * @throws SocketException an error occurred when creating the socket
Lorenzo Colitti65663e12009-05-26 15:51:50 -07001043 *
Lorenzo Colitti2d97a2b2009-09-04 13:35:10 -07001044 * @return the socket file descriptor. On failure, an exception is thrown and
1045 * a negative value is returned.
Lorenzo Colitti65663e12009-05-26 15:51:50 -07001046 *
1047 */
Elliott Hughesb375c0c2010-05-04 18:06:21 -07001048static int createSocketFileDescriptor(JNIEnv* env, jobject fileDescriptor, int type) {
Lorenzo Colitti65663e12009-05-26 15:51:50 -07001049 if (fileDescriptor == NULL) {
Elliott Hughesda4f31d2010-01-28 13:43:39 -08001050 jniThrowNullPointerException(env, NULL);
Lorenzo Colitti65663e12009-05-26 15:51:50 -07001051 errno = EBADF;
1052 return -1;
1053 }
1054
Elliott Hughes722a27e2010-03-05 20:37:25 -08001055 // Try IPv6 but fall back to IPv4...
1056 int sock = socket(PF_INET6, type, 0);
1057 if (sock == -1 && errno == EAFNOSUPPORT) {
Lorenzo Colitti65663e12009-05-26 15:51:50 -07001058 sock = socket(PF_INET, type, 0);
1059 }
Elliott Hughes722a27e2010-03-05 20:37:25 -08001060 if (sock == -1) {
Elliott Hughesa9a57f22009-10-30 17:54:32 -07001061 jniThrowSocketException(env, errno);
Lorenzo Colitti66e35e82009-09-04 11:59:12 -07001062 return sock;
Lorenzo Colitti65663e12009-05-26 15:51:50 -07001063 }
1064 jniSetFileDescriptorOfFD(env, fileDescriptor, sock);
1065 return sock;
1066}
1067
Elliott Hughesd9d26302010-03-15 16:40:21 -07001068static void osNetworkSystem_createStreamSocket(JNIEnv* env, jobject, jobject fileDescriptor, jboolean) {
Lorenzo Colitti65663e12009-05-26 15:51:50 -07001069 createSocketFileDescriptor(env, fileDescriptor, SOCK_STREAM);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001070}
1071
Elliott Hughes4401c752010-05-04 09:47:02 -07001072static void osNetworkSystem_createDatagramSocket(JNIEnv* env, jobject, jobject fileDescriptor, jboolean) {
1073 int fd = createSocketFileDescriptor(env, fileDescriptor, SOCK_DGRAM);
1074#ifdef __linux__
1075 // The RFC (http://tools.ietf.org/rfc/rfc3493.txt) says that IPV6_MULTICAST_HOPS defaults to 1.
1076 // The Linux kernel (at least up to 2.6.32) accidentally defaults to 64 (which would be correct
1077 // for the *unicast* hop limit). See http://www.spinics.net/lists/netdev/msg129022.html.
1078 // When that's fixed, we can remove this code. Until then, we manually set the hop limit on
1079 // IPv6 datagram sockets. (IPv4 is already correct.)
1080 if (fd != -1 && getSocketAddressFamily(fd) == AF_INET6) {
1081 int ttl = 1;
1082 setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof(int));
1083 }
1084#endif
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001085}
1086
Elliott Hughesd9d26302010-03-15 16:40:21 -07001087static jint osNetworkSystem_readDirect(JNIEnv* env, jobject,
Elliott Hughes70882922009-10-21 17:09:13 -07001088 jobject fileDescriptor, jint address, jint count, jint timeout) {
Elliott Hughesb150dcd2009-10-20 22:58:23 -07001089 int fd;
1090 if (!jniGetFd(env, fileDescriptor, fd)) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001091 return 0;
1092 }
1093
Elliott Hughes70882922009-10-21 17:09:13 -07001094 if (timeout != 0) {
Elliott Hughesba563a42009-11-05 13:50:06 -08001095 int result = selectWait(fd, timeout * 1000);
Elliott Hughes70882922009-10-21 17:09:13 -07001096 if (result < 0) {
1097 return 0;
1098 }
Elliott Hughesb150dcd2009-10-20 22:58:23 -07001099 }
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001100
Elliott Hughes70882922009-10-21 17:09:13 -07001101 jbyte* dst = reinterpret_cast<jbyte*>(static_cast<uintptr_t>(address));
Elliott Hughesb375c0c2010-05-04 18:06:21 -07001102 ssize_t bytesReceived = TEMP_FAILURE_RETRY(recv(fd, dst, count, SOCKET_NOFLAGS));
Elliott Hughesb150dcd2009-10-20 22:58:23 -07001103 if (bytesReceived == 0) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001104 return -1;
Elliott Hughesb150dcd2009-10-20 22:58:23 -07001105 } else if (bytesReceived == -1) {
Elliott Hughesd9179c42009-10-26 16:38:13 -07001106 if (errno == EAGAIN || errno == EWOULDBLOCK) {
Elliott Hughes70882922009-10-21 17:09:13 -07001107 // We were asked to read a non-blocking socket with no data
Elliott Hughesd9179c42009-10-26 16:38:13 -07001108 // available, so report "no bytes read".
Elliott Hughes70882922009-10-21 17:09:13 -07001109 return 0;
1110 } else {
Elliott Hughesa9a57f22009-10-30 17:54:32 -07001111 jniThrowSocketException(env, errno);
Elliott Hughes70882922009-10-21 17:09:13 -07001112 return 0;
1113 }
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001114 }
Elliott Hughesb150dcd2009-10-20 22:58:23 -07001115 return bytesReceived;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001116}
1117
Brian Carlstrom44e0e562010-05-06 23:44:16 -07001118static jint osNetworkSystem_readSocketImpl(JNIEnv* env, jclass,
Elliott Hughes70882922009-10-21 17:09:13 -07001119 jobject fileDescriptor, jbyteArray byteArray, jint offset, jint count,
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001120 jint timeout) {
1121 // LOGD("ENTER readSocketImpl");
1122
Elliott Hughes70882922009-10-21 17:09:13 -07001123 jbyte* bytes = env->GetByteArrayElements(byteArray, NULL);
1124 if (bytes == NULL) {
1125 return -1;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001126 }
Elliott Hughes70882922009-10-21 17:09:13 -07001127 jint address =
1128 static_cast<jint>(reinterpret_cast<uintptr_t>(bytes + offset));
Elliott Hughesd9d26302010-03-15 16:40:21 -07001129 int result = osNetworkSystem_readDirect(env, NULL,
Elliott Hughes70882922009-10-21 17:09:13 -07001130 fileDescriptor, address, count, timeout);
1131 env->ReleaseByteArrayElements(byteArray, bytes, 0);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001132 return result;
1133}
1134
Elliott Hughesd9d26302010-03-15 16:40:21 -07001135static jint osNetworkSystem_writeDirect(JNIEnv* env, jobject,
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001136 jobject fileDescriptor, jint address, jint offset, jint count) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001137 if (count <= 0) {
1138 return 0;
1139 }
1140
Elliott Hughesd9179c42009-10-26 16:38:13 -07001141 int fd;
1142 if (!jniGetFd(env, fileDescriptor, fd)) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001143 return 0;
1144 }
1145
Elliott Hughes24912e02009-10-19 16:36:13 -07001146 jbyte* message = reinterpret_cast<jbyte*>(static_cast<uintptr_t>(address + offset));
Elliott Hughesd9179c42009-10-26 16:38:13 -07001147 int bytesSent = send(fd, message, count, SOCKET_NOFLAGS);
1148 if (bytesSent == -1) {
1149 if (errno == EAGAIN || errno == EWOULDBLOCK) {
1150 // We were asked to write to a non-blocking socket, but were told
1151 // it would block, so report "no bytes written".
1152 return 0;
1153 } else {
Elliott Hughesa9a57f22009-10-30 17:54:32 -07001154 jniThrowSocketException(env, errno);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001155 return 0;
1156 }
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001157 }
Elliott Hughesd9179c42009-10-26 16:38:13 -07001158 return bytesSent;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001159}
1160
Elliott Hughesd9d26302010-03-15 16:40:21 -07001161static jint osNetworkSystem_write(JNIEnv* env, jobject,
Elliott Hughesd9179c42009-10-26 16:38:13 -07001162 jobject fileDescriptor, jbyteArray byteArray, jint offset, jint count) {
Elliott Hughesd9179c42009-10-26 16:38:13 -07001163 jbyte* bytes = env->GetByteArrayElements(byteArray, NULL);
1164 if (bytes == NULL) {
1165 return -1;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001166 }
Elliott Hughesd9179c42009-10-26 16:38:13 -07001167 jint address = static_cast<jint>(reinterpret_cast<uintptr_t>(bytes));
Elliott Hughesd9d26302010-03-15 16:40:21 -07001168 int result = osNetworkSystem_writeDirect(env, NULL,
Elliott Hughesd9179c42009-10-26 16:38:13 -07001169 fileDescriptor, address, offset, count);
1170 env->ReleaseByteArrayElements(byteArray, bytes, 0);
The Android Open Source Project5d287a92009-03-18 22:20:24 -07001171 return result;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001172}
1173
Elliott Hughesd9d26302010-03-15 16:40:21 -07001174static void osNetworkSystem_setNonBlocking(JNIEnv* env, jobject,
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001175 jobject fileDescriptor, jboolean nonblocking) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001176 int handle;
Elliott Hughes24912e02009-10-19 16:36:13 -07001177 if (!jniGetFd(env, fileDescriptor, handle)) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001178 return;
1179 }
1180
1181 int block = nonblocking;
Elliott Hughes24912e02009-10-19 16:36:13 -07001182 int rc = ioctl(handle, FIONBIO, &block);
1183 if (rc == -1) {
Elliott Hughesa9a57f22009-10-30 17:54:32 -07001184 jniThrowSocketException(env, errno);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001185 }
1186}
1187
Elliott Hughesb375c0c2010-05-04 18:06:21 -07001188static jboolean osNetworkSystem_connectWithTimeout(JNIEnv* env,
Elliott Hughesd9d26302010-03-15 16:40:21 -07001189 jobject, jobject fileDescriptor, jint timeout, jint trafficClass,
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001190 jobject inetAddr, jint port, jint step, jbyteArray passContext) {
Elliott Hughes87527682009-10-06 14:08:53 -07001191 sockaddr_storage address;
Elliott Hughesfc354fe2009-10-16 17:25:34 -07001192 if (!inetAddressToSocketAddress(env, inetAddr, port, &address)) {
Elliott Hughesb375c0c2010-05-04 18:06:21 -07001193 return JNI_FALSE;
Elliott Hughes87527682009-10-06 14:08:53 -07001194 }
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001195
Elliott Hughes24912e02009-10-19 16:36:13 -07001196 int handle;
1197 if (!jniGetFd(env, fileDescriptor, handle)) {
Elliott Hughesb375c0c2010-05-04 18:06:21 -07001198 return JNI_FALSE;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001199 }
1200
Elliott Hughesb375c0c2010-05-04 18:06:21 -07001201 jbyte* contextBytes = env->GetByteArrayElements(passContext, NULL);
1202 selectFDSet* context = reinterpret_cast<selectFDSet*>(contextBytes);
Elliott Hughesfc354fe2009-10-16 17:25:34 -07001203 int result = 0;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001204 switch (step) {
Elliott Hughesfc354fe2009-10-16 17:25:34 -07001205 case SOCKET_CONNECT_STEP_START:
Elliott Hughesb375c0c2010-05-04 18:06:21 -07001206 result = sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_START, context);
Elliott Hughesfc354fe2009-10-16 17:25:34 -07001207 break;
1208 case SOCKET_CONNECT_STEP_CHECK:
Elliott Hughesb375c0c2010-05-04 18:06:21 -07001209 result = sockConnectWithTimeout(handle, address, timeout, SOCKET_STEP_CHECK, context);
Elliott Hughesfc354fe2009-10-16 17:25:34 -07001210 break;
1211 default:
1212 assert(false);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001213 }
Elliott Hughesb375c0c2010-05-04 18:06:21 -07001214 env->ReleaseByteArrayElements(passContext, contextBytes, 0);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001215
Elliott Hughes87527682009-10-06 14:08:53 -07001216 if (result == 0) {
Elliott Hughesb375c0c2010-05-04 18:06:21 -07001217 // Connected!
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001218 sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_DONE, NULL);
Elliott Hughesb375c0c2010-05-04 18:06:21 -07001219 return JNI_TRUE;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001220 }
1221
Elliott Hughesb375c0c2010-05-04 18:06:21 -07001222 if (result == -EINPROGRESS) {
1223 // Not yet connected, but not yet denied either... Try again later.
1224 return JNI_FALSE;
1225 }
1226
1227 // Denied!
1228 sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_DONE, NULL);
1229 if (result == -EACCES) {
1230 jniThrowSecurityException(env, -result);
1231 } else {
1232 jniThrowConnectException(env, -result);
1233 }
1234 return JNI_FALSE;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001235}
1236
Elliott Hughesd9d26302010-03-15 16:40:21 -07001237static void osNetworkSystem_connectStreamWithTimeoutSocket(JNIEnv* env,
1238 jobject, jobject fileDescriptor, jint remotePort, jint timeout,
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001239 jint trafficClass, jobject inetAddr) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001240 int result = 0;
Lorenzo Colitti65663e12009-05-26 15:51:50 -07001241 struct sockaddr_storage address;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001242 int remainingTimeout = timeout;
1243 int passedTimeout = 0;
1244 int finishTime = 0;
Elliott Hughesb375c0c2010-05-04 18:06:21 -07001245 bool hasTimeout = timeout > 0;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001246
1247 /* if a timeout was specified calculate the finish time value */
1248 if (hasTimeout) {
1249 finishTime = time_msec_clock() + (int) timeout;
1250 }
1251
Elliott Hughes24912e02009-10-19 16:36:13 -07001252 int handle;
1253 if (!jniGetFd(env, fileDescriptor, handle)) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001254 return;
Lorenzo Colitti65663e12009-05-26 15:51:50 -07001255 }
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001256
Elliott Hughesfc354fe2009-10-16 17:25:34 -07001257 if (!inetAddressToSocketAddress(env, inetAddr, remotePort, &address)) {
Lorenzo Colitti65663e12009-05-26 15:51:50 -07001258 return;
Elliott Hughesfc354fe2009-10-16 17:25:34 -07001259 }
Lorenzo Colitti65663e12009-05-26 15:51:50 -07001260
Lorenzo Colitti65663e12009-05-26 15:51:50 -07001261 /*
1262 * we will be looping checking for when we are connected so allocate
1263 * the descriptor sets that we will use
1264 */
Elliott Hughesb375c0c2010-05-04 18:06:21 -07001265 selectFDSet context;
1266 result = sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_START, &context);
1267 if (result == 0) {
1268 /* ok we connected right away so we are done */
1269 sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_DONE, &context);
1270 return;
1271 } else if (result != -EINPROGRESS) {
1272 sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_DONE, &context);
1273 /* we got an error other than NOTCONNECTED so we cannot continue */
1274 if (result == -EACCES) {
1275 jniThrowSecurityException(env, -result);
1276 } else {
1277 jniThrowSocketException(env, -result);
1278 }
Lorenzo Colitti65663e12009-05-26 15:51:50 -07001279 return;
1280 }
1281
Elliott Hughesb375c0c2010-05-04 18:06:21 -07001282 while (result == -EINPROGRESS) {
Lorenzo Colitti65663e12009-05-26 15:51:50 -07001283 passedTimeout = remainingTimeout;
1284
1285 /*
1286 * ok now try and connect. Depending on the platform this may sleep
1287 * for up to passedTimeout milliseconds
1288 */
Elliott Hughesb375c0c2010-05-04 18:06:21 -07001289 result = sockConnectWithTimeout(handle, address, passedTimeout, SOCKET_STEP_CHECK, &context);
Lorenzo Colitti65663e12009-05-26 15:51:50 -07001290
1291 /*
1292 * now check if the socket is still connected.
1293 * Do it here as some platforms seem to think they
1294 * are connected if the socket is closed on them.
1295 */
1296 handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
Elliott Hughes24912e02009-10-19 16:36:13 -07001297 if (handle == -1) {
Elliott Hughesb375c0c2010-05-04 18:06:21 -07001298 sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_DONE, &context);
Elliott Hughesa9a57f22009-10-30 17:54:32 -07001299 jniThrowSocketException(env, EBADF);
Elliott Hughesb375c0c2010-05-04 18:06:21 -07001300 return;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001301 }
1302
1303 /*
Lorenzo Colitti65663e12009-05-26 15:51:50 -07001304 * check if we are now connected,
1305 * if so we can finish the process and return
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001306 */
Elliott Hughesb375c0c2010-05-04 18:06:21 -07001307 if (result == 0) {
1308 sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_DONE, &context);
1309 return;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001310 }
1311
Lorenzo Colitti65663e12009-05-26 15:51:50 -07001312 /*
Elliott Hughesb375c0c2010-05-04 18:06:21 -07001313 * if the error is -EINPROGRESS then we have not yet
Lorenzo Colitti65663e12009-05-26 15:51:50 -07001314 * connected and we may not be done yet
1315 */
Elliott Hughesb375c0c2010-05-04 18:06:21 -07001316 if (result == -EINPROGRESS) {
Lorenzo Colitti65663e12009-05-26 15:51:50 -07001317 /* check if the timeout has expired */
1318 if (hasTimeout) {
1319 remainingTimeout = finishTime - time_msec_clock();
1320 if (remainingTimeout <= 0) {
Elliott Hughesb375c0c2010-05-04 18:06:21 -07001321 sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_DONE, &context);
1322 jniThrowSocketTimeoutException(env, ETIMEDOUT);
1323 return;
Lorenzo Colitti65663e12009-05-26 15:51:50 -07001324 }
1325 } else {
1326 remainingTimeout = 100;
1327 }
1328 } else {
Elliott Hughesb375c0c2010-05-04 18:06:21 -07001329 sockConnectWithTimeout(handle, address, remainingTimeout, SOCKET_STEP_DONE, &context);
1330 if (result == -ECONNRESET || result == -ECONNREFUSED || result == -EADDRNOTAVAIL ||
1331 result == -EADDRINUSE || result == -ENETUNREACH) {
1332 jniThrowConnectException(env, -result);
1333 } else if (result == -EACCES) {
1334 jniThrowSecurityException(env, -result);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001335 } else {
Elliott Hughesb375c0c2010-05-04 18:06:21 -07001336 jniThrowSocketException(env, -result);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001337 }
Elliott Hughesb375c0c2010-05-04 18:06:21 -07001338 return;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001339 }
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001340 }
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001341}
1342
Elliott Hughesd9d26302010-03-15 16:40:21 -07001343static void osNetworkSystem_bind(JNIEnv* env, jobject, jobject fileDescriptor,
1344 jobject inetAddress, jint port) {
Elliott Hughesf5eafc52009-11-05 10:00:02 -08001345 sockaddr_storage socketAddress;
1346 if (!inetAddressToSocketAddress(env, inetAddress, port, &socketAddress)) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001347 return;
Elliott Hughesfc354fe2009-10-16 17:25:34 -07001348 }
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001349
Elliott Hughesf5eafc52009-11-05 10:00:02 -08001350 int fd;
1351 if (!jniGetFd(env, fileDescriptor, fd)) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001352 return;
1353 }
1354
Elliott Hughes722a27e2010-03-05 20:37:25 -08001355 const CompatibleSocketAddress compatibleAddress(fd, socketAddress, false);
1356 int rc = TEMP_FAILURE_RETRY(bind(fd, compatibleAddress.get(), sizeof(sockaddr_storage)));
Elliott Hughesf5eafc52009-11-05 10:00:02 -08001357 if (rc == -1) {
Elliott Hughesba563a42009-11-05 13:50:06 -08001358 jniThrowBindException(env, errno);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001359 }
1360}
1361
Elliott Hughes97144c82010-03-30 14:21:19 -07001362static void osNetworkSystem_listen(JNIEnv* env, jobject, jobject fileDescriptor, jint backlog) {
1363 int fd;
1364 if (!jniGetFd(env, fileDescriptor, fd)) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001365 return;
1366 }
1367
Elliott Hughes97144c82010-03-30 14:21:19 -07001368 int rc = listen(fd, backlog);
Elliott Hughes24912e02009-10-19 16:36:13 -07001369 if (rc == -1) {
Elliott Hughesa9a57f22009-10-30 17:54:32 -07001370 jniThrowSocketException(env, errno);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001371 }
1372}
1373
Elliott Hughesd9d26302010-03-15 16:40:21 -07001374static void osNetworkSystem_accept(JNIEnv* env, jobject,
Elliott Hughesb150dcd2009-10-20 22:58:23 -07001375 jobject serverFileDescriptor,
1376 jobject newSocket, jobject clientFileDescriptor, jint timeout) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001377 // LOGD("ENTER acceptSocketImpl");
1378
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001379 if (newSocket == NULL) {
Elliott Hughesda4f31d2010-01-28 13:43:39 -08001380 jniThrowNullPointerException(env, NULL);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001381 return;
1382 }
1383
Elliott Hughesba563a42009-11-05 13:50:06 -08001384 int rc = pollSelectWait(env, serverFileDescriptor, timeout);
Elliott Hughes24912e02009-10-19 16:36:13 -07001385 if (rc < 0) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001386 return;
1387 }
1388
Elliott Hughesb150dcd2009-10-20 22:58:23 -07001389 int serverFd;
1390 if (!jniGetFd(env, serverFileDescriptor, serverFd)) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001391 return;
1392 }
1393
Elliott Hughes24912e02009-10-19 16:36:13 -07001394 sockaddr_storage sa;
Elliott Hughesb150dcd2009-10-20 22:58:23 -07001395 socklen_t addrlen = sizeof(sa);
1396 int clientFd = TEMP_FAILURE_RETRY(accept(serverFd,
1397 reinterpret_cast<sockaddr*>(&sa), &addrlen));
1398 if (clientFd == -1) {
Elliott Hughesa9a57f22009-10-30 17:54:32 -07001399 jniThrowSocketException(env, errno);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001400 return;
1401 }
1402
Lorenzo Colitti65663e12009-05-26 15:51:50 -07001403 /*
1404 * For network sockets, put the peer address and port in instance variables.
1405 * We don't bother to do this for UNIX domain sockets, since most peers are
1406 * anonymous anyway.
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001407 */
Lorenzo Colitti65663e12009-05-26 15:51:50 -07001408 if (sa.ss_family == AF_INET || sa.ss_family == AF_INET6) {
Elliott Hughes24912e02009-10-19 16:36:13 -07001409 jobject inetAddress = socketAddressToInetAddress(env, &sa);
1410 if (inetAddress == NULL) {
Elliott Hughesb150dcd2009-10-20 22:58:23 -07001411 close(clientFd);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001412 return;
1413 }
1414
1415 env->SetObjectField(newSocket,
1416 gCachedFields.socketimpl_address, inetAddress);
1417
Lorenzo Colitti65663e12009-05-26 15:51:50 -07001418 int port = getSocketAddressPort(&sa);
1419 env->SetIntField(newSocket, gCachedFields.socketimpl_port, port);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001420 }
1421
Elliott Hughesb150dcd2009-10-20 22:58:23 -07001422 jniSetFileDescriptorOfFD(env, clientFileDescriptor, clientFd);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001423}
1424
Elliott Hughesd9d26302010-03-15 16:40:21 -07001425static jboolean osNetworkSystem_supportsUrgentData(JNIEnv* env,
1426 jobject, jobject fileDescriptor) {
Elliott Hughes24912e02009-10-19 16:36:13 -07001427 // TODO(enh): do we really need to exclude the invalid file descriptor case?
1428 int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
1429 return (fd == -1) ? JNI_FALSE : JNI_TRUE;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001430}
1431
Elliott Hughesd9d26302010-03-15 16:40:21 -07001432static void osNetworkSystem_sendUrgentData(JNIEnv* env, jobject,
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001433 jobject fileDescriptor, jbyte value) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001434 int handle;
Elliott Hughes24912e02009-10-19 16:36:13 -07001435 if (!jniGetFd(env, fileDescriptor, handle)) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001436 return;
1437 }
1438
Elliott Hughes24912e02009-10-19 16:36:13 -07001439 int rc = send(handle, &value, 1, MSG_OOB);
1440 if (rc == -1) {
Elliott Hughesa9a57f22009-10-30 17:54:32 -07001441 jniThrowSocketException(env, errno);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001442 }
1443}
1444
Elliott Hughesd9d26302010-03-15 16:40:21 -07001445static void osNetworkSystem_connectDatagram(JNIEnv* env, jobject,
Elliott Hughes24912e02009-10-19 16:36:13 -07001446 jobject fileDescriptor, jint port, jint trafficClass, jobject inetAddress) {
Elliott Hughes24912e02009-10-19 16:36:13 -07001447 sockaddr_storage sockAddr;
Elliott Hughesfc354fe2009-10-16 17:25:34 -07001448 if (!inetAddressToSocketAddress(env, inetAddress, port, &sockAddr)) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001449 return;
Elliott Hughesfc354fe2009-10-16 17:25:34 -07001450 }
Lorenzo Colitti65663e12009-05-26 15:51:50 -07001451
Elliott Hughes24912e02009-10-19 16:36:13 -07001452 int fd;
1453 if (!jniGetFd(env, fileDescriptor, fd)) {
1454 return;
1455 }
1456
Elliott Hughesb375c0c2010-05-04 18:06:21 -07001457 if (doConnect(fd, &sockAddr) == -1) {
Elliott Hughesa9a57f22009-10-30 17:54:32 -07001458 jniThrowSocketException(env, errno);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001459 }
1460}
1461
Elliott Hughesd9d26302010-03-15 16:40:21 -07001462static void osNetworkSystem_disconnectDatagram(JNIEnv* env, jobject,
Elliott Hughes24912e02009-10-19 16:36:13 -07001463 jobject fileDescriptor) {
Elliott Hughes24912e02009-10-19 16:36:13 -07001464 int fd;
1465 if (!jniGetFd(env, fileDescriptor, fd)) {
1466 return;
1467 }
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001468
Elliott Hughes722a27e2010-03-05 20:37:25 -08001469 // To disconnect a datagram socket, we connect to a bogus address with
1470 // the family AF_UNSPEC.
1471 sockaddr_storage ss;
1472 memset(&ss, 0, sizeof(ss));
1473 ss.ss_family = AF_UNSPEC;
1474 const sockaddr* sa = reinterpret_cast<const sockaddr*>(&ss);
1475 int rc = TEMP_FAILURE_RETRY(connect(fd, sa, sizeof(ss)));
1476 if (rc == -1) {
Elliott Hughesa9a57f22009-10-30 17:54:32 -07001477 jniThrowSocketException(env, errno);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001478 }
1479}
1480
Elliott Hughesd9d26302010-03-15 16:40:21 -07001481static void osNetworkSystem_setInetAddress(JNIEnv* env, jobject,
Elliott Hughesb150dcd2009-10-20 22:58:23 -07001482 jobject sender, jbyteArray address) {
Elliott Hughesb150dcd2009-10-20 22:58:23 -07001483 env->SetObjectField(sender, gCachedFields.iaddr_ipaddress, address);
1484}
1485
Elliott Hughesd9d26302010-03-15 16:40:21 -07001486static jint osNetworkSystem_peekDatagram(JNIEnv* env, jobject,
Elliott Hughes24912e02009-10-19 16:36:13 -07001487 jobject fileDescriptor, jobject sender, jint receiveTimeout) {
Elliott Hughesba563a42009-11-05 13:50:06 -08001488 int result = pollSelectWait(env, fileDescriptor, receiveTimeout);
Elliott Hughes24912e02009-10-19 16:36:13 -07001489 if (result < 0) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001490 return 0;
1491 }
1492
Elliott Hughes24912e02009-10-19 16:36:13 -07001493 int fd;
1494 if (!jniGetFd(env, fileDescriptor, fd)) {
1495 return 0;
1496 }
1497
Elliott Hughesb150dcd2009-10-20 22:58:23 -07001498 sockaddr_storage sockAddr;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001499 socklen_t sockAddrLen = sizeof(sockAddr);
Elliott Hughesb150dcd2009-10-20 22:58:23 -07001500 ssize_t length = TEMP_FAILURE_RETRY(recvfrom(fd, NULL, 0, MSG_PEEK,
1501 reinterpret_cast<sockaddr*>(&sockAddr), &sockAddrLen));
1502 if (length == -1) {
Elliott Hughesa9a57f22009-10-30 17:54:32 -07001503 jniThrowSocketException(env, errno);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001504 return 0;
1505 }
1506
Elliott Hughesb150dcd2009-10-20 22:58:23 -07001507 // We update the byte[] in the 'sender' InetAddress, and return the port.
1508 // This awful API is public in the RI, so there's no point returning
1509 // InetSocketAddress here instead.
1510 jbyteArray senderAddressArray = socketAddressToByteArray(env, &sockAddr);
Elliott Hughesfc354fe2009-10-16 17:25:34 -07001511 if (sender == NULL) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001512 return -1;
Elliott Hughesfc354fe2009-10-16 17:25:34 -07001513 }
Elliott Hughesd9d26302010-03-15 16:40:21 -07001514 osNetworkSystem_setInetAddress(env, NULL, sender, senderAddressArray);
Elliott Hughes24912e02009-10-19 16:36:13 -07001515 return getSocketAddressPort(&sockAddr);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001516}
1517
Elliott Hughesd9d26302010-03-15 16:40:21 -07001518static jint osNetworkSystem_receiveDatagramDirect(JNIEnv* env, jobject,
Elliott Hughes24912e02009-10-19 16:36:13 -07001519 jobject fileDescriptor, jobject packet, jint address, jint offset,
1520 jint length, jint receiveTimeout, jboolean peek) {
Elliott Hughesba563a42009-11-05 13:50:06 -08001521 int result = pollSelectWait(env, fileDescriptor, receiveTimeout);
Elliott Hughes24912e02009-10-19 16:36:13 -07001522 if (result < 0) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001523 return 0;
1524 }
1525
Elliott Hughes24912e02009-10-19 16:36:13 -07001526 int fd;
1527 if (!jniGetFd(env, fileDescriptor, fd)) {
1528 return 0;
1529 }
Elliott Hughesb150dcd2009-10-20 22:58:23 -07001530
1531 char* buf =
1532 reinterpret_cast<char*>(static_cast<uintptr_t>(address + offset));
1533 const int mode = peek ? MSG_PEEK : 0;
Elliott Hughes24912e02009-10-19 16:36:13 -07001534 sockaddr_storage sockAddr;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001535 socklen_t sockAddrLen = sizeof(sockAddr);
Elliott Hughesb150dcd2009-10-20 22:58:23 -07001536 ssize_t actualLength = TEMP_FAILURE_RETRY(recvfrom(fd, buf, length, mode,
1537 reinterpret_cast<sockaddr*>(&sockAddr), &sockAddrLen));
1538 if (actualLength == -1) {
Elliott Hughesa9a57f22009-10-30 17:54:32 -07001539 jniThrowSocketException(env, errno);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001540 return 0;
1541 }
1542
1543 if (packet != NULL) {
Lorenzo Colittie8596902009-09-18 15:25:06 -07001544 jbyteArray addr = socketAddressToByteArray(env, &sockAddr);
Elliott Hughesfc354fe2009-10-16 17:25:34 -07001545 if (addr == NULL) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001546 return 0;
Elliott Hughesfc354fe2009-10-16 17:25:34 -07001547 }
Lorenzo Colitti65663e12009-05-26 15:51:50 -07001548 int port = getSocketAddressPort(&sockAddr);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001549 jobject sender = env->CallStaticObjectMethod(
1550 gCachedFields.iaddr_class, gCachedFields.iaddr_getbyaddress,
1551 addr);
1552 env->SetObjectField(packet, gCachedFields.dpack_address, sender);
1553 env->SetIntField(packet, gCachedFields.dpack_port, port);
Lorenzo Colitti65663e12009-05-26 15:51:50 -07001554 env->SetIntField(packet, gCachedFields.dpack_length,
1555 (jint) actualLength);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001556 }
Lorenzo Colitti65663e12009-05-26 15:51:50 -07001557 return (jint) actualLength;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001558}
1559
Elliott Hughesd9d26302010-03-15 16:40:21 -07001560static jint osNetworkSystem_receiveDatagram(JNIEnv* env, jobject,
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001561 jobject fd, jobject packet, jbyteArray data, jint offset, jint length,
1562 jint receiveTimeout, jboolean peek) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001563 int localLength = (length < 65536) ? length : 65536;
1564 jbyte *bytes = (jbyte*) malloc(localLength);
1565 if (bytes == NULL) {
1566 jniThrowException(env, "java/lang/OutOfMemoryError",
1567 "couldn't allocate enough memory for receiveDatagram");
1568 return 0;
1569 }
1570
Elliott Hughesd9d26302010-03-15 16:40:21 -07001571 int actualLength = osNetworkSystem_receiveDatagramDirect(env, NULL, fd,
The Android Open Source Project5d287a92009-03-18 22:20:24 -07001572 packet, (jint)bytes, 0, localLength, receiveTimeout, peek);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001573
1574 if (actualLength > 0) {
1575 env->SetByteArrayRegion(data, offset, actualLength, bytes);
1576 }
1577 free(bytes);
1578
1579 return actualLength;
1580}
1581
Elliott Hughesd9d26302010-03-15 16:40:21 -07001582static jint osNetworkSystem_recvConnectedDatagramDirect(JNIEnv* env,
1583 jobject, jobject fileDescriptor, jobject packet,
Elliott Hughes24912e02009-10-19 16:36:13 -07001584 jint address, jint offset, jint length,
1585 jint receiveTimeout, jboolean peek) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001586
Elliott Hughesba563a42009-11-05 13:50:06 -08001587 int result = pollSelectWait(env, fileDescriptor, receiveTimeout);
Elliott Hughes24912e02009-10-19 16:36:13 -07001588 if (result < 0) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001589 return 0;
1590 }
1591
Elliott Hughes24912e02009-10-19 16:36:13 -07001592 int fd;
1593 if (!jniGetFd(env, fileDescriptor, fd)) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001594 return 0;
1595 }
Elliott Hughes24912e02009-10-19 16:36:13 -07001596
1597 char* buf = reinterpret_cast<char*>(static_cast<uintptr_t>(address + offset));
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001598 int mode = peek ? MSG_PEEK : 0;
Elliott Hughes24912e02009-10-19 16:36:13 -07001599 int actualLength = recvfrom(fd, buf, length, mode, NULL, NULL);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001600 if (actualLength < 0) {
1601 jniThrowException(env, "java/net/PortUnreachableException", "");
1602 return 0;
1603 }
1604
Elliott Hughes24912e02009-10-19 16:36:13 -07001605 if (packet != NULL) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001606 env->SetIntField(packet, gCachedFields.dpack_length, actualLength);
1607 }
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001608 return actualLength;
1609}
1610
Elliott Hughesd9d26302010-03-15 16:40:21 -07001611static jint osNetworkSystem_recvConnectedDatagram(JNIEnv* env, jobject,
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001612 jobject fd, jobject packet, jbyteArray data, jint offset, jint length,
1613 jint receiveTimeout, jboolean peek) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001614 int localLength = (length < 65536) ? length : 65536;
1615 jbyte *bytes = (jbyte*) malloc(localLength);
1616 if (bytes == NULL) {
1617 jniThrowException(env, "java/lang/OutOfMemoryError",
1618 "couldn't allocate enough memory for recvConnectedDatagram");
1619 return 0;
1620 }
1621
Elliott Hughesd9d26302010-03-15 16:40:21 -07001622 int actualLength = osNetworkSystem_recvConnectedDatagramDirect(env,
1623 NULL, fd, packet, (jint)bytes, 0, localLength,
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001624 receiveTimeout, peek);
1625
1626 if (actualLength > 0) {
1627 env->SetByteArrayRegion(data, offset, actualLength, bytes);
1628 }
1629 free(bytes);
1630
1631 return actualLength;
1632}
1633
Elliott Hughesd9d26302010-03-15 16:40:21 -07001634static jint osNetworkSystem_sendDatagramDirect(JNIEnv* env, jobject,
Elliott Hughes24912e02009-10-19 16:36:13 -07001635 jobject fileDescriptor, jint address, jint offset, jint length,
1636 jint port,
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001637 jboolean bindToDevice, jint trafficClass, jobject inetAddress) {
Elliott Hughes24912e02009-10-19 16:36:13 -07001638 int fd;
1639 if (!jniGetFd(env, fileDescriptor, fd)) {
1640 return -1;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001641 }
1642
Elliott Hughes24912e02009-10-19 16:36:13 -07001643 sockaddr_storage receiver;
Elliott Hughesfc354fe2009-10-16 17:25:34 -07001644 if (!inetAddressToSocketAddress(env, inetAddress, port, &receiver)) {
1645 return -1;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001646 }
1647
Elliott Hughesb150dcd2009-10-20 22:58:23 -07001648 char* buf =
1649 reinterpret_cast<char*>(static_cast<uintptr_t>(address + offset));
1650 ssize_t bytesSent = TEMP_FAILURE_RETRY(sendto(fd, buf, length,
1651 SOCKET_NOFLAGS,
1652 reinterpret_cast<sockaddr*>(&receiver), sizeof(receiver)));
1653 if (bytesSent == -1) {
1654 if (errno == ECONNRESET || errno == ECONNREFUSED) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001655 return 0;
1656 } else {
Elliott Hughesa9a57f22009-10-30 17:54:32 -07001657 jniThrowSocketException(env, errno);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001658 }
1659 }
Elliott Hughesb150dcd2009-10-20 22:58:23 -07001660 return bytesSent;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001661}
1662
Elliott Hughesd9d26302010-03-15 16:40:21 -07001663static jint osNetworkSystem_sendDatagram(JNIEnv* env, jobject,
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001664 jobject fd, jbyteArray data, jint offset, jint length, jint port,
1665 jboolean bindToDevice, jint trafficClass, jobject inetAddress) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001666 jbyte *bytes = env->GetByteArrayElements(data, NULL);
Elliott Hughesd9d26302010-03-15 16:40:21 -07001667 int actualLength = osNetworkSystem_sendDatagramDirect(env, NULL, fd,
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001668 (jint)bytes, offset, length, port, bindToDevice, trafficClass,
1669 inetAddress);
1670 env->ReleaseByteArrayElements(data, bytes, JNI_ABORT);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001671 return actualLength;
1672}
1673
Elliott Hughesd9d26302010-03-15 16:40:21 -07001674static jint osNetworkSystem_sendConnectedDatagramDirect(JNIEnv* env,
1675 jobject, jobject fileDescriptor,
Elliott Hughes24912e02009-10-19 16:36:13 -07001676 jint address, jint offset, jint length,
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001677 jboolean bindToDevice) {
Elliott Hughes24912e02009-10-19 16:36:13 -07001678 int fd;
1679 if (!jniGetFd(env, fileDescriptor, fd)) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001680 return 0;
1681 }
1682
Elliott Hughesb150dcd2009-10-20 22:58:23 -07001683 char* buf =
1684 reinterpret_cast<char*>(static_cast<uintptr_t>(address + offset));
1685 ssize_t bytesSent = TEMP_FAILURE_RETRY(send(fd, buf, length, 0));
1686 if (bytesSent == -1) {
1687 if (errno == ECONNRESET || errno == ECONNREFUSED) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001688 return 0;
1689 } else {
Elliott Hughesa9a57f22009-10-30 17:54:32 -07001690 jniThrowSocketException(env, errno);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001691 }
1692 }
Elliott Hughesb150dcd2009-10-20 22:58:23 -07001693 return bytesSent;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001694}
1695
Elliott Hughesd9d26302010-03-15 16:40:21 -07001696static jint osNetworkSystem_sendConnectedDatagram(JNIEnv* env, jobject,
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001697 jobject fd, jbyteArray data, jint offset, jint length,
1698 jboolean bindToDevice) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001699 jbyte *bytes = env->GetByteArrayElements(data, NULL);
Elliott Hughesd9d26302010-03-15 16:40:21 -07001700 int actualLength = osNetworkSystem_sendConnectedDatagramDirect(env,
1701 NULL, fd, (jint)bytes, offset, length, bindToDevice);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001702 env->ReleaseByteArrayElements(data, bytes, JNI_ABORT);
1703
1704 return actualLength;
1705}
1706
Elliott Hughesd9d26302010-03-15 16:40:21 -07001707static void osNetworkSystem_createServerStreamSocket(JNIEnv* env, jobject,
1708 jobject fileDescriptor, jboolean) {
1709 int fd = createSocketFileDescriptor(env, fileDescriptor, SOCK_STREAM);
1710 if (fd != -1) {
1711 // TODO: we could actually do this in Java. (and check for errors!)
1712 int value = 1;
1713 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(int));
Elliott Hughesfc354fe2009-10-16 17:25:34 -07001714 }
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001715}
1716
Elliott Hughes24912e02009-10-19 16:36:13 -07001717static void doShutdown(JNIEnv* env, jobject fileDescriptor, int how) {
1718 int fd;
1719 if (!jniGetFd(env, fileDescriptor, fd)) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001720 return;
1721 }
Elliott Hughes24912e02009-10-19 16:36:13 -07001722 int rc = shutdown(fd, how);
1723 if (rc == -1) {
Elliott Hughesa9a57f22009-10-30 17:54:32 -07001724 jniThrowSocketException(env, errno);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001725 }
1726}
1727
Elliott Hughesd9d26302010-03-15 16:40:21 -07001728static void osNetworkSystem_shutdownInput(JNIEnv* env, jobject, jobject fd) {
1729 doShutdown(env, fd, SHUT_RD);
Elliott Hughes24912e02009-10-19 16:36:13 -07001730}
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001731
Elliott Hughesd9d26302010-03-15 16:40:21 -07001732static void osNetworkSystem_shutdownOutput(JNIEnv* env, jobject, jobject fd) {
1733 doShutdown(env, fd, SHUT_WR);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001734}
1735
Elliott Hughesd9d26302010-03-15 16:40:21 -07001736static jint osNetworkSystem_sendDatagram2(JNIEnv* env, jobject,
Elliott Hughes24912e02009-10-19 16:36:13 -07001737 jobject fileDescriptor, jbyteArray data, jint offset, jint length,
1738 jint port, jobject inetAddress) {
Elliott Hughesb150dcd2009-10-20 22:58:23 -07001739 sockaddr_storage sockAddr;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001740 if (inetAddress != NULL) {
Elliott Hughesb150dcd2009-10-20 22:58:23 -07001741 if (!inetAddressToSocketAddress(env, inetAddress, port, &sockAddr)) {
Elliott Hughesfc354fe2009-10-16 17:25:34 -07001742 return -1;
1743 }
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001744 }
1745
Elliott Hughesb150dcd2009-10-20 22:58:23 -07001746 int fd;
1747 if (!jniGetFd(env, fileDescriptor, fd)) {
1748 return 0;
1749 }
1750
Elliott Hughesfc354fe2009-10-16 17:25:34 -07001751 jbyte* message = (jbyte*) malloc(length * sizeof(jbyte));
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001752 if (message == NULL) {
1753 jniThrowException(env, "java/lang/OutOfMemoryError",
1754 "couldn't allocate enough memory for readSocket");
1755 return 0;
1756 }
1757
1758 env->GetByteArrayRegion(data, offset, length, message);
1759
Elliott Hughesb150dcd2009-10-20 22:58:23 -07001760 int totalBytesSent = 0;
1761 while (totalBytesSent < length) {
1762 ssize_t bytesSent = TEMP_FAILURE_RETRY(sendto(fd,
1763 message + totalBytesSent, length - totalBytesSent,
1764 SOCKET_NOFLAGS,
1765 reinterpret_cast<sockaddr*>(&sockAddr), sizeof(sockAddr)));
1766 if (bytesSent == -1) {
Elliott Hughesa9a57f22009-10-30 17:54:32 -07001767 jniThrowSocketException(env, errno);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001768 free(message);
1769 return 0;
1770 }
1771
Elliott Hughesb150dcd2009-10-20 22:58:23 -07001772 totalBytesSent += bytesSent;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001773 }
1774
1775 free(message);
Elliott Hughesb150dcd2009-10-20 22:58:23 -07001776 return totalBytesSent;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001777}
1778
Elliott Hughesde816cc2010-03-31 18:34:53 -07001779static bool isValidFd(int fd) {
1780 return fd >= 0 && fd < FD_SETSIZE;
1781}
1782
Elliott Hughes42d8ce72009-09-17 18:32:07 -07001783static bool initFdSet(JNIEnv* env, jobjectArray fdArray, jint count, fd_set* fdSet, int* maxFd) {
1784 for (int i = 0; i < count; ++i) {
1785 jobject fileDescriptor = env->GetObjectArrayElement(fdArray, i);
1786 if (fileDescriptor == NULL) {
1787 return false;
1788 }
1789
1790 const int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
Elliott Hughesde816cc2010-03-31 18:34:53 -07001791 if (!isValidFd(fd)) {
Elliott Hughes24912e02009-10-19 16:36:13 -07001792 LOGE("selectImpl: ignoring invalid fd %i", fd);
Elliott Hughes42d8ce72009-09-17 18:32:07 -07001793 continue;
1794 }
1795
1796 FD_SET(fd, fdSet);
1797
1798 if (fd > *maxFd) {
1799 *maxFd = fd;
1800 }
1801 }
1802 return true;
1803}
1804
Elliott Hughesf5eafc52009-11-05 10:00:02 -08001805/*
1806 * Note: fdSet has to be non-const because although on Linux FD_ISSET() is sane
1807 * and takes a const fd_set*, it takes fd_set* on Mac OS. POSIX is not on our
1808 * side here:
1809 * http://www.opengroup.org/onlinepubs/000095399/functions/select.html
1810 */
Dan Bornsteinfef88752009-11-04 15:34:14 -08001811static bool translateFdSet(JNIEnv* env, jobjectArray fdArray, jint count, fd_set& fdSet, jint* flagArray, size_t offset, jint op) {
Elliott Hughes42d8ce72009-09-17 18:32:07 -07001812 for (int i = 0; i < count; ++i) {
1813 jobject fileDescriptor = env->GetObjectArrayElement(fdArray, i);
1814 if (fileDescriptor == NULL) {
1815 return false;
1816 }
1817
1818 const int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
Elliott Hughesde816cc2010-03-31 18:34:53 -07001819 if (isValidFd(fd) && FD_ISSET(fd, &fdSet)) {
Elliott Hughes42d8ce72009-09-17 18:32:07 -07001820 flagArray[i + offset] = op;
1821 } else {
1822 flagArray[i + offset] = SOCKET_OP_NONE;
1823 }
1824 }
1825 return true;
1826}
1827
Elliott Hughesd9d26302010-03-15 16:40:21 -07001828static jboolean osNetworkSystem_selectImpl(JNIEnv* env, jclass,
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001829 jobjectArray readFDArray, jobjectArray writeFDArray, jint countReadC,
Elliott Hughes42d8ce72009-09-17 18:32:07 -07001830 jint countWriteC, jintArray outFlags, jlong timeoutMs) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001831 // LOGD("ENTER selectImpl");
Elliott Hughes42d8ce72009-09-17 18:32:07 -07001832
1833 // Initialize the fd_sets.
1834 int maxFd = -1;
1835 fd_set readFds;
1836 fd_set writeFds;
1837 FD_ZERO(&readFds);
1838 FD_ZERO(&writeFds);
1839 bool initialized = initFdSet(env, readFDArray, countReadC, &readFds, &maxFd) &&
1840 initFdSet(env, writeFDArray, countWriteC, &writeFds, &maxFd);
1841 if (!initialized) {
1842 return -1;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001843 }
Elliott Hughes42d8ce72009-09-17 18:32:07 -07001844
1845 // Initialize the timeout, if any.
1846 timeval tv;
1847 timeval* tvp = NULL;
1848 if (timeoutMs >= 0) {
1849 tv = toTimeval(timeoutMs);
1850 tvp = &tv;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001851 }
Elliott Hughes42d8ce72009-09-17 18:32:07 -07001852
1853 // Perform the select.
Elliott Hughesba563a42009-11-05 13:50:06 -08001854 int result = select(maxFd + 1, &readFds, &writeFds, NULL, tvp);
1855 if (result == 0) {
1856 // Timeout.
1857 return JNI_FALSE;
1858 } else if (result == -1) {
1859 // Error.
1860 if (errno == EINTR) {
1861 return JNI_FALSE;
1862 } else {
1863 jniThrowSocketException(env, errno);
1864 return JNI_FALSE;
1865 }
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001866 }
Elliott Hughes42d8ce72009-09-17 18:32:07 -07001867
1868 // Translate the result into the int[] we're supposed to fill in.
1869 jint* flagArray = env->GetIntArrayElements(outFlags, NULL);
1870 if (flagArray == NULL) {
Elliott Hughesba563a42009-11-05 13:50:06 -08001871 return JNI_FALSE;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001872 }
Elliott Hughes42d8ce72009-09-17 18:32:07 -07001873 bool okay = translateFdSet(env, readFDArray, countReadC, readFds, flagArray, 0, SOCKET_OP_READ) &&
1874 translateFdSet(env, writeFDArray, countWriteC, writeFds, flagArray, countReadC, SOCKET_OP_WRITE);
1875 env->ReleaseIntArrayElements(outFlags, flagArray, 0);
Elliott Hughesba563a42009-11-05 13:50:06 -08001876 return okay;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001877}
1878
Elliott Hughesd9d26302010-03-15 16:40:21 -07001879static jobject osNetworkSystem_getSocketLocalAddress(JNIEnv* env,
1880 jobject, jobject fileDescriptor) {
Elliott Hughes24912e02009-10-19 16:36:13 -07001881 int fd;
1882 if (!jniGetFd(env, fileDescriptor, fd)) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001883 return NULL;
1884 }
1885
Elliott Hughes24912e02009-10-19 16:36:13 -07001886 sockaddr_storage addr;
1887 socklen_t addrLen = sizeof(addr);
1888 memset(&addr, 0, addrLen);
Elliott Hughes24912e02009-10-19 16:36:13 -07001889 int rc = getsockname(fd, (sockaddr*) &addr, &addrLen);
Elliott Hughesa9a57f22009-10-30 17:54:32 -07001890 if (rc == -1) {
1891 // TODO: the public API doesn't allow failure, so this whole method
1892 // represents a broken design. In practice, though, getsockname can't
1893 // fail unless we give it invalid arguments.
1894 LOGE("getsockname failed: %s (errno=%i)", strerror(errno), errno);
1895 return NULL;
1896 }
Lorenzo Colitti65663e12009-05-26 15:51:50 -07001897 return socketAddressToInetAddress(env, &addr);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001898}
1899
Elliott Hughesd9d26302010-03-15 16:40:21 -07001900static jint osNetworkSystem_getSocketLocalPort(JNIEnv* env, jobject,
Elliott Hughes4c5cbf22010-01-19 15:29:02 -08001901 jobject fileDescriptor) {
Elliott Hughes24912e02009-10-19 16:36:13 -07001902 int fd;
1903 if (!jniGetFd(env, fileDescriptor, fd)) {
1904 return 0;
1905 }
1906
1907 sockaddr_storage addr;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001908 socklen_t addrLen = sizeof(addr);
Elliott Hughesa9a57f22009-10-30 17:54:32 -07001909 memset(&addr, 0, addrLen);
Elliott Hughes24912e02009-10-19 16:36:13 -07001910 int rc = getsockname(fd, (sockaddr*) &addr, &addrLen);
Elliott Hughesa9a57f22009-10-30 17:54:32 -07001911 if (rc == -1) {
1912 // TODO: the public API doesn't allow failure, so this whole method
1913 // represents a broken design. In practice, though, getsockname can't
1914 // fail unless we give it invalid arguments.
1915 LOGE("getsockname failed: %s (errno=%i)", strerror(errno), errno);
1916 return 0;
1917 }
1918 return getSocketAddressPort(&addr);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001919}
1920
Elliott Hughes4401c752010-05-04 09:47:02 -07001921template <typename T>
1922static bool getSocketOption(JNIEnv* env, int fd, int level, int option, T* value) {
1923 socklen_t size = sizeof(*value);
1924 int rc = getsockopt(fd, level, option, value, &size);
1925 if (rc == -1) {
1926 LOGE("getSocketOption(fd=%i, level=%i, option=%i) failed: %s (errno=%i)",
1927 fd, level, option, strerror(errno), errno);
1928 jniThrowSocketException(env, errno);
1929 return false;
1930 }
1931 return true;
1932}
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001933
Elliott Hughes4401c752010-05-04 09:47:02 -07001934static jobject getSocketOption_Boolean(JNIEnv* env, int fd, int level, int option) {
1935 int value;
1936 return getSocketOption(env, fd, level, option, &value) ? newJavaLangBoolean(env, value) : NULL;
1937}
1938
1939static jobject getSocketOption_Integer(JNIEnv* env, int fd, int level, int option) {
1940 int value;
1941 return getSocketOption(env, fd, level, option, &value) ? newJavaLangInteger(env, value) : NULL;
1942}
1943
1944static jobject osNetworkSystem_getSocketOption(JNIEnv* env, jobject, jobject fileDescriptor, jint option) {
1945 int fd;
1946 if (!jniGetFd(env, fileDescriptor, fd)) {
1947 return NULL;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001948 }
1949
Elliott Hughes4401c752010-05-04 09:47:02 -07001950 int family = getSocketAddressFamily(fd);
1951 if (family != AF_INET && family != AF_INET6) {
1952 jniThrowSocketException(env, EAFNOSUPPORT);
1953 return NULL;
1954 }
Dan Bornsteinfef88752009-11-04 15:34:14 -08001955
Elliott Hughes4401c752010-05-04 09:47:02 -07001956 switch (option) {
1957 case JAVASOCKOPT_TCP_NODELAY:
1958 return getSocketOption_Boolean(env, fd, IPPROTO_TCP, TCP_NODELAY);
1959 case JAVASOCKOPT_SO_SNDBUF:
1960 return getSocketOption_Integer(env, fd, SOL_SOCKET, SO_SNDBUF);
1961 case JAVASOCKOPT_SO_RCVBUF:
1962 return getSocketOption_Integer(env, fd, SOL_SOCKET, SO_RCVBUF);
1963 case JAVASOCKOPT_SO_BROADCAST:
1964 return getSocketOption_Boolean(env, fd, SOL_SOCKET, SO_BROADCAST);
1965 case JAVASOCKOPT_SO_REUSEADDR:
1966 return getSocketOption_Boolean(env, fd, SOL_SOCKET, SO_REUSEADDR);
1967 case JAVASOCKOPT_SO_KEEPALIVE:
1968 return getSocketOption_Boolean(env, fd, SOL_SOCKET, SO_KEEPALIVE);
1969 case JAVASOCKOPT_SO_OOBINLINE:
1970 return getSocketOption_Boolean(env, fd, SOL_SOCKET, SO_OOBINLINE);
1971 case JAVASOCKOPT_IP_TOS:
1972 if (family == AF_INET) {
1973 return getSocketOption_Boolean(env, fd, IPPROTO_IP, IP_TOS);
1974 } else {
1975 return getSocketOption_Boolean(env, fd, IPPROTO_IPV6, IPV6_TCLASS);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001976 }
Elliott Hughes4401c752010-05-04 09:47:02 -07001977 case JAVASOCKOPT_SO_LINGER:
1978 {
1979 linger lingr;
1980 bool ok = getSocketOption(env, fd, SOL_SOCKET, SO_LINGER, &lingr);
1981 return ok ? newJavaLangInteger(env, !lingr.l_onoff ? -1 : lingr.l_linger) : NULL;
Dan Bornsteinfef88752009-11-04 15:34:14 -08001982 }
Elliott Hughes4401c752010-05-04 09:47:02 -07001983 case JAVASOCKOPT_SO_RCVTIMEOUT:
1984 {
1985 timeval timeout;
1986 bool ok = getSocketOption(env, fd, SOL_SOCKET, SO_RCVTIMEO, &timeout);
1987 return ok ? newJavaLangInteger(env, toMs(timeout)) : NULL;
Dan Bornsteinfef88752009-11-04 15:34:14 -08001988 }
Dan Bornsteinfef88752009-11-04 15:34:14 -08001989#ifdef ENABLE_MULTICAST
Elliott Hughes4401c752010-05-04 09:47:02 -07001990 case JAVASOCKOPT_IP_MULTICAST_IF:
1991 {
1992 struct sockaddr_storage sockVal;
1993 if (!getSocketOption(env, fd, IPPROTO_IP, IP_MULTICAST_IF, &sockVal)) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001994 return NULL;
1995 }
Elliott Hughesa9a57f22009-10-30 17:54:32 -07001996 if (sockVal.ss_family != AF_INET) {
Elliott Hughes4d8e9332010-05-03 14:31:03 -07001997 LOGE("sockVal.ss_family != AF_INET (%i)", sockVal.ss_family);
Elliott Hughesa9a57f22009-10-30 17:54:32 -07001998 // Java expects an AF_INET INADDR_ANY, but Linux just returns AF_UNSPEC.
1999 jbyteArray inAddrAny = env->NewByteArray(4); // { 0, 0, 0, 0 }
2000 return byteArrayToInetAddress(env, inAddrAny);
2001 }
Lorenzo Colitti65663e12009-05-26 15:51:50 -07002002 return socketAddressToInetAddress(env, &sockVal);
2003 }
Elliott Hughes4401c752010-05-04 09:47:02 -07002004 case JAVASOCKOPT_IP_MULTICAST_IF2:
2005 if (family == AF_INET) {
Lorenzo Colitti65663e12009-05-26 15:51:50 -07002006 struct ip_mreqn multicastRequest;
Elliott Hughes4401c752010-05-04 09:47:02 -07002007 bool ok = getSocketOption(env, fd, IPPROTO_IP, IP_MULTICAST_IF, &multicastRequest);
2008 return ok ? newJavaLangInteger(env, multicastRequest.imr_ifindex) : NULL;
2009 } else {
2010 return getSocketOption_Integer(env, fd, IPPROTO_IPV6, IPV6_MULTICAST_IF);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08002011 }
Elliott Hughes4401c752010-05-04 09:47:02 -07002012 case JAVASOCKOPT_IP_MULTICAST_LOOP:
2013 if (family == AF_INET) {
2014 // Although IPv6 was cleaned up to use int, IPv4 multicast loopback uses a byte.
2015 u_char loopback;
2016 bool ok = getSocketOption(env, fd, IPPROTO_IP, IP_MULTICAST_LOOP, &loopback);
2017 return ok ? newJavaLangBoolean(env, loopback) : NULL;
2018 } else {
2019 return getSocketOption_Boolean(env, fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP);
2020 }
2021 case JAVASOCKOPT_MULTICAST_TTL:
2022 if (family == AF_INET) {
2023 // Although IPv6 was cleaned up to use int, and IPv4 non-multicast TTL uses int,
2024 // IPv4 multicast TTL uses a byte.
2025 u_char ttl;
2026 bool ok = getSocketOption(env, fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl);
2027 return ok ? newJavaLangInteger(env, ttl) : NULL;
2028 } else {
2029 return getSocketOption_Integer(env, fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08002030 }
Dan Bornsteinfef88752009-11-04 15:34:14 -08002031#else
Elliott Hughes4401c752010-05-04 09:47:02 -07002032 case JAVASOCKOPT_MULTICAST_TTL:
2033 case JAVASOCKOPT_IP_MULTICAST_IF:
2034 case JAVASOCKOPT_IP_MULTICAST_IF2:
2035 case JAVASOCKOPT_IP_MULTICAST_LOOP:
2036 jniThrowException(env, "java/lang/UnsupportedOperationException", NULL);
2037 return NULL;
Dan Bornsteinfef88752009-11-04 15:34:14 -08002038#endif // def ENABLE_MULTICAST
Elliott Hughes4401c752010-05-04 09:47:02 -07002039 default:
2040 jniThrowSocketException(env, ENOPROTOOPT);
2041 return NULL;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08002042 }
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08002043}
2044
Elliott Hughes4d8e9332010-05-03 14:31:03 -07002045template <typename T>
2046static void setSocketOption(JNIEnv* env, int fd, int level, int option, T* value) {
2047 int rc = setsockopt(fd, level, option, value, sizeof(*value));
2048 if (rc == -1) {
2049 LOGE("setSocketOption(fd=%i, level=%i, option=%i) failed: %s (errno=%i)",
Elliott Hughes4401c752010-05-04 09:47:02 -07002050 fd, level, option, strerror(errno), errno);
Elliott Hughes4d8e9332010-05-03 14:31:03 -07002051 jniThrowSocketException(env, errno);
2052 }
2053}
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08002054
Elliott Hughes4d8e9332010-05-03 14:31:03 -07002055static void osNetworkSystem_setSocketOption(JNIEnv* env, jobject, jobject fileDescriptor, jint option, jobject optVal) {
2056 int fd;
2057 if (!jniGetFd(env, fileDescriptor, fd)) {
2058 return;
2059 }
2060
2061 int intVal;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08002062 if (env->IsInstanceOf(optVal, gCachedFields.integer_class)) {
2063 intVal = (int) env->GetIntField(optVal, gCachedFields.integer_class_value);
2064 } else if (env->IsInstanceOf(optVal, gCachedFields.boolean_class)) {
2065 intVal = (int) env->GetBooleanField(optVal, gCachedFields.boolean_class_value);
2066 } else if (env->IsInstanceOf(optVal, gCachedFields.byte_class)) {
Elliott Hughesa9a57f22009-10-30 17:54:32 -07002067 intVal = (int) env->GetByteField(optVal, gCachedFields.byte_class_value);
Elliott Hughes4401c752010-05-04 09:47:02 -07002068 } else if (env->IsInstanceOf(optVal, gCachedFields.genericipmreq_class) || env->IsInstanceOf(optVal, gCachedFields.iaddr_class)) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08002069 // we'll use optVal directly
2070 } else {
Elliott Hughes4401c752010-05-04 09:47:02 -07002071 jniThrowSocketException(env, EINVAL);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08002072 return;
2073 }
2074
Elliott Hughes4d8e9332010-05-03 14:31:03 -07002075 int family = getSocketAddressFamily(fd);
2076 if (family != AF_INET && family != AF_INET6) {
2077 jniThrowSocketException(env, EAFNOSUPPORT);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08002078 return;
2079 }
2080
Elliott Hughes4d8e9332010-05-03 14:31:03 -07002081 switch (option) {
2082 case JAVASOCKOPT_SO_LINGER:
2083 {
Elliott Hughes4401c752010-05-04 09:47:02 -07002084 linger lingr;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08002085 lingr.l_onoff = intVal > 0 ? 1 : 0;
2086 lingr.l_linger = intVal;
Elliott Hughes4d8e9332010-05-03 14:31:03 -07002087 setSocketOption(env, fd, SOL_SOCKET, SO_LINGER, &lingr);
2088 return;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08002089 }
Elliott Hughes4d8e9332010-05-03 14:31:03 -07002090 case JAVASOCKOPT_SO_SNDBUF:
2091 setSocketOption(env, fd, SOL_SOCKET, SO_SNDBUF, &intVal);
2092 return;
2093 case JAVASOCKOPT_SO_RCVBUF:
2094 setSocketOption(env, fd, SOL_SOCKET, SO_RCVBUF, &intVal);
2095 return;
2096 case JAVASOCKOPT_SO_BROADCAST:
2097 setSocketOption(env, fd, SOL_SOCKET, SO_BROADCAST, &intVal);
2098 return;
2099 case JAVASOCKOPT_SO_REUSEADDR:
2100 setSocketOption(env, fd, SOL_SOCKET, SO_REUSEADDR, &intVal);
2101 return;
2102 case JAVASOCKOPT_SO_KEEPALIVE:
2103 setSocketOption(env, fd, SOL_SOCKET, SO_KEEPALIVE, &intVal);
2104 return;
2105 case JAVASOCKOPT_SO_OOBINLINE:
2106 setSocketOption(env, fd, SOL_SOCKET, SO_OOBINLINE, &intVal);
2107 return;
2108 case JAVASOCKOPT_REUSEADDR_AND_REUSEPORT:
2109 // SO_REUSEPORT doesn't need to get set on this System
2110 setSocketOption(env, fd, SOL_SOCKET, SO_REUSEADDR, &intVal);
2111 return;
2112 case JAVASOCKOPT_SO_RCVTIMEOUT:
2113 {
Dan Bornsteinfef88752009-11-04 15:34:14 -08002114 timeval timeout(toTimeval(intVal));
Elliott Hughes4d8e9332010-05-03 14:31:03 -07002115 setSocketOption(env, fd, SOL_SOCKET, SO_RCVTIMEO, &timeout);
2116 return;
Dan Bornsteinfef88752009-11-04 15:34:14 -08002117 }
Elliott Hughes4d8e9332010-05-03 14:31:03 -07002118 case JAVASOCKOPT_IP_TOS:
2119 if (family == AF_INET) {
2120 setSocketOption(env, fd, IPPROTO_IP, IP_TOS, &intVal);
2121 } else {
2122 setSocketOption(env, fd, IPPROTO_IPV6, IPV6_TCLASS, &intVal);
2123 }
2124 return;
2125 case JAVASOCKOPT_TCP_NODELAY:
2126 setSocketOption(env, fd, IPPROTO_TCP, TCP_NODELAY, &intVal);
2127 return;
Dan Bornsteinfef88752009-11-04 15:34:14 -08002128#ifdef ENABLE_MULTICAST
Elliott Hughes4d8e9332010-05-03 14:31:03 -07002129 case JAVASOCKOPT_MCAST_ADD_MEMBERSHIP:
2130 mcastAddDropMembership(env, fd, optVal, IP_ADD_MEMBERSHIP);
2131 return;
2132 case JAVASOCKOPT_MCAST_DROP_MEMBERSHIP:
2133 mcastAddDropMembership(env, fd, optVal, IP_DROP_MEMBERSHIP);
2134 return;
2135 case JAVASOCKOPT_IP_MULTICAST_IF:
2136 {
2137 struct sockaddr_storage sockVal;
2138 if (!env->IsInstanceOf(optVal, gCachedFields.iaddr_class) ||
2139 !inetAddressToSocketAddress(env, optVal, 0, &sockVal)) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08002140 return;
2141 }
Lorenzo Colittibeeef8a2009-09-30 17:51:26 -07002142 // This call is IPv4 only. The socket may be IPv6, but the address
2143 // that identifies the interface to join must be an IPv4 address.
2144 if (sockVal.ss_family != AF_INET) {
Elliott Hughesa9a57f22009-10-30 17:54:32 -07002145 jniThrowSocketException(env, EAFNOSUPPORT);
Lorenzo Colitti65663e12009-05-26 15:51:50 -07002146 return;
2147 }
Mike Wakerly7076abb2009-03-24 18:37:27 -07002148 struct ip_mreqn mcast_req;
2149 memset(&mcast_req, 0, sizeof(mcast_req));
Elliott Hughes4d8e9332010-05-03 14:31:03 -07002150 mcast_req.imr_address = reinterpret_cast<sockaddr_in*>(&sockVal)->sin_addr;
2151 setSocketOption(env, fd, IPPROTO_IP, IP_MULTICAST_IF, &mcast_req);
Dan Bornsteinfef88752009-11-04 15:34:14 -08002152 return;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08002153 }
Elliott Hughes4d8e9332010-05-03 14:31:03 -07002154 case JAVASOCKOPT_IP_MULTICAST_IF2:
2155 if (family == AF_INET) {
2156 // IP_MULTICAST_IF expects a pointer to a struct ip_mreqn.
2157 struct ip_mreqn multicastRequest;
2158 memset(&multicastRequest, 0, sizeof(multicastRequest));
2159 multicastRequest.imr_ifindex = intVal;
2160 setSocketOption(env, fd, IPPROTO_IP, IP_MULTICAST_IF, &multicastRequest);
2161 } else {
2162 // IPV6_MULTICAST_IF expects a pointer to an integer.
2163 setSocketOption(env, fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &intVal);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08002164 }
Elliott Hughes4d8e9332010-05-03 14:31:03 -07002165 return;
Elliott Hughes4401c752010-05-04 09:47:02 -07002166 case JAVASOCKOPT_MULTICAST_TTL:
2167 if (family == AF_INET) {
2168 // Although IPv6 was cleaned up to use int, and IPv4 non-multicast TTL uses int,
2169 // IPv4 multicast TTL uses a byte.
2170 u_char ttl = intVal;
2171 setSocketOption(env, fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl);
2172 } else {
2173 setSocketOption(env, fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &intVal);
2174 }
2175 return;
Elliott Hughes4d8e9332010-05-03 14:31:03 -07002176 case JAVASOCKOPT_IP_MULTICAST_LOOP:
2177 if (family == AF_INET) {
Elliott Hughes4401c752010-05-04 09:47:02 -07002178 // Although IPv6 was cleaned up to use int, IPv4 multicast loopback uses a byte.
2179 u_char loopback = intVal;
2180 setSocketOption(env, fd, IPPROTO_IP, IP_MULTICAST_LOOP, &loopback);
Elliott Hughes4d8e9332010-05-03 14:31:03 -07002181 } else {
2182 setSocketOption(env, fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &intVal);
2183 }
2184 return;
2185#else
Elliott Hughes4401c752010-05-04 09:47:02 -07002186 case JAVASOCKOPT_MULTICAST_TTL:
Elliott Hughes4d8e9332010-05-03 14:31:03 -07002187 case JAVASOCKOPT_MCAST_ADD_MEMBERSHIP:
2188 case JAVASOCKOPT_MCAST_DROP_MEMBERSHIP:
2189 case JAVASOCKOPT_IP_MULTICAST_IF:
2190 case JAVASOCKOPT_IP_MULTICAST_IF2:
2191 case JAVASOCKOPT_IP_MULTICAST_LOOP:
2192 jniThrowException(env, "java/lang/UnsupportedOperationException", NULL);
2193 return;
2194#endif // def ENABLE_MULTICAST
2195 default:
2196 jniThrowSocketException(env, ENOPROTOOPT);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08002197 }
2198}
2199
Elliott Hughesd9d26302010-03-15 16:40:21 -07002200static void osNetworkSystem_socketClose(JNIEnv* env, jobject, jobject fileDescriptor) {
Elliott Hughes24912e02009-10-19 16:36:13 -07002201 int fd;
2202 if (!jniGetFd(env, fileDescriptor, fd)) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08002203 return;
2204 }
2205
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08002206 jniSetFileDescriptorOfFD(env, fileDescriptor, -1);
2207
Elliott Hughes24912e02009-10-19 16:36:13 -07002208 close(fd);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08002209}
2210
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08002211static JNINativeMethod gMethods[] = {
Elliott Hughesd9d26302010-03-15 16:40:21 -07002212 { "accept", "(Ljava/io/FileDescriptor;Ljava/net/SocketImpl;Ljava/io/FileDescriptor;I)V",(void*) osNetworkSystem_accept },
2213 { "bind", "(Ljava/io/FileDescriptor;Ljava/net/InetAddress;I)V", (void*) osNetworkSystem_bind },
2214 { "byteArrayToIpString", "([B)Ljava/lang/String;", (void*) osNetworkSystem_byteArrayToIpString },
2215 { "connectDatagram", "(Ljava/io/FileDescriptor;IILjava/net/InetAddress;)V", (void*) osNetworkSystem_connectDatagram },
2216 { "connectStreamWithTimeoutSocket", "(Ljava/io/FileDescriptor;IIILjava/net/InetAddress;)V", (void*) osNetworkSystem_connectStreamWithTimeoutSocket },
Elliott Hughesb375c0c2010-05-04 18:06:21 -07002217 { "connectWithTimeout", "(Ljava/io/FileDescriptor;IILjava/net/InetAddress;II[B)Z", (void*) osNetworkSystem_connectWithTimeout },
Elliott Hughesd9d26302010-03-15 16:40:21 -07002218 { "createDatagramSocket", "(Ljava/io/FileDescriptor;Z)V", (void*) osNetworkSystem_createDatagramSocket },
2219 { "createServerStreamSocket", "(Ljava/io/FileDescriptor;Z)V", (void*) osNetworkSystem_createServerStreamSocket },
2220 { "createStreamSocket", "(Ljava/io/FileDescriptor;Z)V", (void*) osNetworkSystem_createStreamSocket },
2221 { "disconnectDatagram", "(Ljava/io/FileDescriptor;)V", (void*) osNetworkSystem_disconnectDatagram },
2222 { "getSocketLocalAddress", "(Ljava/io/FileDescriptor;)Ljava/net/InetAddress;", (void*) osNetworkSystem_getSocketLocalAddress },
2223 { "getSocketLocalPort", "(Ljava/io/FileDescriptor;)I", (void*) osNetworkSystem_getSocketLocalPort },
2224 { "getSocketOption", "(Ljava/io/FileDescriptor;I)Ljava/lang/Object;", (void*) osNetworkSystem_getSocketOption },
2225 { "ipStringToByteArray", "(Ljava/lang/String;)[B", (void*) osNetworkSystem_ipStringToByteArray },
Elliott Hughes97144c82010-03-30 14:21:19 -07002226 { "listen", "(Ljava/io/FileDescriptor;I)V", (void*) osNetworkSystem_listen },
Elliott Hughesd9d26302010-03-15 16:40:21 -07002227 { "peekDatagram", "(Ljava/io/FileDescriptor;Ljava/net/InetAddress;I)I", (void*) osNetworkSystem_peekDatagram },
2228 { "readDirect", "(Ljava/io/FileDescriptor;III)I", (void*) osNetworkSystem_readDirect },
2229 { "readSocketImpl", "(Ljava/io/FileDescriptor;[BIII)I", (void*) osNetworkSystem_readSocketImpl },
2230 { "receiveDatagramDirect", "(Ljava/io/FileDescriptor;Ljava/net/DatagramPacket;IIIIZ)I", (void*) osNetworkSystem_receiveDatagramDirect },
2231 { "receiveDatagram", "(Ljava/io/FileDescriptor;Ljava/net/DatagramPacket;[BIIIZ)I", (void*) osNetworkSystem_receiveDatagram },
2232 { "recvConnectedDatagramDirect", "(Ljava/io/FileDescriptor;Ljava/net/DatagramPacket;IIIIZ)I", (void*) osNetworkSystem_recvConnectedDatagramDirect },
2233 { "recvConnectedDatagram", "(Ljava/io/FileDescriptor;Ljava/net/DatagramPacket;[BIIIZ)I", (void*) osNetworkSystem_recvConnectedDatagram },
2234 { "selectImpl", "([Ljava/io/FileDescriptor;[Ljava/io/FileDescriptor;II[IJ)Z", (void*) osNetworkSystem_selectImpl },
2235 { "sendConnectedDatagramDirect", "(Ljava/io/FileDescriptor;IIIZ)I", (void*) osNetworkSystem_sendConnectedDatagramDirect },
2236 { "sendConnectedDatagram", "(Ljava/io/FileDescriptor;[BIIZ)I", (void*) osNetworkSystem_sendConnectedDatagram },
2237 { "sendDatagramDirect", "(Ljava/io/FileDescriptor;IIIIZILjava/net/InetAddress;)I", (void*) osNetworkSystem_sendDatagramDirect },
2238 { "sendDatagram", "(Ljava/io/FileDescriptor;[BIIIZILjava/net/InetAddress;)I", (void*) osNetworkSystem_sendDatagram },
2239 { "sendDatagram2", "(Ljava/io/FileDescriptor;[BIIILjava/net/InetAddress;)I", (void*) osNetworkSystem_sendDatagram2 },
2240 { "sendUrgentData", "(Ljava/io/FileDescriptor;B)V", (void*) osNetworkSystem_sendUrgentData },
2241 { "setInetAddress", "(Ljava/net/InetAddress;[B)V", (void*) osNetworkSystem_setInetAddress },
2242 { "setNonBlocking", "(Ljava/io/FileDescriptor;Z)V", (void*) osNetworkSystem_setNonBlocking },
2243 { "setSocketOption", "(Ljava/io/FileDescriptor;ILjava/lang/Object;)V", (void*) osNetworkSystem_setSocketOption },
2244 { "shutdownInput", "(Ljava/io/FileDescriptor;)V", (void*) osNetworkSystem_shutdownInput },
2245 { "shutdownOutput", "(Ljava/io/FileDescriptor;)V", (void*) osNetworkSystem_shutdownOutput },
2246 { "socketClose", "(Ljava/io/FileDescriptor;)V", (void*) osNetworkSystem_socketClose },
2247 { "supportsUrgentData", "(Ljava/io/FileDescriptor;)Z", (void*) osNetworkSystem_supportsUrgentData },
2248 { "writeDirect", "(Ljava/io/FileDescriptor;III)I", (void*) osNetworkSystem_writeDirect },
2249 { "write", "(Ljava/io/FileDescriptor;[BII)I", (void*) osNetworkSystem_write },
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08002250};
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08002251int register_org_apache_harmony_luni_platform_OSNetworkSystem(JNIEnv* env) {
Elliott Hughes7861ea92009-11-12 12:23:05 -08002252 return initCachedFields(env) && jniRegisterNativeMethods(env,
Elliott Hughesc08f9fb2010-04-16 17:44:12 -07002253 "org/apache/harmony/luni/platform/OSNetworkSystem", gMethods, NELEM(gMethods));
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08002254}
Lorenzo Colittie8596902009-09-18 15:25:06 -07002255// END android-changed