From c80af6d84d8fb729f17028ac533fac07bb7c4c5d Mon Sep 17 00:00:00 2001 From: Neil Fuller Date: Fri, 3 Jul 2015 10:59:17 +0100 Subject: [PATCH] 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 --- core/java/android/net/LocalSocketImpl.java | 123 ++++++++++++----- core/jni/android_net_LocalSocketImpl.cpp | 206 ----------------------------- 2 files changed, 90 insertions(+), 239 deletions(-) diff --git a/core/java/android/net/LocalSocketImpl.java b/core/java/android/net/LocalSocketImpl.java index fa9f4790389f..8823ab14aa80 100644 --- a/core/java/android/net/LocalSocketImpl.java +++ b/core/java/android/net/LocalSocketImpl.java @@ -25,6 +25,8 @@ import java.net.SocketOptions; 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 @@ class LocalSocketImpl 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 @@ class LocalSocketImpl * 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 @@ class LocalSocketImpl 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 @@ class LocalSocketImpl */ 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 @@ class LocalSocketImpl 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 @@ class LocalSocketImpl * @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 @@ class LocalSocketImpl * @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 97abe6bb7324..ee6997d5a463 100644 --- a/core/jni/android_net_LocalSocketImpl.cpp +++ b/core/jni/android_net_LocalSocketImpl.cpp @@ -199,156 +199,6 @@ socket_shutdown (JNIEnv *env, jobject object, jobject fileDescriptor, } } -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 @@ static jobject socket_get_peer_credentials(JNIEnv *env, 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 @@ static JNINativeMethod gMethods[] = { {"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) -- 2.11.0