blob: e58794bcd43ee81745bf8772fc76931e9c3e2ef8 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038
39namespace android {
40
41static jfieldID field_inboundFileDescriptors;
42static jfieldID field_outboundFileDescriptors;
43static jclass class_Credentials;
44static jclass class_FileDescriptor;
45static jmethodID method_CredentialsInit;
46
47/*
48 * private native FileDescriptor
49 * create_native(boolean stream)
50 * throws IOException;
51 */
52static jobject
53socket_create (JNIEnv *env, jobject object, jboolean stream)
54{
55 int ret;
56
57 ret = socket(PF_LOCAL, stream ? SOCK_STREAM : SOCK_DGRAM, 0);
58
59 if (ret < 0) {
60 jniThrowIOException(env, errno);
61 return NULL;
62 }
63
64 return jniCreateFileDescriptor(env,ret);
65}
66
67/* private native void connectLocal(FileDescriptor fd,
68 * String name, int namespace) throws IOException
69 */
70static void
71socket_connect_local(JNIEnv *env, jobject object,
72 jobject fileDescriptor, jstring name, jint namespaceId)
73{
74 int ret;
75 const char *nameUtf8;
76 int fd;
77
78 nameUtf8 = env->GetStringUTFChars(name, NULL);
79
80 fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
81
82 if (env->ExceptionOccurred() != NULL) {
83 return;
84 }
85
86 ret = socket_local_client_connect(
87 fd,
88 nameUtf8,
89 namespaceId,
90 SOCK_STREAM);
91
92 env->ReleaseStringUTFChars(name, nameUtf8);
93
94 if (ret < 0) {
95 jniThrowIOException(env, errno);
96 return;
97 }
98}
99
100#define DEFAULT_BACKLOG 4
101
102/* private native void bindLocal(FileDescriptor fd, String name, namespace)
103 * throws IOException;
104 */
105
106static void
107socket_bind_local (JNIEnv *env, jobject object, jobject fileDescriptor,
108 jstring name, jint namespaceId)
109{
110 int ret;
111 int fd;
112 const char *nameUtf8;
113
114
115 if (name == NULL) {
116 jniThrowException(env, "java/lang/NullPointerException", NULL);
117 }
118
119 fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
120
121 if (env->ExceptionOccurred() != NULL) {
122 return;
123 }
124
125 nameUtf8 = env->GetStringUTFChars(name, NULL);
126
127 ret = socket_local_server_bind(fd, nameUtf8, namespaceId);
128
129 env->ReleaseStringUTFChars(name, nameUtf8);
130
131 if (ret < 0) {
132 jniThrowIOException(env, errno);
133 return;
134 }
135}
136
137/* private native void listen_native(int fd, int backlog) throws IOException; */
138static void
139socket_listen (JNIEnv *env, jobject object, jobject fileDescriptor, int backlog)
140{
141 int ret;
142 int fd;
143
144 fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
145
146 if (env->ExceptionOccurred() != NULL) {
147 return;
148 }
149
150 ret = listen(fd, backlog);
151
152 if (ret < 0) {
153 jniThrowIOException(env, errno);
154 return;
155 }
156}
157
158/* private native FileDescriptor
159** accept (FileDescriptor fd, LocalSocketImpl s)
160** throws IOException;
161*/
162static jobject
163socket_accept (JNIEnv *env, jobject object, jobject fileDescriptor, jobject s)
164{
165 union {
166 struct sockaddr address;
167 struct sockaddr_un un_address;
168 } sa;
169
170 int ret;
171 int retFD;
172 int fd;
173 socklen_t addrlen;
174
175 if (s == NULL) {
176 jniThrowException(env, "java/lang/NullPointerException", NULL);
177 return NULL;
178 }
179
180 fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
181
182 if (env->ExceptionOccurred() != NULL) {
183 return NULL;
184 }
185
186 do {
187 addrlen = sizeof(sa);
188 ret = accept(fd, &(sa.address), &addrlen);
189 } while (ret < 0 && errno == EINTR);
190
191 if (ret < 0) {
192 jniThrowIOException(env, errno);
193 return NULL;
194 }
195
196 retFD = ret;
197
198 return jniCreateFileDescriptor(env, retFD);
199}
200
201/* private native void shutdown(FileDescriptor fd, boolean shutdownInput) */
202
203static void
204socket_shutdown (JNIEnv *env, jobject object, jobject fileDescriptor,
205 jboolean shutdownInput)
206{
207 int ret;
208 int fd;
209
210 fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
211
212 if (env->ExceptionOccurred() != NULL) {
213 return;
214 }
215
216 ret = shutdown(fd, shutdownInput ? SHUT_RD : SHUT_WR);
217
218 if (ret < 0) {
219 jniThrowIOException(env, errno);
220 return;
221 }
222}
223
224static bool
225java_opt_to_real(int optID, int* opt, int* level)
226{
227 switch (optID)
228 {
229 case 4098:
230 *opt = SO_RCVBUF;
231 *level = SOL_SOCKET;
232 return true;
233 case 4097:
234 *opt = SO_SNDBUF;
235 *level = SOL_SOCKET;
236 return true;
237 case 4102:
238 *opt = SO_SNDTIMEO;
239 *level = SOL_SOCKET;
240 return true;
241 case 128:
242 *opt = SO_LINGER;
243 *level = SOL_SOCKET;
244 return true;
245 case 1:
246 *opt = TCP_NODELAY;
247 *level = IPPROTO_TCP;
248 return true;
249 case 4:
250 *opt = SO_REUSEADDR;
251 *level = SOL_SOCKET;
252 return true;
253
254 }
255 return false;
256}
257
258static jint
259socket_getOption(JNIEnv *env, jobject object, jobject fileDescriptor, int optID)
260{
261 int ret, value;
262 int opt, level;
263 int fd;
264
265 socklen_t size = sizeof(int);
266
267 if (!java_opt_to_real(optID, &opt, &level)) {
268 jniThrowIOException(env, -1);
269 return 0;
270 }
271
272 fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
273
274 if (env->ExceptionOccurred() != NULL) {
275 return 0;
276 }
277
278 switch (opt)
279 {
280 case SO_LINGER:
281 {
282 struct linger lingr;
283 size = sizeof(lingr);
284 ret = getsockopt(fd, level, opt, &lingr, &size);
285 if (!lingr.l_onoff) {
286 value = -1;
287 } else {
288 value = lingr.l_linger;
289 }
290 break;
291 }
292 default:
293 ret = getsockopt(fd, level, opt, &value, &size);
294 break;
295 }
296
297
298 if (ret != 0) {
299 jniThrowIOException(env, errno);
300 return 0;
301 }
302
303 return value;
304}
305
306static void socket_setOption(
307 JNIEnv *env, jobject object, jobject fileDescriptor, int optID,
308 jint boolValue, jint intValue) {
309 int ret;
310 int optname;
311 int level;
312 int fd;
313
314 if (!java_opt_to_real(optID, &optname, &level)) {
315 jniThrowIOException(env, -1);
316 return;
317 }
318
319 fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
320
321 if (env->ExceptionOccurred() != NULL) {
322 return;
323 }
324
325 switch (optname) {
326 case SO_LINGER: {
327 /*
328 * SO_LINGER is special because it needs to use a special
329 * "linger" struct as well as use the incoming boolean
330 * argument specially.
331 */
332 struct linger lingr;
333 lingr.l_onoff = boolValue ? 1 : 0; // Force it to be 0 or 1.
334 lingr.l_linger = intValue;
335 ret = setsockopt(fd, level, optname, &lingr, sizeof(lingr));
336 break;
337 }
338 case SO_SNDTIMEO: {
339 /*
340 * SO_TIMEOUT from the core library gets converted to
341 * SO_SNDTIMEO, but the option is supposed to set both
342 * send and receive timeouts. Note: The incoming timeout
343 * value is in milliseconds.
344 */
345 struct timeval timeout;
346 timeout.tv_sec = intValue / 1000;
347 timeout.tv_usec = (intValue % 1000) * 1000;
348
349 ret = setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO,
350 (void *)&timeout, sizeof(timeout));
351
352 if (ret == 0) {
353 ret = setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO,
354 (void *)&timeout, sizeof(timeout));
355 }
356
357 break;
358 }
359 default: {
360 /*
361 * In all other cases, the translated option level and
362 * optname may be used directly for a call to setsockopt().
363 */
364 ret = setsockopt(fd, level, optname, &intValue, sizeof(intValue));
365 break;
366 }
367 }
368
369 if (ret != 0) {
370 jniThrowIOException(env, errno);
371 return;
372 }
373}
374
375static 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
424static void socket_close (JNIEnv *env, jobject object, jobject fileDescriptor)
425{
426 int fd;
427 int err;
428
429 if (fileDescriptor == NULL) {
430 jniThrowException(env, "java/lang/NullPointerException", 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 */
456static 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 */
517static 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 */
575static 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
655static jint socket_read (JNIEnv *env, jobject object, jobject fileDescriptor)
656{
657 int fd;
658 int err;
659
660 if (fileDescriptor == NULL) {
661 jniThrowException(env, "java/lang/NullPointerException", 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
688static 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 jniThrowException(env, "java/lang/NullPointerException", 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
733static 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 jniThrowException(env, "java/lang/NullPointerException", 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
755static 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 jniThrowException(env, "java/lang/NullPointerException", 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
793static 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 jniThrowException(env, "java/lang/NullPointerException", 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
832static jobject socket_getSockName(JNIEnv *env,
833 jobject object, jobject fileDescriptor)
834{
835 int err;
836 int fd;
837
838 if (fileDescriptor == NULL) {
839 jniThrowException(env, "java/lang/NullPointerException", 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 */
884static 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
909int 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
959error:
960 LOGE("Error registering android.net.LocalSocketImpl");
961 return -1;
962}
963
964};