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