android_net_LocalSocketImpl.cpp revision 69a017bc1d1649350f830dfada5c6ed5eac0b770
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
39namespace android {
40
41static jfieldID field_inboundFileDescriptors;
42static jfieldID field_outboundFileDescriptors;
43static jclass class_Credentials;
44static jclass class_FileDescriptor;
45static jmethodID method_CredentialsInit;
46
47/*
48 * private native FileDescriptor
49 * create_native(boolean stream)
50 *               throws IOException;
51 */
52static jobject
53socket_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 */
70static void
71socket_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
106static void
107socket_bind_local (JNIEnv *env, jobject object, jobject fileDescriptor,
108                jstring name, jint namespaceId)
109{
110    int ret;
111    int fd;
112    const char *nameUtf8;
113
114
115    if (name == NULL) {
116        jniThrowNullPointerException(env, NULL);
117    }
118
119    fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
120
121    if (env->ExceptionOccurred() != NULL) {
122        return;
123    }
124
125    nameUtf8 = env->GetStringUTFChars(name, NULL);
126
127    ret = socket_local_server_bind(fd, nameUtf8, namespaceId);
128
129    env->ReleaseStringUTFChars(name, nameUtf8);
130
131    if (ret < 0) {
132        jniThrowIOException(env, errno);
133        return;
134    }
135}
136
137/* private native void listen_native(int fd, int backlog) throws IOException; */
138static void
139socket_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*/
162static jobject
163socket_accept (JNIEnv *env, jobject object, jobject fileDescriptor, jobject s)
164{
165    union {
166        struct sockaddr address;
167        struct sockaddr_un un_address;
168    } sa;
169
170    int ret;
171    int retFD;
172    int fd;
173    socklen_t addrlen;
174
175    if (s == NULL) {
176        jniThrowNullPointerException(env, NULL);
177        return NULL;
178    }
179
180    fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
181
182    if (env->ExceptionOccurred() != NULL) {
183        return NULL;
184    }
185
186    do {
187        addrlen = sizeof(sa);
188        ret = accept(fd, &(sa.address), &addrlen);
189    } while (ret < 0 && errno == EINTR);
190
191    if (ret < 0) {
192        jniThrowIOException(env, errno);
193        return NULL;
194    }
195
196    retFD = ret;
197
198    return jniCreateFileDescriptor(env, retFD);
199}
200
201/* private native void shutdown(FileDescriptor fd, boolean shutdownInput) */
202
203static void
204socket_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
224static bool
225java_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
258static jint
259socket_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
306static 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
375static 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
424static void socket_close (JNIEnv *env, jobject object, jobject fileDescriptor)
425{
426    int fd;
427    int err;
428
429    if (fileDescriptor == NULL) {
430        jniThrowNullPointerException(env, 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 */
456static 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 */
517static 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 */
575static 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
655static jint socket_read (JNIEnv *env, jobject object, jobject fileDescriptor)
656{
657    int fd;
658    int err;
659
660    if (fileDescriptor == NULL) {
661        jniThrowNullPointerException(env, 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
688static 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        jniThrowNullPointerException(env, 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
733static 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        jniThrowNullPointerException(env, 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
755static 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        jniThrowNullPointerException(env, 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
793static 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        jniThrowNullPointerException(env, 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
832static jobject socket_getSockName(JNIEnv *env,
833        jobject object, jobject fileDescriptor)
834{
835    int err;
836    int fd;
837
838    if (fileDescriptor == NULL) {
839        jniThrowNullPointerException(env, 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 */
884static 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
909int 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
959error:
960    LOGE("Error registering android.net.LocalSocketImpl");
961    return -1;
962}
963
964};
965