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