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         jniThrowException(env, "java/lang/NullPointerException", 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         jniThrowException(env, "java/lang/NullPointerException", 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 
    375 static jint socket_available (JNIEnv *env, jobject object,
    376         jobject fileDescriptor)
    377 {
    378     int fd;
    379 
    380     fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
    381 
    382     if (env->ExceptionOccurred() != NULL) {
    383         return (jint)-1;
    384     }
    385 
    386 #if 1
    387     int avail;
    388     int ret = ioctl(fd, FIONREAD, &avail);
    389 
    390     // If this were a non-socket fd, there would be other cases to worry
    391     // about...
    392 
    393     if (ret < 0) {
    394         jniThrowIOException(env, errno);
    395         return (jint) 0;
    396     }
    397 
    398     return (jint)avail;
    399 #else
    400 // there appears to be a bionic bug that prevents this version from working.
    401 
    402     ssize_t ret;
    403     struct msghdr msg;
    404 
    405     memset(&msg, 0, sizeof(msg));
    406 
    407     do {
    408         ret = recvmsg(fd, &msg, MSG_PEEK | MSG_DONTWAIT | MSG_NOSIGNAL);
    409     } while (ret < 0 && errno == EINTR);
    410 
    411 
    412     // MSG_PEEK returns 0 on EOF and EWOULDBLOCK on none available
    413     if (ret < 0 && errno == EWOULDBLOCK) {
    414         return 0;
    415     } if (ret < 0) {
    416         jniThrowIOException(env, errno);
    417         return -1;
    418     }
    419 
    420     return (jint)ret;
    421 #endif
    422 }
    423 
    424 static void socket_close (JNIEnv *env, jobject object, jobject fileDescriptor)
    425 {
    426     int fd;
    427     int err;
    428 
    429     if (fileDescriptor == NULL) {
    430         jniThrowException(env, "java/lang/NullPointerException", NULL);
    431         return;
    432     }
    433 
    434     fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
    435 
    436     if (env->ExceptionOccurred() != NULL) {
    437         return;
    438     }
    439 
    440     do {
    441         err = close(fd);
    442     } while (err < 0 && errno == EINTR);
    443 
    444     if (err < 0) {
    445         jniThrowIOException(env, errno);
    446         return;
    447     }
    448 }
    449 
    450 /**
    451  * Processes ancillary data, handling only
    452  * SCM_RIGHTS. Creates appropriate objects and sets appropriate
    453  * fields in the LocalSocketImpl object. Returns 0 on success
    454  * or -1 if an exception was thrown.
    455  */
    456 static int socket_process_cmsg(JNIEnv *env, jobject thisJ, struct msghdr * pMsg)
    457 {
    458     struct cmsghdr *cmsgptr;
    459 
    460     for (cmsgptr = CMSG_FIRSTHDR(pMsg);
    461             cmsgptr != NULL; cmsgptr = CMSG_NXTHDR(pMsg, cmsgptr)) {
    462 
    463         if (cmsgptr->cmsg_level != SOL_SOCKET) {
    464             continue;
    465         }
    466 
    467         if (cmsgptr->cmsg_type == SCM_RIGHTS) {
    468             int *pDescriptors = (int *)CMSG_DATA(cmsgptr);
    469             jobjectArray fdArray;
    470             int count
    471                 = ((cmsgptr->cmsg_len - CMSG_LEN(0)) / sizeof(int));
    472 
    473             if (count < 0) {
    474                 jniThrowException(env, "java/io/IOException",
    475                     "invalid cmsg length");
    476             }
    477 
    478             fdArray = env->NewObjectArray(count, class_FileDescriptor, NULL);
    479 
    480             if (fdArray == NULL) {
    481                 return -1;
    482             }
    483 
    484             for (int i = 0; i < count; i++) {
    485                 jobject fdObject
    486                         = jniCreateFileDescriptor(env, pDescriptors[i]);
    487 
    488                 if (env->ExceptionOccurred() != NULL) {
    489                     return -1;
    490                 }
    491 
    492                 env->SetObjectArrayElement(fdArray, i, fdObject);
    493 
    494                 if (env->ExceptionOccurred() != NULL) {
    495                     return -1;
    496                 }
    497             }
    498 
    499             env->SetObjectField(thisJ, field_inboundFileDescriptors, fdArray);
    500 
    501             if (env->ExceptionOccurred() != NULL) {
    502                 return -1;
    503             }
    504         }
    505     }
    506 
    507     return 0;
    508 }
    509 
    510 /**
    511  * Reads data from a socket into buf, processing any ancillary data
    512  * and adding it to thisJ.
    513  *
    514  * Returns the length of normal data read, or -1 if an exception has
    515  * been thrown in this function.
    516  */
    517 static ssize_t socket_read_all(JNIEnv *env, jobject thisJ, int fd,
    518         void *buffer, size_t len)
    519 {
    520     ssize_t ret;
    521     ssize_t bytesread = 0;
    522     struct msghdr msg;
    523     struct iovec iv;
    524     unsigned char *buf = (unsigned char *)buffer;
    525     // Enough buffer for a pile of fd's. We throw an exception if
    526     // this buffer is too small.
    527     struct cmsghdr cmsgbuf[2*sizeof(cmsghdr) + 0x100];
    528 
    529     memset(&msg, 0, sizeof(msg));
    530     memset(&iv, 0, sizeof(iv));
    531 
    532     iv.iov_base = buf;
    533     iv.iov_len = len;
    534 
    535     msg.msg_iov = &iv;
    536     msg.msg_iovlen = 1;
    537     msg.msg_control = cmsgbuf;
    538     msg.msg_controllen = sizeof(cmsgbuf);
    539 
    540     do {
    541         ret = recvmsg(fd, &msg, MSG_NOSIGNAL);
    542     } while (ret < 0 && errno == EINTR);
    543 
    544     if (ret < 0 && errno == EPIPE) {
    545         // Treat this as an end of stream
    546         return 0;
    547     }
    548 
    549     if (ret < 0) {
    550         jniThrowIOException(env, errno);
    551         return -1;
    552     }
    553 
    554     if ((msg.msg_flags & (MSG_CTRUNC | MSG_OOB | MSG_ERRQUEUE)) != 0) {
    555         // To us, any of the above flags are a fatal error
    556 
    557         jniThrowException(env, "java/io/IOException",
    558                 "Unexpected error or truncation during recvmsg()");
    559 
    560         return -1;
    561     }
    562 
    563     if (ret >= 0) {
    564         socket_process_cmsg(env, thisJ, &msg);
    565     }
    566 
    567     return ret;
    568 }
    569 
    570 /**
    571  * Writes all the data in the specified buffer to the specified socket.
    572  *
    573  * Returns 0 on success or -1 if an exception was thrown.
    574  */
    575 static int socket_write_all(JNIEnv *env, jobject object, int fd,
    576         void *buf, size_t len)
    577 {
    578     ssize_t ret;
    579     struct msghdr msg;
    580     unsigned char *buffer = (unsigned char *)buf;
    581     memset(&msg, 0, sizeof(msg));
    582 
    583     jobjectArray outboundFds
    584             = (jobjectArray)env->GetObjectField(
    585                 object, field_outboundFileDescriptors);
    586 
    587     if (env->ExceptionOccurred() != NULL) {
    588         return -1;
    589     }
    590 
    591     struct cmsghdr *cmsg;
    592     int countFds = outboundFds == NULL ? 0 : env->GetArrayLength(outboundFds);
    593     int fds[countFds];
    594     char msgbuf[CMSG_SPACE(countFds)];
    595 
    596     // Add any pending outbound file descriptors to the message
    597     if (outboundFds != NULL) {
    598 
    599         if (env->ExceptionOccurred() != NULL) {
    600             return -1;
    601         }
    602 
    603         for (int i = 0; i < countFds; i++) {
    604             jobject fdObject = env->GetObjectArrayElement(outboundFds, i);
    605             if (env->ExceptionOccurred() != NULL) {
    606                 return -1;
    607             }
    608 
    609             fds[i] = jniGetFDFromFileDescriptor(env, fdObject);
    610             if (env->ExceptionOccurred() != NULL) {
    611                 return -1;
    612             }
    613         }
    614 
    615         // See "man cmsg" really
    616         msg.msg_control = msgbuf;
    617         msg.msg_controllen = sizeof msgbuf;
    618         cmsg = CMSG_FIRSTHDR(&msg);
    619         cmsg->cmsg_level = SOL_SOCKET;
    620         cmsg->cmsg_type = SCM_RIGHTS;
    621         cmsg->cmsg_len = CMSG_LEN(sizeof fds);
    622         memcpy(CMSG_DATA(cmsg), fds, sizeof fds);
    623     }
    624 
    625     // We only write our msg_control during the first write
    626     while (len > 0) {
    627         struct iovec iv;
    628         memset(&iv, 0, sizeof(iv));
    629 
    630         iv.iov_base = buffer;
    631         iv.iov_len = len;
    632 
    633         msg.msg_iov = &iv;
    634         msg.msg_iovlen = 1;
    635 
    636         do {
    637             ret = sendmsg(fd, &msg, MSG_NOSIGNAL);
    638         } while (ret < 0 && errno == EINTR);
    639 
    640         if (ret < 0) {
    641             jniThrowIOException(env, errno);
    642             return -1;
    643         }
    644 
    645         buffer += ret;
    646         len -= ret;
    647 
    648         // Wipes out any msg_control too
    649         memset(&msg, 0, sizeof(msg));
    650     }
    651 
    652     return 0;
    653 }
    654 
    655 static jint socket_read (JNIEnv *env, jobject object, jobject fileDescriptor)
    656 {
    657     int fd;
    658     int err;
    659 
    660     if (fileDescriptor == NULL) {
    661         jniThrowException(env, "java/lang/NullPointerException", NULL);
    662         return (jint)-1;
    663     }
    664 
    665     fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
    666 
    667     if (env->ExceptionOccurred() != NULL) {
    668         return (jint)0;
    669     }
    670 
    671     unsigned char buf;
    672 
    673     err = socket_read_all(env, object, fd, &buf, 1);
    674 
    675     if (err < 0) {
    676         jniThrowIOException(env, errno);
    677         return (jint)0;
    678     }
    679 
    680     if (err == 0) {
    681         // end of file
    682         return (jint)-1;
    683     }
    684 
    685     return (jint)buf;
    686 }
    687 
    688 static jint socket_readba (JNIEnv *env, jobject object,
    689         jbyteArray buffer, jint off, jint len, jobject fileDescriptor)
    690 {
    691     int fd;
    692     jbyte* byteBuffer;
    693     int ret;
    694 
    695     if (fileDescriptor == NULL || buffer == NULL) {
    696         jniThrowException(env, "java/lang/NullPointerException", NULL);
    697         return (jint)-1;
    698     }
    699 
    700     if (off < 0 || len < 0 || (off + len) > env->GetArrayLength(buffer)) {
    701         jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", NULL);
    702         return (jint)-1;
    703     }
    704 
    705     if (len == 0) {
    706         // because socket_read_all returns 0 on EOF
    707         return 0;
    708     }
    709 
    710     fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
    711 
    712     if (env->ExceptionOccurred() != NULL) {
    713         return (jint)-1;
    714     }
    715 
    716     byteBuffer = env->GetByteArrayElements(buffer, NULL);
    717 
    718     if (NULL == byteBuffer) {
    719         // an exception will have been thrown
    720         return (jint)-1;
    721     }
    722 
    723     ret = socket_read_all(env, object,
    724             fd, byteBuffer + off, len);
    725 
    726     // A return of -1 above means an exception is pending
    727 
    728     env->ReleaseByteArrayElements(buffer, byteBuffer, 0);
    729 
    730     return (jint) ((ret == 0) ? -1 : ret);
    731 }
    732 
    733 static void socket_write (JNIEnv *env, jobject object,
    734         jint b, jobject fileDescriptor)
    735 {
    736     int fd;
    737     int err;
    738 
    739     if (fileDescriptor == NULL) {
    740         jniThrowException(env, "java/lang/NullPointerException", NULL);
    741         return;
    742     }
    743 
    744     fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
    745 
    746     if (env->ExceptionOccurred() != NULL) {
    747         return;
    748     }
    749 
    750     err = socket_write_all(env, object, fd, &b, 1);
    751 
    752     // A return of -1 above means an exception is pending
    753 }
    754 
    755 static void socket_writeba (JNIEnv *env, jobject object,
    756         jbyteArray buffer, jint off, jint len, jobject fileDescriptor)
    757 {
    758     int fd;
    759     int err;
    760     jbyte* byteBuffer;
    761 
    762     if (fileDescriptor == NULL || buffer == NULL) {
    763         jniThrowException(env, "java/lang/NullPointerException", NULL);
    764         return;
    765     }
    766 
    767     if (off < 0 || len < 0 || (off + len) > env->GetArrayLength(buffer)) {
    768         jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", NULL);
    769         return;
    770     }
    771 
    772     fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
    773 
    774     if (env->ExceptionOccurred() != NULL) {
    775         return;
    776     }
    777 
    778     byteBuffer = env->GetByteArrayElements(buffer,NULL);
    779 
    780     if (NULL == byteBuffer) {
    781         // an exception will have been thrown
    782         return;
    783     }
    784 
    785     err = socket_write_all(env, object, fd,
    786             byteBuffer + off, len);
    787 
    788     // A return of -1 above means an exception is pending
    789 
    790     env->ReleaseByteArrayElements(buffer, byteBuffer, JNI_ABORT);
    791 }
    792 
    793 static jobject socket_get_peer_credentials(JNIEnv *env,
    794         jobject object, jobject fileDescriptor)
    795 {
    796     int err;
    797     int fd;
    798 
    799     if (fileDescriptor == NULL) {
    800         jniThrowException(env, "java/lang/NullPointerException", NULL);
    801         return NULL;
    802     }
    803 
    804     fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
    805 
    806     if (env->ExceptionOccurred() != NULL) {
    807         return NULL;
    808     }
    809 
    810     struct ucred creds;
    811 
    812     memset(&creds, 0, sizeof(creds));
    813     socklen_t szCreds = sizeof(creds);
    814 
    815     err = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &creds, &szCreds);
    816 
    817     if (err < 0) {
    818         jniThrowIOException(env, errno);
    819         return NULL;
    820     }
    821 
    822     if (szCreds == 0) {
    823         return NULL;
    824     }
    825 
    826     return env->NewObject(class_Credentials, method_CredentialsInit,
    827             creds.pid, creds.uid, creds.gid);
    828 }
    829 
    830 #if 0
    831 //TODO change this to return an instance of LocalSocketAddress
    832 static jobject socket_getSockName(JNIEnv *env,
    833         jobject object, jobject fileDescriptor)
    834 {
    835     int err;
    836     int fd;
    837 
    838     if (fileDescriptor == NULL) {
    839         jniThrowException(env, "java/lang/NullPointerException", NULL);
    840         return NULL;
    841     }
    842 
    843     fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
    844 
    845     if (env->ExceptionOccurred() != NULL) {
    846         return NULL;
    847     }
    848 
    849     union {
    850         struct sockaddr address;
    851         struct sockaddr_un un_address;
    852     } sa;
    853 
    854     memset(&sa, 0, sizeof(sa));
    855 
    856     socklen_t namelen = sizeof(sa);
    857     err = getsockname(fd, &(sa.address), &namelen);
    858 
    859     if (err < 0) {
    860         jniThrowIOException(env, errno);
    861         return NULL;
    862     }
    863 
    864     if (sa.address.sa_family != AF_UNIX) {
    865         // We think we're an impl only for AF_UNIX, so this should never happen.
    866 
    867         jniThrowIOException(env, EINVAL);
    868         return NULL;
    869     }
    870 
    871     if (sa.un_address.sun_path[0] == '\0') {
    872     } else {
    873     }
    874 
    875 
    876 
    877 
    878 }
    879 #endif
    880 
    881 /*
    882  * JNI registration.
    883  */
    884 static JNINativeMethod gMethods[] = {
    885      /* name, signature, funcPtr */
    886     {"getOption_native", "(Ljava/io/FileDescriptor;I)I", (void*)socket_getOption},
    887     {"setOption_native", "(Ljava/io/FileDescriptor;III)V", (void*)socket_setOption},
    888     {"create_native", "(Z)Ljava/io/FileDescriptor;", (void*)socket_create},
    889     {"connectLocal", "(Ljava/io/FileDescriptor;Ljava/lang/String;I)V",
    890                                                 (void*)socket_connect_local},
    891     {"bindLocal", "(Ljava/io/FileDescriptor;Ljava/lang/String;I)V", (void*)socket_bind_local},
    892     {"listen_native", "(Ljava/io/FileDescriptor;I)V", (void*)socket_listen},
    893     {"accept", "(Ljava/io/FileDescriptor;Landroid/net/LocalSocketImpl;)Ljava/io/FileDescriptor;", (void*)socket_accept},
    894     {"shutdown", "(Ljava/io/FileDescriptor;Z)V", (void*)socket_shutdown},
    895     {"available_native", "(Ljava/io/FileDescriptor;)I", (void*) socket_available},
    896     {"close_native", "(Ljava/io/FileDescriptor;)V", (void*) socket_close},
    897     {"read_native", "(Ljava/io/FileDescriptor;)I", (void*) socket_read},
    898     {"readba_native", "([BIILjava/io/FileDescriptor;)I", (void*) socket_readba},
    899     {"writeba_native", "([BIILjava/io/FileDescriptor;)V", (void*) socket_writeba},
    900     {"write_native", "(ILjava/io/FileDescriptor;)V", (void*) socket_write},
    901     {"getPeerCredentials_native",
    902             "(Ljava/io/FileDescriptor;)Landroid/net/Credentials;",
    903             (void*) socket_get_peer_credentials}
    904     //,{"getSockName_native", "(Ljava/io/FileDescriptor;)Ljava/lang/String;",
    905     //        (void *) socket_getSockName}
    906 
    907 };
    908 
    909 int register_android_net_LocalSocketImpl(JNIEnv *env)
    910 {
    911     jclass clazz;
    912 
    913     clazz = env->FindClass("android/net/LocalSocketImpl");
    914 
    915     if (clazz == NULL) {
    916         goto error;
    917     }
    918 
    919     field_inboundFileDescriptors = env->GetFieldID(clazz,
    920             "inboundFileDescriptors", "[Ljava/io/FileDescriptor;");
    921 
    922     if (field_inboundFileDescriptors == NULL) {
    923         goto error;
    924     }
    925 
    926     field_outboundFileDescriptors = env->GetFieldID(clazz,
    927             "outboundFileDescriptors", "[Ljava/io/FileDescriptor;");
    928 
    929     if (field_outboundFileDescriptors == NULL) {
    930         goto error;
    931     }
    932 
    933     class_Credentials = env->FindClass("android/net/Credentials");
    934 
    935     if (class_Credentials == NULL) {
    936         goto error;
    937     }
    938 
    939     class_Credentials = (jclass)env->NewGlobalRef(class_Credentials);
    940 
    941     class_FileDescriptor = env->FindClass("java/io/FileDescriptor");
    942 
    943     if (class_FileDescriptor == NULL) {
    944         goto error;
    945     }
    946 
    947     class_FileDescriptor = (jclass)env->NewGlobalRef(class_FileDescriptor);
    948 
    949     method_CredentialsInit
    950             = env->GetMethodID(class_Credentials, "<init>", "(III)V");
    951 
    952     if (method_CredentialsInit == NULL) {
    953         goto error;
    954     }
    955 
    956     return jniRegisterNativeMethods(env,
    957         "android/net/LocalSocketImpl", gMethods, NELEM(gMethods));
    958 
    959 error:
    960     LOGE("Error registering android.net.LocalSocketImpl");
    961     return -1;
    962 }
    963 
    964 };
    965