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