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