Switch to using android.system.Os for more calls
The methods being switched here should involve no important
semantic changes. socket.getSoTimeout() is now implemented:
previously it would have returned 0 in all cases.
Some tidy up of unimplemented / commented code.
Switching other calls to use Os would carry more risk and
will be handled separately they can be switched safely.
Bug: 3106438
Change-Id: I5526249395565fee6e43f159a2b5975b0d41d058
diff --git a/core/java/android/net/LocalSocketImpl.java b/core/java/android/net/LocalSocketImpl.java
index fa9f479..8823ab1 100644
--- a/core/java/android/net/LocalSocketImpl.java
+++ b/core/java/android/net/LocalSocketImpl.java
@@ -25,6 +25,8 @@
import android.system.ErrnoException;
import android.system.Os;
import android.system.OsConstants;
+import android.system.StructLinger;
+import android.system.StructTimeval;
/**
* Socket implementation used for android.net.LocalSocket and
@@ -184,13 +186,6 @@
private native void shutdown(FileDescriptor fd, boolean shutdownInput);
private native Credentials getPeerCredentials_native(
FileDescriptor fd) throws IOException;
- private native int getOption_native(FileDescriptor fd, int optID)
- throws IOException;
- private native void setOption_native(FileDescriptor fd, int optID,
- int b, int value) throws IOException;
-
-// private native LocalSocketAddress getSockName_native
-// (FileDescriptor fd) throws IOException;
/**
* Accepts a connection on a server socket.
@@ -232,7 +227,7 @@
* or {@link LocalSocket#SOCKET_SEQPACKET}
* @throws IOException
*/
- public void create (int sockType) throws IOException {
+ public void create(int sockType) throws IOException {
// no error if socket already created
// need this for LocalServerSocket.accept()
if (fd == null) {
@@ -434,24 +429,49 @@
throw new IOException("socket not created");
}
- if (optID == SocketOptions.SO_TIMEOUT) {
- return 0;
- }
-
- int value = getOption_native(fd, optID);
- switch (optID)
- {
- case SocketOptions.SO_RCVBUF:
- case SocketOptions.SO_SNDBUF:
- return value;
- case SocketOptions.SO_REUSEADDR:
- default:
- return value;
+ try {
+ Object toReturn;
+ switch (optID) {
+ case SocketOptions.SO_TIMEOUT:
+ StructTimeval timeval = Os.getsockoptTimeval(fd, OsConstants.SOL_SOCKET,
+ OsConstants.SO_SNDTIMEO);
+ toReturn = (int) timeval.toMillis();
+ break;
+ case SocketOptions.SO_RCVBUF:
+ case SocketOptions.SO_SNDBUF:
+ case SocketOptions.SO_REUSEADDR:
+ int osOpt = javaSoToOsOpt(optID);
+ toReturn = Os.getsockoptInt(fd, OsConstants.SOL_SOCKET, osOpt);
+ break;
+ case SocketOptions.SO_LINGER:
+ StructLinger linger=
+ Os.getsockoptLinger(fd, OsConstants.SOL_SOCKET, OsConstants.SO_LINGER);
+ if (!linger.isOn()) {
+ toReturn = -1;
+ } else {
+ toReturn = linger.l_linger;
+ }
+ break;
+ case SocketOptions.TCP_NODELAY:
+ toReturn = Os.getsockoptInt(fd, OsConstants.IPPROTO_TCP,
+ OsConstants.TCP_NODELAY);
+ break;
+ default:
+ throw new IOException("Unknown option: " + optID);
+ }
+ return toReturn;
+ } catch (ErrnoException e) {
+ throw e.rethrowAsIOException();
}
}
public void setOption(int optID, Object value)
throws IOException {
+
+ if (fd == null) {
+ throw new IOException("socket not created");
+ }
+
/*
* Boolean.FALSE is used to disable some options, so it
* is important to distinguish between FALSE and unset.
@@ -460,11 +480,6 @@
*/
int boolValue = -1;
int intValue = 0;
-
- if (fd == null) {
- throw new IOException("socket not created");
- }
-
if (value instanceof Integer) {
intValue = (Integer)value;
} else if (value instanceof Boolean) {
@@ -473,7 +488,39 @@
throw new IOException("bad value: " + value);
}
- setOption_native(fd, optID, boolValue, intValue);
+ try {
+ switch (optID) {
+ case SocketOptions.SO_LINGER:
+ StructLinger linger = new StructLinger(boolValue, intValue);
+ Os.setsockoptLinger(fd, OsConstants.SOL_SOCKET, OsConstants.SO_LINGER, linger);
+ break;
+ case SocketOptions.SO_TIMEOUT:
+ /*
+ * SO_TIMEOUT from the core library gets converted to
+ * SO_SNDTIMEO, but the option is supposed to set both
+ * send and receive timeouts. Note: The incoming timeout
+ * value is in milliseconds.
+ */
+ StructTimeval timeval = StructTimeval.fromMillis(intValue);
+ Os.setsockoptTimeval(fd, OsConstants.SOL_SOCKET, OsConstants.SO_SNDTIMEO,
+ timeval);
+ break;
+ case SocketOptions.SO_RCVBUF:
+ case SocketOptions.SO_SNDBUF:
+ case SocketOptions.SO_REUSEADDR:
+ int osOpt = javaSoToOsOpt(optID);
+ Os.setsockoptInt(fd, OsConstants.SOL_SOCKET, osOpt, intValue);
+ break;
+ case SocketOptions.TCP_NODELAY:
+ Os.setsockoptInt(fd, OsConstants.IPPROTO_TCP, OsConstants.TCP_NODELAY,
+ intValue);
+ break;
+ default:
+ throw new IOException("Unknown option: " + optID);
+ }
+ } catch (ErrnoException e) {
+ throw e.rethrowAsIOException();
+ }
}
/**
@@ -517,8 +564,7 @@
* @return non-null; peer credentials
* @throws IOException
*/
- public Credentials getPeerCredentials() throws IOException
- {
+ public Credentials getPeerCredentials() throws IOException {
return getPeerCredentials_native(fd);
}
@@ -528,15 +574,26 @@
* @return non-null; socket name
* @throws IOException on failure
*/
- public LocalSocketAddress getSockAddress() throws IOException
- {
+ public LocalSocketAddress getSockAddress() throws IOException {
+ // This method has never been implemented.
return null;
- //TODO implement this
- //return getSockName_native(fd);
}
@Override
protected void finalize() throws IOException {
close();
}
+
+ private static int javaSoToOsOpt(int optID) {
+ switch (optID) {
+ case SocketOptions.SO_SNDBUF:
+ return OsConstants.SO_SNDBUF;
+ case SocketOptions.SO_RCVBUF:
+ return OsConstants.SO_RCVBUF;
+ case SocketOptions.SO_REUSEADDR:
+ return OsConstants.SO_REUSEADDR;
+ default:
+ throw new UnsupportedOperationException("Unknown option: " + optID);
+ }
+ }
}
diff --git a/core/jni/android_net_LocalSocketImpl.cpp b/core/jni/android_net_LocalSocketImpl.cpp
index 97abe6b..ee6997d 100644
--- a/core/jni/android_net_LocalSocketImpl.cpp
+++ b/core/jni/android_net_LocalSocketImpl.cpp
@@ -199,156 +199,6 @@
}
}
-static bool
-java_opt_to_real(int optID, int* opt, int* level)
-{
- switch (optID)
- {
- case 4098:
- *opt = SO_RCVBUF;
- *level = SOL_SOCKET;
- return true;
- case 4097:
- *opt = SO_SNDBUF;
- *level = SOL_SOCKET;
- return true;
- case 4102:
- *opt = SO_SNDTIMEO;
- *level = SOL_SOCKET;
- return true;
- case 128:
- *opt = SO_LINGER;
- *level = SOL_SOCKET;
- return true;
- case 1:
- *opt = TCP_NODELAY;
- *level = IPPROTO_TCP;
- return true;
- case 4:
- *opt = SO_REUSEADDR;
- *level = SOL_SOCKET;
- return true;
-
- }
- return false;
-}
-
-static jint
-socket_getOption(JNIEnv *env, jobject object, jobject fileDescriptor, jint optID)
-{
- int ret, value;
- int opt, level;
- int fd;
-
- socklen_t size = sizeof(int);
-
- if (!java_opt_to_real(optID, &opt, &level)) {
- jniThrowIOException(env, -1);
- return 0;
- }
-
- fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
-
- if (env->ExceptionCheck()) {
- return 0;
- }
-
- switch (opt)
- {
- case SO_LINGER:
- {
- struct linger lingr;
- size = sizeof(lingr);
- ret = getsockopt(fd, level, opt, &lingr, &size);
- if (!lingr.l_onoff) {
- value = -1;
- } else {
- value = lingr.l_linger;
- }
- break;
- }
- default:
- ret = getsockopt(fd, level, opt, &value, &size);
- break;
- }
-
-
- if (ret != 0) {
- jniThrowIOException(env, errno);
- return 0;
- }
-
- return value;
-}
-
-static void socket_setOption(
- JNIEnv *env, jobject object, jobject fileDescriptor, jint optID,
- jint boolValue, jint intValue) {
- int ret;
- int optname;
- int level;
- int fd;
-
- if (!java_opt_to_real(optID, &optname, &level)) {
- jniThrowIOException(env, -1);
- return;
- }
-
- fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
-
- if (env->ExceptionCheck()) {
- return;
- }
-
- switch (optname) {
- case SO_LINGER: {
- /*
- * SO_LINGER is special because it needs to use a special
- * "linger" struct as well as use the incoming boolean
- * argument specially.
- */
- struct linger lingr;
- lingr.l_onoff = boolValue ? 1 : 0; // Force it to be 0 or 1.
- lingr.l_linger = intValue;
- ret = setsockopt(fd, level, optname, &lingr, sizeof(lingr));
- break;
- }
- case SO_SNDTIMEO: {
- /*
- * SO_TIMEOUT from the core library gets converted to
- * SO_SNDTIMEO, but the option is supposed to set both
- * send and receive timeouts. Note: The incoming timeout
- * value is in milliseconds.
- */
- struct timeval timeout;
- timeout.tv_sec = intValue / 1000;
- timeout.tv_usec = (intValue % 1000) * 1000;
-
- ret = setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO,
- (void *)&timeout, sizeof(timeout));
-
- if (ret == 0) {
- ret = setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO,
- (void *)&timeout, sizeof(timeout));
- }
-
- break;
- }
- default: {
- /*
- * In all other cases, the translated option level and
- * optname may be used directly for a call to setsockopt().
- */
- ret = setsockopt(fd, level, optname, &intValue, sizeof(intValue));
- break;
- }
- }
-
- if (ret != 0) {
- jniThrowIOException(env, errno);
- return;
- }
-}
static jint socket_pending (JNIEnv *env, jobject object,
jobject fileDescriptor)
{
@@ -803,64 +653,11 @@
creds.pid, creds.uid, creds.gid);
}
-#if 0
-//TODO change this to return an instance of LocalSocketAddress
-static jobject socket_getSockName(JNIEnv *env,
- jobject object, jobject fileDescriptor)
-{
- int err;
- int fd;
-
- if (fileDescriptor == NULL) {
- jniThrowNullPointerException(env, NULL);
- return NULL;
- }
-
- fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
-
- if (env->ExceptionCheck()) {
- return NULL;
- }
-
- union {
- struct sockaddr address;
- struct sockaddr_un un_address;
- } sa;
-
- memset(&sa, 0, sizeof(sa));
-
- socklen_t namelen = sizeof(sa);
- err = getsockname(fd, &(sa.address), &namelen);
-
- if (err < 0) {
- jniThrowIOException(env, errno);
- return NULL;
- }
-
- if (sa.address.sa_family != AF_UNIX) {
- // We think we're an impl only for AF_UNIX, so this should never happen.
-
- jniThrowIOException(env, EINVAL);
- return NULL;
- }
-
- if (sa.un_address.sun_path[0] == '\0') {
- } else {
- }
-
-
-
-
-}
-#endif
-
/*
* JNI registration.
*/
static JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
- {"getOption_native", "(Ljava/io/FileDescriptor;I)I", (void*)socket_getOption},
- {"setOption_native", "(Ljava/io/FileDescriptor;III)V", (void*)socket_setOption},
{"connectLocal", "(Ljava/io/FileDescriptor;Ljava/lang/String;I)V",
(void*)socket_connect_local},
{"bindLocal", "(Ljava/io/FileDescriptor;Ljava/lang/String;I)V", (void*)socket_bind_local},
@@ -876,9 +673,6 @@
{"getPeerCredentials_native",
"(Ljava/io/FileDescriptor;)Landroid/net/Credentials;",
(void*) socket_get_peer_credentials}
- //,{"getSockName_native", "(Ljava/io/FileDescriptor;)Ljava/lang/String;",
- // (void *) socket_getSockName}
-
};
int register_android_net_LocalSocketImpl(JNIEnv *env)