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