• 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 <cutils/properties.h>
39 #include <cutils/adb_networking.h>
40 
41 namespace android {
42 
43 static jfieldID field_inboundFileDescriptors;
44 static jfieldID field_outboundFileDescriptors;
45 static jclass class_Credentials;
46 static jclass class_FileDescriptor;
47 static jmethodID method_CredentialsInit;
48 
49 /*
50  * private native FileDescriptor
51  * create_native(boolean stream)
52  *               throws IOException;
53  */
54 static jobject
socket_create(JNIEnv * env,jobject object,jboolean stream)55 socket_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  */
72 static void
socket_connect_local(JNIEnv * env,jobject object,jobject fileDescriptor,jstring name,jint namespaceId)73 socket_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 
108 static void
socket_bind_local(JNIEnv * env,jobject object,jobject fileDescriptor,jstring name,jint namespaceId)109 socket_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; */
140 static void
socket_listen(JNIEnv * env,jobject object,jobject fileDescriptor,int backlog)141 socket_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 */
164 static jobject
socket_accept(JNIEnv * env,jobject object,jobject fileDescriptor,jobject s)165 socket_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 
205 static void
socket_shutdown(JNIEnv * env,jobject object,jobject fileDescriptor,jboolean shutdownInput)206 socket_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 
226 static bool
java_opt_to_real(int optID,int * opt,int * level)227 java_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 
260 static jint
socket_getOption(JNIEnv * env,jobject object,jobject fileDescriptor,int optID)261 socket_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 
socket_setOption(JNIEnv * env,jobject object,jobject fileDescriptor,int optID,jint boolValue,jint intValue)308 static 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 
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->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 
socket_close(JNIEnv * env,jobject object,jobject fileDescriptor)426 static 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  */
socket_process_cmsg(JNIEnv * env,jobject thisJ,struct msghdr * pMsg)458 static 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  */
socket_read_all(JNIEnv * env,jobject thisJ,int fd,void * buffer,size_t len)519 static 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  */
socket_write_all(JNIEnv * env,jobject object,int fd,void * buf,size_t len)577 static 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 
socket_read(JNIEnv * env,jobject object,jobject fileDescriptor)657 static 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 
socket_readba(JNIEnv * env,jobject object,jbyteArray buffer,jint off,jint len,jobject fileDescriptor)690 static 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/ArrayIndexOutOfBoundsException", 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 
socket_write(JNIEnv * env,jobject object,jint b,jobject fileDescriptor)735 static 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 
socket_writeba(JNIEnv * env,jobject object,jbyteArray buffer,jint off,jint len,jobject fileDescriptor)757 static 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/ArrayIndexOutOfBoundsException", 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 
socket_get_peer_credentials(JNIEnv * env,jobject object,jobject fileDescriptor)795 static 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
834 static 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  */
886 static 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 
register_android_net_LocalSocketImpl(JNIEnv * env)911 int 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 
961 error:
962     LOGE("Error registering android.net.LocalSocketImpl");
963     return -1;
964 }
965 
966 };
967