Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright (C) 2006 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #define LOG_TAG "LocalSocketImpl"
     18 
     19 #include "JNIHelp.h"
     20 #include "jni.h"
     21 #include "utils/Log.h"
     22 #include "utils/misc.h"
     23 
     24 #include <stdio.h>
     25 #include <string.h>
     26 #include <sys/types.h>
     27 #include <sys/socket.h>
     28 #include <sys/un.h>
     29 #include <arpa/inet.h>
     30 #include <netinet/in.h>
     31 #include <stdlib.h>
     32 #include <errno.h>
     33 #include <unistd.h>
     34 #include <sys/ioctl.h>
     35 
     36 #include <cutils/sockets.h>
     37 #include <netinet/tcp.h>
     38 
     39 namespace android {
     40 
     41 static jfieldID field_inboundFileDescriptors;
     42 static jfieldID field_outboundFileDescriptors;
     43 static jclass class_Credentials;
     44 static jclass class_FileDescriptor;
     45 static jmethodID method_CredentialsInit;
     46 
     47 /*
     48  * private native FileDescriptor
     49  * create_native(boolean stream)
     50  *               throws IOException;
     51  */
     52 static jobject
     53 socket_create (JNIEnv *env, jobject object, jboolean stream)
     54 {
     55     int ret;
     56 
     57     ret = socket(PF_LOCAL, stream ? SOCK_STREAM : SOCK_DGRAM, 0);
     58 
     59     if (ret < 0) {
     60         jniThrowIOException(env, errno);
     61         return NULL;
     62     }
     63 
     64     return jniCreateFileDescriptor(env,ret);
     65 }
     66 
     67 /* private native void connectLocal(FileDescriptor fd,
     68  * String name, int namespace) throws IOException
     69  */
     70 static void
     71 socket_connect_local(JNIEnv *env, jobject object,
     72                         jobject fileDescriptor, jstring name, jint namespaceId)
     73 {
     74     int ret;
     75     const char *nameUtf8;
     76     int fd;
     77 
     78     nameUtf8 = env->GetStringUTFChars(name, NULL);
     79 
     80     fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
     81 
     82     if (env->ExceptionOccurred() != NULL) {
     83         return;
     84     }
     85 
     86     ret = socket_local_client_connect(
     87                 fd,
     88                 nameUtf8,
     89                 namespaceId,
     90                 SOCK_STREAM);
     91 
     92     env->ReleaseStringUTFChars(name, nameUtf8);
     93 
     94     if (ret < 0) {
     95         jniThrowIOException(env, errno);
     96         return;
     97     }
     98 }
     99 
    100 #define DEFAULT_BACKLOG 4
    101 
    102 /* private native void bindLocal(FileDescriptor fd, String name, namespace)
    103  * throws IOException;
    104  */
    105 
    106 static void
    107 socket_bind_local (JNIEnv *env, jobject object, jobject fileDescriptor,
    108                 jstring name, jint namespaceId)
    109 {
    110     int ret;
    111     int fd;
    112     const char *nameUtf8;
    113 
    114 
    115     if (name == NULL) {
    116         jniThrowNullPointerException(env, NULL);
    117     }
    118 
    119     fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
    120 
    121     if (env->ExceptionOccurred() != NULL) {
    122         return;
    123     }
    124 
    125     nameUtf8 = env->GetStringUTFChars(name, NULL);
    126 
    127     ret = socket_local_server_bind(fd, nameUtf8, namespaceId);
    128 
    129     env->ReleaseStringUTFChars(name, nameUtf8);
    130 
    131     if (ret < 0) {
    132         jniThrowIOException(env, errno);
    133         return;
    134     }
    135 }
    136 
    137 /* private native void listen_native(int fd, int backlog) throws IOException; */
    138 static void
    139 socket_listen (JNIEnv *env, jobject object, jobject fileDescriptor, int backlog)
    140 {
    141     int ret;
    142     int fd;
    143 
    144     fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
    145 
    146     if (env->ExceptionOccurred() != NULL) {
    147         return;
    148     }
    149 
    150     ret = listen(fd, backlog);
    151 
    152     if (ret < 0) {
    153         jniThrowIOException(env, errno);
    154         return;
    155     }
    156 }
    157 
    158 /*    private native FileDescriptor
    159 **    accept (FileDescriptor fd, LocalSocketImpl s)
    160 **                                   throws IOException;
    161 */
    162 static jobject
    163 socket_accept (JNIEnv *env, jobject object, jobject fileDescriptor, jobject s)
    164 {
    165     union {
    166         struct sockaddr address;
    167         struct sockaddr_un un_address;
    168     } sa;
    169 
    170     int ret;
    171     int retFD;
    172     int fd;
    173     socklen_t addrlen;
    174 
    175     if (s == NULL) {
    176         jniThrowNullPointerException(env, NULL);
    177         return NULL;
    178     }
    179 
    180     fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
    181 
    182     if (env->ExceptionOccurred() != NULL) {
    183         return NULL;
    184     }
    185 
    186     do {
    187         addrlen = sizeof(sa);
    188         ret = accept(fd, &(sa.address), &addrlen);
    189     } while (ret < 0 && errno == EINTR);
    190 
    191     if (ret < 0) {
    192         jniThrowIOException(env, errno);
    193         return NULL;
    194     }
    195 
    196     retFD = ret;
    197 
    198     return jniCreateFileDescriptor(env, retFD);
    199 }
    200 
    201 /* private native void shutdown(FileDescriptor fd, boolean shutdownInput) */
    202 
    203 static void
    204 socket_shutdown (JNIEnv *env, jobject object, jobject fileDescriptor,
    205                     jboolean shutdownInput)
    206 {
    207     int ret;
    208     int fd;
    209 
    210     fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
    211 
    212     if (env->ExceptionOccurred() != NULL) {
    213         return;
    214     }
    215 
    216     ret = shutdown(fd, shutdownInput ? SHUT_RD : SHUT_WR);
    217 
    218     if (ret < 0) {
    219         jniThrowIOException(env, errno);
    220         return;
    221     }
    222 }
    223 
    224 static bool
    225 java_opt_to_real(int optID, int* opt, int* level)
    226 {
    227     switch (optID)
    228     {
    229         case 4098:
    230             *opt = SO_RCVBUF;
    231             *level = SOL_SOCKET;
    232             return true;
    233         case 4097:
    234             *opt = SO_SNDBUF;
    235             *level = SOL_SOCKET;
    236             return true;
    237         case 4102:
    238             *opt = SO_SNDTIMEO;
    239             *level = SOL_SOCKET;
    240             return true;
    241         case 128:
    242             *opt = SO_LINGER;
    243             *level = SOL_SOCKET;
    244             return true;
    245         case 1:
    246             *opt = TCP_NODELAY;
    247             *level = IPPROTO_TCP;
    248             return true;
    249         case 4:
    250             *opt = SO_REUSEADDR;
    251             *level = SOL_SOCKET;
    252             return true;
    253 
    254     }
    255     return false;
    256 }
    257 
    258 static jint
    259 socket_getOption(JNIEnv *env, jobject object, jobject fileDescriptor, int optID)
    260 {
    261     int ret, value;
    262     int opt, level;
    263     int fd;
    264 
    265     socklen_t size = sizeof(int);
    266 
    267     if (!java_opt_to_real(optID, &opt, &level)) {
    268         jniThrowIOException(env, -1);
    269         return 0;
    270     }
    271 
    272     fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
    273 
    274     if (env->ExceptionOccurred() != NULL) {
    275         return 0;
    276     }
    277 
    278     switch (opt)
    279     {
    280         case SO_LINGER:
    281         {
    282             struct linger lingr;
    283             size = sizeof(lingr);
    284             ret = getsockopt(fd, level, opt, &lingr, &size);
    285             if (!lingr.l_onoff) {
    286                 value = -1;
    287             } else {
    288                 value = lingr.l_linger;
    289             }
    290             break;
    291         }
    292         default:
    293             ret = getsockopt(fd, level, opt, &value, &size);
    294             break;
    295     }
    296 
    297 
    298     if (ret != 0) {
    299         jniThrowIOException(env, errno);
    300         return 0;
    301     }
    302 
    303     return value;
    304 }
    305 
    306 static void socket_setOption(
    307         JNIEnv *env, jobject object, jobject fileDescriptor, int optID,
    308         jint boolValue, jint intValue) {
    309     int ret;
    310     int optname;
    311     int level;
    312     int fd;
    313 
    314     if (!java_opt_to_real(optID, &optname, &level)) {
    315         jniThrowIOException(env, -1);
    316         return;
    317     }
    318 
    319     fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
    320 
    321     if (env->ExceptionOccurred() != NULL) {
    322         return;
    323     }
    324 
    325     switch (optname) {
    326         case SO_LINGER: {
    327             /*
    328              * SO_LINGER is special because it needs to use a special
    329              * "linger" struct as well as use the incoming boolean
    330              * argument specially.
    331              */
    332             struct linger lingr;
    333             lingr.l_onoff = boolValue ? 1 : 0; // Force it to be 0 or 1.
    334             lingr.l_linger = intValue;
    335             ret = setsockopt(fd, level, optname, &lingr, sizeof(lingr));
    336             break;
    337         }
    338         case SO_SNDTIMEO: {
    339             /*
    340              * SO_TIMEOUT from the core library gets converted to
    341              * SO_SNDTIMEO, but the option is supposed to set both
    342              * send and receive timeouts. Note: The incoming timeout
    343              * value is in milliseconds.
    344              */
    345             struct timeval timeout;
    346             timeout.tv_sec = intValue / 1000;
    347             timeout.tv_usec = (intValue % 1000) * 1000;
    348 
    349             ret = setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO,
    350                     (void *)&timeout, sizeof(timeout));
    351 
    352             if (ret == 0) {
    353                 ret = setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO,
    354                         (void *)&timeout, sizeof(timeout));
    355             }
    356 
    357             break;
    358         }
    359         default: {
    360             /*
    361              * In all other cases, the translated option level and
    362              * optname may be used directly for a call to setsockopt().
    363              */
    364             ret = setsockopt(fd, level, optname, &intValue, sizeof(intValue));
    365             break;
    366         }
    367     }
    368 
    369     if (ret != 0) {
    370         jniThrowIOException(env, errno);
    371         return;
    372     }
    373 }
    374 static jint socket_pending (JNIEnv *env, jobject object,
    375         jobject fileDescriptor)
    376 {
    377     int fd;
    378 
    379     fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
    380 
    381     if (env->ExceptionOccurred() != NULL) {
    382         return (jint)-1;
    383     }
    384 
    385     int pending;
    386     int ret = ioctl(fd, TIOCOUTQ, &pending);
    387 
    388     // If this were a non-socket fd, there would be other cases to worry
    389     // about...
    390 
    391     //ALOGD("socket_pending, ioctl ret:%d, pending:%d", ret, pending);
    392     if (ret < 0) {
    393         jniThrowIOException(env, errno);
    394         return (jint) 0;
    395     }
    396 
    397     return (jint)pending;
    398 }
    399 static jint socket_available (JNIEnv *env, jobject object,
    400         jobject fileDescriptor)
    401 {
    402     int fd;
    403 
    404     fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
    405 
    406     if (env->ExceptionOccurred() != NULL) {
    407         return (jint)-1;
    408     }
    409 
    410 #if 1
    411     int avail;
    412     int ret = ioctl(fd, FIONREAD, &avail);
    413 
    414     // If this were a non-socket fd, there would be other cases to worry
    415     // about...
    416 
    417     if (ret < 0) {
    418         jniThrowIOException(env, errno);
    419         return (jint) 0;
    420     }
    421 
    422     return (jint)avail;
    423 #else
    424 // there appears to be a bionic bug that prevents this version from working.
    425 
    426     ssize_t ret;
    427     struct msghdr msg;
    428 
    429     memset(&msg, 0, sizeof(msg));
    430 
    431     do {
    432         ret = recvmsg(fd, &msg, MSG_PEEK | MSG_DONTWAIT | MSG_NOSIGNAL);
    433     } while (ret < 0 && errno == EINTR);
    434 
    435 
    436     // MSG_PEEK returns 0 on EOF and EWOULDBLOCK on none available
    437     if (ret < 0 && errno == EWOULDBLOCK) {
    438         return 0;
    439     } if (ret < 0) {
    440         jniThrowIOException(env, errno);
    441         return -1;
    442     }
    443 
    444     return (jint)ret;
    445 #endif
    446 }
    447 
    448 static void socket_close (JNIEnv *env, jobject object, jobject fileDescriptor)
    449 {
    450     int fd;
    451     int err;
    452 
    453     if (fileDescriptor == NULL) {
    454         jniThrowNullPointerException(env, NULL);
    455         return;
    456     }
    457 
    458     fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
    459 
    460     if (env->ExceptionOccurred() != NULL) {
    461         return;
    462     }
    463 
    464     do {
    465         err = close(fd);
    466     } while (err < 0 && errno == EINTR);
    467 
    468     if (err < 0) {
    469         jniThrowIOException(env, errno);
    470         return;
    471     }
    472 }
    473 
    474 /**
    475  * Processes ancillary data, handling only
    476  * SCM_RIGHTS. Creates appropriate objects and sets appropriate
    477  * fields in the LocalSocketImpl object. Returns 0 on success
    478  * or -1 if an exception was thrown.
    479  */
    480 static int socket_process_cmsg(JNIEnv *env, jobject thisJ, struct msghdr * pMsg)
    481 {
    482     struct cmsghdr *cmsgptr;
    483 
    484     for (cmsgptr = CMSG_FIRSTHDR(pMsg);
    485             cmsgptr != NULL; cmsgptr = CMSG_NXTHDR(pMsg, cmsgptr)) {
    486 
    487         if (cmsgptr->cmsg_level != SOL_SOCKET) {
    488             continue;
    489         }
    490 
    491         if (cmsgptr->cmsg_type == SCM_RIGHTS) {
    492             int *pDescriptors = (int *)CMSG_DATA(cmsgptr);
    493             jobjectArray fdArray;
    494             int count
    495                 = ((cmsgptr->cmsg_len - CMSG_LEN(0)) / sizeof(int));
    496 
    497             if (count < 0) {
    498                 jniThrowException(env, "java/io/IOException",
    499                     "invalid cmsg length");
    500             }
    501 
    502             fdArray = env->NewObjectArray(count, class_FileDescriptor, NULL);
    503 
    504             if (fdArray == NULL) {
    505                 return -1;
    506             }
    507 
    508             for (int i = 0; i < count; i++) {
    509                 jobject fdObject
    510                         = jniCreateFileDescriptor(env, pDescriptors[i]);
    511 
    512                 if (env->ExceptionOccurred() != NULL) {
    513                     return -1;
    514                 }
    515 
    516                 env->SetObjectArrayElement(fdArray, i, fdObject);
    517 
    518                 if (env->ExceptionOccurred() != NULL) {
    519                     return -1;
    520                 }
    521             }
    522 
    523             env->SetObjectField(thisJ, field_inboundFileDescriptors, fdArray);
    524 
    525             if (env->ExceptionOccurred() != NULL) {
    526                 return -1;
    527             }
    528         }
    529     }
    530 
    531     return 0;
    532 }
    533 
    534 /**
    535  * Reads data from a socket into buf, processing any ancillary data
    536  * and adding it to thisJ.
    537  *
    538  * Returns the length of normal data read, or -1 if an exception has
    539  * been thrown in this function.
    540  */
    541 static ssize_t socket_read_all(JNIEnv *env, jobject thisJ, int fd,
    542         void *buffer, size_t len)
    543 {
    544     ssize_t ret;
    545     ssize_t bytesread = 0;
    546     struct msghdr msg;
    547     struct iovec iv;
    548     unsigned char *buf = (unsigned char *)buffer;
    549     // Enough buffer for a pile of fd's. We throw an exception if
    550     // this buffer is too small.
    551     struct cmsghdr cmsgbuf[2*sizeof(cmsghdr) + 0x100];
    552 
    553     memset(&msg, 0, sizeof(msg));
    554     memset(&iv, 0, sizeof(iv));
    555 
    556     iv.iov_base = buf;
    557     iv.iov_len = len;
    558 
    559     msg.msg_iov = &iv;
    560     msg.msg_iovlen = 1;
    561     msg.msg_control = cmsgbuf;
    562     msg.msg_controllen = sizeof(cmsgbuf);
    563 
    564     do {
    565         ret = recvmsg(fd, &msg, MSG_NOSIGNAL);
    566     } while (ret < 0 && errno == EINTR);
    567 
    568     if (ret < 0 && errno == EPIPE) {
    569         // Treat this as an end of stream
    570         return 0;
    571     }
    572 
    573     if (ret < 0) {
    574         jniThrowIOException(env, errno);
    575         return -1;
    576     }
    577 
    578     if ((msg.msg_flags & (MSG_CTRUNC | MSG_OOB | MSG_ERRQUEUE)) != 0) {
    579         // To us, any of the above flags are a fatal error
    580 
    581         jniThrowException(env, "java/io/IOException",
    582                 "Unexpected error or truncation during recvmsg()");
    583 
    584         return -1;
    585     }
    586 
    587     if (ret >= 0) {
    588         socket_process_cmsg(env, thisJ, &msg);
    589     }
    590 
    591     return ret;
    592 }
    593 
    594 /**
    595  * Writes all the data in the specified buffer to the specified socket.
    596  *
    597  * Returns 0 on success or -1 if an exception was thrown.
    598  */
    599 static int socket_write_all(JNIEnv *env, jobject object, int fd,
    600         void *buf, size_t len)
    601 {
    602     ssize_t ret;
    603     struct msghdr msg;
    604     unsigned char *buffer = (unsigned char *)buf;
    605     memset(&msg, 0, sizeof(msg));
    606 
    607     jobjectArray outboundFds
    608             = (jobjectArray)env->GetObjectField(
    609                 object, field_outboundFileDescriptors);
    610 
    611     if (env->ExceptionOccurred() != NULL) {
    612         return -1;
    613     }
    614 
    615     struct cmsghdr *cmsg;
    616     int countFds = outboundFds == NULL ? 0 : env->GetArrayLength(outboundFds);
    617     int fds[countFds];
    618     char msgbuf[CMSG_SPACE(countFds)];
    619 
    620     // Add any pending outbound file descriptors to the message
    621     if (outboundFds != NULL) {
    622 
    623         if (env->ExceptionOccurred() != NULL) {
    624             return -1;
    625         }
    626 
    627         for (int i = 0; i < countFds; i++) {
    628             jobject fdObject = env->GetObjectArrayElement(outboundFds, i);
    629             if (env->ExceptionOccurred() != NULL) {
    630                 return -1;
    631             }
    632 
    633             fds[i] = jniGetFDFromFileDescriptor(env, fdObject);
    634             if (env->ExceptionOccurred() != NULL) {
    635                 return -1;
    636             }
    637         }
    638 
    639         // See "man cmsg" really
    640         msg.msg_control = msgbuf;
    641         msg.msg_controllen = sizeof msgbuf;
    642         cmsg = CMSG_FIRSTHDR(&msg);
    643         cmsg->cmsg_level = SOL_SOCKET;
    644         cmsg->cmsg_type = SCM_RIGHTS;
    645         cmsg->cmsg_len = CMSG_LEN(sizeof fds);
    646         memcpy(CMSG_DATA(cmsg), fds, sizeof fds);
    647     }
    648 
    649     // We only write our msg_control during the first write
    650     while (len > 0) {
    651         struct iovec iv;
    652         memset(&iv, 0, sizeof(iv));
    653 
    654         iv.iov_base = buffer;
    655         iv.iov_len = len;
    656 
    657         msg.msg_iov = &iv;
    658         msg.msg_iovlen = 1;
    659 
    660         do {
    661             ret = sendmsg(fd, &msg, MSG_NOSIGNAL);
    662         } while (ret < 0 && errno == EINTR);
    663 
    664         if (ret < 0) {
    665             jniThrowIOException(env, errno);
    666             return -1;
    667         }
    668 
    669         buffer += ret;
    670         len -= ret;
    671 
    672         // Wipes out any msg_control too
    673         memset(&msg, 0, sizeof(msg));
    674     }
    675 
    676     return 0;
    677 }
    678 
    679 static jint socket_read (JNIEnv *env, jobject object, jobject fileDescriptor)
    680 {
    681     int fd;
    682     int err;
    683 
    684     if (fileDescriptor == NULL) {
    685         jniThrowNullPointerException(env, NULL);
    686         return (jint)-1;
    687     }
    688 
    689     fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
    690 
    691     if (env->ExceptionOccurred() != NULL) {
    692         return (jint)0;
    693     }
    694 
    695     unsigned char buf;
    696 
    697     err = socket_read_all(env, object, fd, &buf, 1);
    698 
    699     if (err < 0) {
    700         jniThrowIOException(env, errno);
    701         return (jint)0;
    702     }
    703 
    704     if (err == 0) {
    705         // end of file
    706         return (jint)-1;
    707     }
    708 
    709     return (jint)buf;
    710 }
    711 
    712 static jint socket_readba (JNIEnv *env, jobject object,
    713         jbyteArray buffer, jint off, jint len, jobject fileDescriptor)
    714 {
    715     int fd;
    716     jbyte* byteBuffer;
    717     int ret;
    718 
    719     if (fileDescriptor == NULL || buffer == NULL) {
    720         jniThrowNullPointerException(env, NULL);
    721         return (jint)-1;
    722     }
    723 
    724     if (off < 0 || len < 0 || (off + len) > env->GetArrayLength(buffer)) {
    725         jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", NULL);
    726         return (jint)-1;
    727     }
    728 
    729     if (len == 0) {
    730         // because socket_read_all returns 0 on EOF
    731         return 0;
    732     }
    733 
    734     fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
    735 
    736     if (env->ExceptionOccurred() != NULL) {
    737         return (jint)-1;
    738     }
    739 
    740     byteBuffer = env->GetByteArrayElements(buffer, NULL);
    741 
    742     if (NULL == byteBuffer) {
    743         // an exception will have been thrown
    744         return (jint)-1;
    745     }
    746 
    747     ret = socket_read_all(env, object,
    748             fd, byteBuffer + off, len);
    749 
    750     // A return of -1 above means an exception is pending
    751 
    752     env->ReleaseByteArrayElements(buffer, byteBuffer, 0);
    753 
    754     return (jint) ((ret == 0) ? -1 : ret);
    755 }
    756 
    757 static void socket_write (JNIEnv *env, jobject object,
    758         jint b, jobject fileDescriptor)
    759 {
    760     int fd;
    761     int err;
    762 
    763     if (fileDescriptor == NULL) {
    764         jniThrowNullPointerException(env, NULL);
    765         return;
    766     }
    767 
    768     fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
    769 
    770     if (env->ExceptionOccurred() != NULL) {
    771         return;
    772     }
    773 
    774     err = socket_write_all(env, object, fd, &b, 1);
    775 
    776     // A return of -1 above means an exception is pending
    777 }
    778 
    779 static void socket_writeba (JNIEnv *env, jobject object,
    780         jbyteArray buffer, jint off, jint len, jobject fileDescriptor)
    781 {
    782     int fd;
    783     int err;
    784     jbyte* byteBuffer;
    785 
    786     if (fileDescriptor == NULL || buffer == NULL) {
    787         jniThrowNullPointerException(env, NULL);
    788         return;
    789     }
    790 
    791     if (off < 0 || len < 0 || (off + len) > env->GetArrayLength(buffer)) {
    792         jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", NULL);
    793         return;
    794     }
    795 
    796     fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
    797 
    798     if (env->ExceptionOccurred() != NULL) {
    799         return;
    800     }
    801 
    802     byteBuffer = env->GetByteArrayElements(buffer,NULL);
    803 
    804     if (NULL == byteBuffer) {
    805         // an exception will have been thrown
    806         return;
    807     }
    808 
    809     err = socket_write_all(env, object, fd,
    810             byteBuffer + off, len);
    811 
    812     // A return of -1 above means an exception is pending
    813 
    814     env->ReleaseByteArrayElements(buffer, byteBuffer, JNI_ABORT);
    815 }
    816 
    817 static jobject socket_get_peer_credentials(JNIEnv *env,
    818         jobject object, jobject fileDescriptor)
    819 {
    820     int err;
    821     int fd;
    822 
    823     if (fileDescriptor == NULL) {
    824         jniThrowNullPointerException(env, NULL);
    825         return NULL;
    826     }
    827 
    828     fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
    829 
    830     if (env->ExceptionOccurred() != NULL) {
    831         return NULL;
    832     }
    833 
    834     struct ucred creds;
    835 
    836     memset(&creds, 0, sizeof(creds));
    837     socklen_t szCreds = sizeof(creds);
    838 
    839     err = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &creds, &szCreds);
    840 
    841     if (err < 0) {
    842         jniThrowIOException(env, errno);
    843         return NULL;
    844     }
    845 
    846     if (szCreds == 0) {
    847         return NULL;
    848     }
    849 
    850     return env->NewObject(class_Credentials, method_CredentialsInit,
    851             creds.pid, creds.uid, creds.gid);
    852 }
    853 
    854 #if 0
    855 //TODO change this to return an instance of LocalSocketAddress
    856 static jobject socket_getSockName(JNIEnv *env,
    857         jobject object, jobject fileDescriptor)
    858 {
    859     int err;
    860     int fd;
    861 
    862     if (fileDescriptor == NULL) {
    863         jniThrowNullPointerException(env, NULL);
    864         return NULL;
    865     }
    866 
    867     fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
    868 
    869     if (env->ExceptionOccurred() != NULL) {
    870         return NULL;
    871     }
    872 
    873     union {
    874         struct sockaddr address;
    875         struct sockaddr_un un_address;
    876     } sa;
    877 
    878     memset(&sa, 0, sizeof(sa));
    879 
    880     socklen_t namelen = sizeof(sa);
    881     err = getsockname(fd, &(sa.address), &namelen);
    882 
    883     if (err < 0) {
    884         jniThrowIOException(env, errno);
    885         return NULL;
    886     }
    887 
    888     if (sa.address.sa_family != AF_UNIX) {
    889         // We think we're an impl only for AF_UNIX, so this should never happen.
    890 
    891         jniThrowIOException(env, EINVAL);
    892         return NULL;
    893     }
    894 
    895     if (sa.un_address.sun_path[0] == '\0') {
    896     } else {
    897     }
    898 
    899 
    900 
    901 
    902 }
    903 #endif
    904 
    905 /*
    906  * JNI registration.
    907  */
    908 static JNINativeMethod gMethods[] = {
    909      /* name, signature, funcPtr */
    910     {"getOption_native", "(Ljava/io/FileDescriptor;I)I", (void*)socket_getOption},
    911     {"setOption_native", "(Ljava/io/FileDescriptor;III)V", (void*)socket_setOption},
    912     {"create_native", "(Z)Ljava/io/FileDescriptor;", (void*)socket_create},
    913     {"connectLocal", "(Ljava/io/FileDescriptor;Ljava/lang/String;I)V",
    914                                                 (void*)socket_connect_local},
    915     {"bindLocal", "(Ljava/io/FileDescriptor;Ljava/lang/String;I)V", (void*)socket_bind_local},
    916     {"listen_native", "(Ljava/io/FileDescriptor;I)V", (void*)socket_listen},
    917     {"accept", "(Ljava/io/FileDescriptor;Landroid/net/LocalSocketImpl;)Ljava/io/FileDescriptor;", (void*)socket_accept},
    918     {"shutdown", "(Ljava/io/FileDescriptor;Z)V", (void*)socket_shutdown},
    919     {"available_native", "(Ljava/io/FileDescriptor;)I", (void*) socket_available},
    920     {"pending_native", "(Ljava/io/FileDescriptor;)I", (void*) socket_pending},
    921     {"close_native", "(Ljava/io/FileDescriptor;)V", (void*) socket_close},
    922     {"read_native", "(Ljava/io/FileDescriptor;)I", (void*) socket_read},
    923     {"readba_native", "([BIILjava/io/FileDescriptor;)I", (void*) socket_readba},
    924     {"writeba_native", "([BIILjava/io/FileDescriptor;)V", (void*) socket_writeba},
    925     {"write_native", "(ILjava/io/FileDescriptor;)V", (void*) socket_write},
    926     {"getPeerCredentials_native",
    927             "(Ljava/io/FileDescriptor;)Landroid/net/Credentials;",
    928             (void*) socket_get_peer_credentials}
    929     //,{"getSockName_native", "(Ljava/io/FileDescriptor;)Ljava/lang/String;",
    930     //        (void *) socket_getSockName}
    931 
    932 };
    933 
    934 int register_android_net_LocalSocketImpl(JNIEnv *env)
    935 {
    936     jclass clazz;
    937 
    938     clazz = env->FindClass("android/net/LocalSocketImpl");
    939 
    940     if (clazz == NULL) {
    941         goto error;
    942     }
    943 
    944     field_inboundFileDescriptors = env->GetFieldID(clazz,
    945             "inboundFileDescriptors", "[Ljava/io/FileDescriptor;");
    946 
    947     if (field_inboundFileDescriptors == NULL) {
    948         goto error;
    949     }
    950 
    951     field_outboundFileDescriptors = env->GetFieldID(clazz,
    952             "outboundFileDescriptors", "[Ljava/io/FileDescriptor;");
    953 
    954     if (field_outboundFileDescriptors == NULL) {
    955         goto error;
    956     }
    957 
    958     class_Credentials = env->FindClass("android/net/Credentials");
    959 
    960     if (class_Credentials == NULL) {
    961         goto error;
    962     }
    963 
    964     class_Credentials = (jclass)env->NewGlobalRef(class_Credentials);
    965 
    966     class_FileDescriptor = env->FindClass("java/io/FileDescriptor");
    967 
    968     if (class_FileDescriptor == NULL) {
    969         goto error;
    970     }
    971 
    972     class_FileDescriptor = (jclass)env->NewGlobalRef(class_FileDescriptor);
    973 
    974     method_CredentialsInit
    975             = env->GetMethodID(class_Credentials, "<init>", "(III)V");
    976 
    977     if (method_CredentialsInit == NULL) {
    978         goto error;
    979     }
    980 
    981     return jniRegisterNativeMethods(env,
    982         "android/net/LocalSocketImpl", gMethods, NELEM(gMethods));
    983 
    984 error:
    985     ALOGE("Error registering android.net.LocalSocketImpl");
    986     return -1;
    987 }
    988 
    989 };
    990