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