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)