Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 93bb2bf2 authored by Neil Fuller's avatar Neil Fuller Committed by Android Git Automerger
Browse files

am 761e39e1: Merge "Switch to using android.system.Os for more calls"

* commit '761e39e1':
  Switch to using android.system.Os for more calls
parents 4da086ee 761e39e1
Loading
Loading
Loading
Loading
+90 −33
Original line number Diff line number Diff line
@@ -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.
@@ -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)
        {
        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:
                return value;
                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:
                return value;
                    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);
        }
    }
}
+0 −206
Original line number Diff line number Diff line
@@ -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)