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