19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2006 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define LOG_TAG "LocalSocketImpl"
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
192279b2534272282a5b5152723235da397e49195cSteven Moreland#include <nativehelper/JNIHelp.h>
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "jni.h"
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "utils/Log.h"
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "utils/misc.h"
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <stdio.h>
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <string.h>
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <sys/types.h>
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <sys/socket.h>
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <sys/un.h>
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <arpa/inet.h>
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <netinet/in.h>
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <stdlib.h>
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <errno.h>
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <unistd.h>
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <sys/ioctl.h>
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <cutils/sockets.h>
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <netinet/tcp.h>
382279b2534272282a5b5152723235da397e49195cSteven Moreland#include <nativehelper/ScopedUtfChars.h>
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectnamespace android {
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
420f0b4919667f418b249c497f5ad3e83fdf4437e5Andreas Gampetemplate <typename T>
430f0b4919667f418b249c497f5ad3e83fdf4437e5Andreas Gampevoid UNUSED(T t) {}
440f0b4919667f418b249c497f5ad3e83fdf4437e5Andreas Gampe
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic jfieldID field_inboundFileDescriptors;
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic jfieldID field_outboundFileDescriptors;
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic jclass class_Credentials;
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic jclass class_FileDescriptor;
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic jmethodID method_CredentialsInit;
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* private native void connectLocal(FileDescriptor fd,
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * String name, int namespace) throws IOException
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic void
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectsocket_connect_local(JNIEnv *env, jobject object,
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        jobject fileDescriptor, jstring name, jint namespaceId)
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int ret;
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int fd;
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6398671c34fa00a79c62ff0d9d874428bed1f86e92Mathieu Chartier    if (env->ExceptionCheck()) {
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return;
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
67092eb8d43baffd7723bc7847c180a32fb5269481You Kim    ScopedUtfChars nameUtf8(env, name);
68092eb8d43baffd7723bc7847c180a32fb5269481You Kim
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ret = socket_local_client_connect(
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                fd,
71092eb8d43baffd7723bc7847c180a32fb5269481You Kim                nameUtf8.c_str(),
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                namespaceId,
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                SOCK_STREAM);
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (ret < 0) {
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        jniThrowIOException(env, errno);
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return;
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define DEFAULT_BACKLOG 4
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8369a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes/* private native void bindLocal(FileDescriptor fd, String name, namespace)
8469a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes * throws IOException;
8569a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes */
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic void
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectsocket_bind_local (JNIEnv *env, jobject object, jobject fileDescriptor,
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                jstring name, jint namespaceId)
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int ret;
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int fd;
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (name == NULL) {
9569a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes        jniThrowNullPointerException(env, NULL);
96092eb8d43baffd7723bc7847c180a32fb5269481You Kim        return;
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10198671c34fa00a79c62ff0d9d874428bed1f86e92Mathieu Chartier    if (env->ExceptionCheck()) {
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return;
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
105092eb8d43baffd7723bc7847c180a32fb5269481You Kim    ScopedUtfChars nameUtf8(env, name);
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
107092eb8d43baffd7723bc7847c180a32fb5269481You Kim    ret = socket_local_server_bind(fd, nameUtf8.c_str(), namespaceId);
10869a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (ret < 0) {
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        jniThrowIOException(env, errno);
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return;
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
11669a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes * Processes ancillary data, handling only
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * SCM_RIGHTS. Creates appropriate objects and sets appropriate
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * fields in the LocalSocketImpl object. Returns 0 on success
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * or -1 if an exception was thrown.
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic int socket_process_cmsg(JNIEnv *env, jobject thisJ, struct msghdr * pMsg)
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    struct cmsghdr *cmsgptr;
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12569a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes    for (cmsgptr = CMSG_FIRSTHDR(pMsg);
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            cmsgptr != NULL; cmsgptr = CMSG_NXTHDR(pMsg, cmsgptr)) {
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (cmsgptr->cmsg_level != SOL_SOCKET) {
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            continue;
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (cmsgptr->cmsg_type == SCM_RIGHTS) {
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int *pDescriptors = (int *)CMSG_DATA(cmsgptr);
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            jobjectArray fdArray;
13569a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes            int count
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                = ((cmsgptr->cmsg_len - CMSG_LEN(0)) / sizeof(int));
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (count < 0) {
13969a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes                jniThrowException(env, "java/io/IOException",
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    "invalid cmsg length");
141092eb8d43baffd7723bc7847c180a32fb5269481You Kim                return -1;
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fdArray = env->NewObjectArray(count, class_FileDescriptor, NULL);
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (fdArray == NULL) {
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return -1;
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < count; i++) {
15169a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes                jobject fdObject
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        = jniCreateFileDescriptor(env, pDescriptors[i]);
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15498671c34fa00a79c62ff0d9d874428bed1f86e92Mathieu Chartier                if (env->ExceptionCheck()) {
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return -1;
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                env->SetObjectArrayElement(fdArray, i, fdObject);
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16098671c34fa00a79c62ff0d9d874428bed1f86e92Mathieu Chartier                if (env->ExceptionCheck()) {
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return -1;
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            env->SetObjectField(thisJ, field_inboundFileDescriptors, fdArray);
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16798671c34fa00a79c62ff0d9d874428bed1f86e92Mathieu Chartier            if (env->ExceptionCheck()) {
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return -1;
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return 0;
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Reads data from a socket into buf, processing any ancillary data
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * and adding it to thisJ.
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns the length of normal data read, or -1 if an exception has
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * been thrown in this function.
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
18369a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughesstatic ssize_t socket_read_all(JNIEnv *env, jobject thisJ, int fd,
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        void *buffer, size_t len)
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ssize_t ret;
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    struct msghdr msg;
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    struct iovec iv;
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    unsigned char *buf = (unsigned char *)buffer;
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Enough buffer for a pile of fd's. We throw an exception if
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // this buffer is too small.
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    struct cmsghdr cmsgbuf[2*sizeof(cmsghdr) + 0x100];
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    memset(&msg, 0, sizeof(msg));
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    memset(&iv, 0, sizeof(iv));
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    iv.iov_base = buf;
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    iv.iov_len = len;
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    msg.msg_iov = &iv;
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    msg.msg_iovlen = 1;
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    msg.msg_control = cmsgbuf;
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    msg.msg_controllen = sizeof(cmsgbuf);
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
205b0e5079b5dc37641741c3ea370376261aa06667fNick Kralevich    ret = TEMP_FAILURE_RETRY(recvmsg(fd, &msg, MSG_NOSIGNAL | MSG_CMSG_CLOEXEC));
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (ret < 0 && errno == EPIPE) {
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Treat this as an end of stream
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return 0;
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (ret < 0) {
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        jniThrowIOException(env, errno);
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return -1;
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if ((msg.msg_flags & (MSG_CTRUNC | MSG_OOB | MSG_ERRQUEUE)) != 0) {
2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // To us, any of the above flags are a fatal error
2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
22069a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes        jniThrowException(env, "java/io/IOException",
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                "Unexpected error or truncation during recvmsg()");
2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return -1;
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (ret >= 0) {
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        socket_process_cmsg(env, thisJ, &msg);
2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return ret;
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Writes all the data in the specified buffer to the specified socket.
2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns 0 on success or -1 if an exception was thrown.
2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic int socket_write_all(JNIEnv *env, jobject object, int fd,
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        void *buf, size_t len)
2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ssize_t ret;
2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    struct msghdr msg;
2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    unsigned char *buffer = (unsigned char *)buf;
2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    memset(&msg, 0, sizeof(msg));
2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
24669a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes    jobjectArray outboundFds
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            = (jobjectArray)env->GetObjectField(
2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                object, field_outboundFileDescriptors);
2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
25098671c34fa00a79c62ff0d9d874428bed1f86e92Mathieu Chartier    if (env->ExceptionCheck()) {
2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return -1;
2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    struct cmsghdr *cmsg;
2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int countFds = outboundFds == NULL ? 0 : env->GetArrayLength(outboundFds);
2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int fds[countFds];
2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    char msgbuf[CMSG_SPACE(countFds)];
2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Add any pending outbound file descriptors to the message
2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (outboundFds != NULL) {
2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
26298671c34fa00a79c62ff0d9d874428bed1f86e92Mathieu Chartier        if (env->ExceptionCheck()) {
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return -1;
2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < countFds; i++) {
2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            jobject fdObject = env->GetObjectArrayElement(outboundFds, i);
26898671c34fa00a79c62ff0d9d874428bed1f86e92Mathieu Chartier            if (env->ExceptionCheck()) {
2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return -1;
2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fds[i] = jniGetFDFromFileDescriptor(env, fdObject);
27398671c34fa00a79c62ff0d9d874428bed1f86e92Mathieu Chartier            if (env->ExceptionCheck()) {
2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return -1;
2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // See "man cmsg" really
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        msg.msg_control = msgbuf;
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        msg.msg_controllen = sizeof msgbuf;
2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        cmsg = CMSG_FIRSTHDR(&msg);
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        cmsg->cmsg_level = SOL_SOCKET;
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        cmsg->cmsg_type = SCM_RIGHTS;
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        cmsg->cmsg_len = CMSG_LEN(sizeof fds);
2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        memcpy(CMSG_DATA(cmsg), fds, sizeof fds);
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // We only write our msg_control during the first write
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    while (len > 0) {
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        struct iovec iv;
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        memset(&iv, 0, sizeof(iv));
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        iv.iov_base = buffer;
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        iv.iov_len = len;
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        msg.msg_iov = &iv;
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        msg.msg_iovlen = 1;
29869a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        do {
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ret = sendmsg(fd, &msg, MSG_NOSIGNAL);
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } while (ret < 0 && errno == EINTR);
3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (ret < 0) {
3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            jniThrowIOException(env, errno);
3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return -1;
3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        buffer += ret;
3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        len -= ret;
3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Wipes out any msg_control too
3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        memset(&msg, 0, sizeof(msg));
3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return 0;
3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic jint socket_read (JNIEnv *env, jobject object, jobject fileDescriptor)
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int fd;
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int err;
3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (fileDescriptor == NULL) {
32469a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes        jniThrowNullPointerException(env, NULL);
3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (jint)-1;
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
33098671c34fa00a79c62ff0d9d874428bed1f86e92Mathieu Chartier    if (env->ExceptionCheck()) {
3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (jint)0;
3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    unsigned char buf;
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    err = socket_read_all(env, object, fd, &buf, 1);
3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (err < 0) {
3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        jniThrowIOException(env, errno);
3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (jint)0;
3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (err == 0) {
3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // end of file
3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (jint)-1;
3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return (jint)buf;
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
35169a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughesstatic jint socket_readba (JNIEnv *env, jobject object,
3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        jbyteArray buffer, jint off, jint len, jobject fileDescriptor)
3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int fd;
3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    jbyte* byteBuffer;
3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int ret;
3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (fileDescriptor == NULL || buffer == NULL) {
35969a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes        jniThrowNullPointerException(env, NULL);
3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (jint)-1;
3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (off < 0 || len < 0 || (off + len) > env->GetArrayLength(buffer)) {
3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", NULL);
3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (jint)-1;
3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (len == 0) {
3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // because socket_read_all returns 0 on EOF
3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return 0;
3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
37598671c34fa00a79c62ff0d9d874428bed1f86e92Mathieu Chartier    if (env->ExceptionCheck()) {
3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (jint)-1;
3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    byteBuffer = env->GetByteArrayElements(buffer, NULL);
3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (NULL == byteBuffer) {
3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // an exception will have been thrown
3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (jint)-1;
3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
38669a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes    ret = socket_read_all(env, object,
3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fd, byteBuffer + off, len);
3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // A return of -1 above means an exception is pending
3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    env->ReleaseByteArrayElements(buffer, byteBuffer, 0);
3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return (jint) ((ret == 0) ? -1 : ret);
3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
39669a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughesstatic void socket_write (JNIEnv *env, jobject object,
3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        jint b, jobject fileDescriptor)
3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int fd;
4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int err;
4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (fileDescriptor == NULL) {
40369a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes        jniThrowNullPointerException(env, NULL);
4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return;
4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
40998671c34fa00a79c62ff0d9d874428bed1f86e92Mathieu Chartier    if (env->ExceptionCheck()) {
4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return;
4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    err = socket_write_all(env, object, fd, &b, 1);
4140f0b4919667f418b249c497f5ad3e83fdf4437e5Andreas Gampe    UNUSED(err);
4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // A return of -1 above means an exception is pending
4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
41869a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughesstatic void socket_writeba (JNIEnv *env, jobject object,
4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        jbyteArray buffer, jint off, jint len, jobject fileDescriptor)
4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int fd;
4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int err;
4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    jbyte* byteBuffer;
4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (fileDescriptor == NULL || buffer == NULL) {
42669a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes        jniThrowNullPointerException(env, NULL);
4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return;
4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (off < 0 || len < 0 || (off + len) > env->GetArrayLength(buffer)) {
4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", NULL);
4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return;
4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
43798671c34fa00a79c62ff0d9d874428bed1f86e92Mathieu Chartier    if (env->ExceptionCheck()) {
4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return;
4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    byteBuffer = env->GetByteArrayElements(buffer,NULL);
4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (NULL == byteBuffer) {
4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // an exception will have been thrown
4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return;
4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
44869a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes    err = socket_write_all(env, object, fd,
4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            byteBuffer + off, len);
4500f0b4919667f418b249c497f5ad3e83fdf4437e5Andreas Gampe    UNUSED(err);
4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // A return of -1 above means an exception is pending
4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    env->ReleaseByteArrayElements(buffer, byteBuffer, JNI_ABORT);
4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
45669a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughesstatic jobject socket_get_peer_credentials(JNIEnv *env,
4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        jobject object, jobject fileDescriptor)
4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int err;
4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int fd;
4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (fileDescriptor == NULL) {
46369a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes        jniThrowNullPointerException(env, NULL);
4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return NULL;
4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
46998671c34fa00a79c62ff0d9d874428bed1f86e92Mathieu Chartier    if (env->ExceptionCheck()) {
4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return NULL;
4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    struct ucred creds;
4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    memset(&creds, 0, sizeof(creds));
4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    socklen_t szCreds = sizeof(creds);
4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
47869a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes    err = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &creds, &szCreds);
4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (err < 0) {
4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        jniThrowIOException(env, errno);
4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return NULL;
4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (szCreds == 0) {
4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return NULL;
4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
48969a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes    return env->NewObject(class_Credentials, method_CredentialsInit,
4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            creds.pid, creds.uid, creds.gid);
4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * JNI registration.
4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
49676f6a86de25e1bf74717e047e55fd44b089673f3Daniel Micaystatic const JNINativeMethod gMethods[] = {
4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     /* name, signature, funcPtr */
4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    {"connectLocal", "(Ljava/io/FileDescriptor;Ljava/lang/String;I)V",
4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                (void*)socket_connect_local},
5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    {"bindLocal", "(Ljava/io/FileDescriptor;Ljava/lang/String;I)V", (void*)socket_bind_local},
5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    {"read_native", "(Ljava/io/FileDescriptor;)I", (void*) socket_read},
5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    {"readba_native", "([BIILjava/io/FileDescriptor;)I", (void*) socket_readba},
5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    {"writeba_native", "([BIILjava/io/FileDescriptor;)V", (void*) socket_writeba},
5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    {"write_native", "(ILjava/io/FileDescriptor;)V", (void*) socket_write},
50569a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes    {"getPeerCredentials_native",
50669a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes            "(Ljava/io/FileDescriptor;)Landroid/net/Credentials;",
5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            (void*) socket_get_peer_credentials}
5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project};
5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectint register_android_net_LocalSocketImpl(JNIEnv *env)
5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    jclass clazz;
5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    clazz = env->FindClass("android/net/LocalSocketImpl");
5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (clazz == NULL) {
5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto error;
5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
52069a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes    field_inboundFileDescriptors = env->GetFieldID(clazz,
5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            "inboundFileDescriptors", "[Ljava/io/FileDescriptor;");
5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (field_inboundFileDescriptors == NULL) {
5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto error;
5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
52769a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes    field_outboundFileDescriptors = env->GetFieldID(clazz,
5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            "outboundFileDescriptors", "[Ljava/io/FileDescriptor;");
5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (field_outboundFileDescriptors == NULL) {
5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto error;
5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    class_Credentials = env->FindClass("android/net/Credentials");
53569a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes
5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (class_Credentials == NULL) {
5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto error;
5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    class_Credentials = (jclass)env->NewGlobalRef(class_Credentials);
5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    class_FileDescriptor = env->FindClass("java/io/FileDescriptor");
5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (class_FileDescriptor == NULL) {
5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto error;
5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    class_FileDescriptor = (jclass)env->NewGlobalRef(class_FileDescriptor);
5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
55069a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes    method_CredentialsInit
5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            = env->GetMethodID(class_Credentials, "<init>", "(III)V");
5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (method_CredentialsInit == NULL) {
5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto error;
5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return jniRegisterNativeMethods(env,
5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "android/net/LocalSocketImpl", gMethods, NELEM(gMethods));
5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projecterror:
5613762c311729fe9f3af085c14c5c1fb471d994c03Steve Block    ALOGE("Error registering android.net.LocalSocketImpl");
5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return -1;
5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project};
566