blob: f2b69c671bd4085f432f91e893a100ade3916242 [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
Elliott Hughes69a017b2011-04-08 14:10:28 -0700102/* private native void bindLocal(FileDescriptor fd, String name, namespace)
103 * throws IOException;
104 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800105
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) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700116 jniThrowNullPointerException(env, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800117 }
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);
Elliott Hughes69a017b2011-04-08 14:10:28 -0700130
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800131 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;
Elliott Hughes69a017b2011-04-08 14:10:28 -0700169
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800170 int ret;
171 int retFD;
172 int fd;
173 socklen_t addrlen;
174
175 if (s == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700176 jniThrowNullPointerException(env, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800177 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;
Elliott Hughes69a017b2011-04-08 14:10:28 -0700348
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800349 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 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700356
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800357 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}
zzy71bfafc2013-04-16 17:17:37 -0700374static jint socket_pending (JNIEnv *env, jobject object,
375 jobject fileDescriptor)
376{
377 int fd;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800378
zzy71bfafc2013-04-16 17:17:37 -0700379 fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
380
381 if (env->ExceptionOccurred() != NULL) {
382 return (jint)-1;
383 }
384
385 int pending;
386 int ret = ioctl(fd, TIOCOUTQ, &pending);
387
388 // If this were a non-socket fd, there would be other cases to worry
389 // about...
390
391 //ALOGD("socket_pending, ioctl ret:%d, pending:%d", ret, pending);
392 if (ret < 0) {
393 jniThrowIOException(env, errno);
394 return (jint) 0;
395 }
396
397 return (jint)pending;
398}
Elliott Hughes69a017b2011-04-08 14:10:28 -0700399static jint socket_available (JNIEnv *env, jobject object,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800400 jobject fileDescriptor)
401{
402 int fd;
403
404 fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
405
406 if (env->ExceptionOccurred() != NULL) {
407 return (jint)-1;
408 }
409
410#if 1
411 int avail;
412 int ret = ioctl(fd, FIONREAD, &avail);
413
414 // If this were a non-socket fd, there would be other cases to worry
415 // about...
416
417 if (ret < 0) {
418 jniThrowIOException(env, errno);
419 return (jint) 0;
420 }
421
422 return (jint)avail;
423#else
424// there appears to be a bionic bug that prevents this version from working.
Elliott Hughes69a017b2011-04-08 14:10:28 -0700425
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800426 ssize_t ret;
427 struct msghdr msg;
428
429 memset(&msg, 0, sizeof(msg));
430
431 do {
432 ret = recvmsg(fd, &msg, MSG_PEEK | MSG_DONTWAIT | MSG_NOSIGNAL);
433 } while (ret < 0 && errno == EINTR);
434
Elliott Hughes69a017b2011-04-08 14:10:28 -0700435
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800436 // MSG_PEEK returns 0 on EOF and EWOULDBLOCK on none available
437 if (ret < 0 && errno == EWOULDBLOCK) {
438 return 0;
439 } if (ret < 0) {
440 jniThrowIOException(env, errno);
441 return -1;
442 }
443
444 return (jint)ret;
445#endif
446}
447
448static void socket_close (JNIEnv *env, jobject object, jobject fileDescriptor)
449{
450 int fd;
451 int err;
452
453 if (fileDescriptor == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700454 jniThrowNullPointerException(env, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800455 return;
456 }
457
458 fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
459
460 if (env->ExceptionOccurred() != NULL) {
461 return;
462 }
463
464 do {
465 err = close(fd);
466 } while (err < 0 && errno == EINTR);
467
468 if (err < 0) {
469 jniThrowIOException(env, errno);
470 return;
471 }
472}
473
474/**
Elliott Hughes69a017b2011-04-08 14:10:28 -0700475 * Processes ancillary data, handling only
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800476 * SCM_RIGHTS. Creates appropriate objects and sets appropriate
477 * fields in the LocalSocketImpl object. Returns 0 on success
478 * or -1 if an exception was thrown.
479 */
480static int socket_process_cmsg(JNIEnv *env, jobject thisJ, struct msghdr * pMsg)
481{
482 struct cmsghdr *cmsgptr;
483
Elliott Hughes69a017b2011-04-08 14:10:28 -0700484 for (cmsgptr = CMSG_FIRSTHDR(pMsg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800485 cmsgptr != NULL; cmsgptr = CMSG_NXTHDR(pMsg, cmsgptr)) {
486
487 if (cmsgptr->cmsg_level != SOL_SOCKET) {
488 continue;
489 }
490
491 if (cmsgptr->cmsg_type == SCM_RIGHTS) {
492 int *pDescriptors = (int *)CMSG_DATA(cmsgptr);
493 jobjectArray fdArray;
Elliott Hughes69a017b2011-04-08 14:10:28 -0700494 int count
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800495 = ((cmsgptr->cmsg_len - CMSG_LEN(0)) / sizeof(int));
496
497 if (count < 0) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700498 jniThrowException(env, "java/io/IOException",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800499 "invalid cmsg length");
500 }
501
502 fdArray = env->NewObjectArray(count, class_FileDescriptor, NULL);
503
504 if (fdArray == NULL) {
505 return -1;
506 }
507
508 for (int i = 0; i < count; i++) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700509 jobject fdObject
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800510 = jniCreateFileDescriptor(env, pDescriptors[i]);
511
512 if (env->ExceptionOccurred() != NULL) {
513 return -1;
514 }
515
516 env->SetObjectArrayElement(fdArray, i, fdObject);
517
518 if (env->ExceptionOccurred() != NULL) {
519 return -1;
520 }
521 }
522
523 env->SetObjectField(thisJ, field_inboundFileDescriptors, fdArray);
524
525 if (env->ExceptionOccurred() != NULL) {
526 return -1;
527 }
528 }
529 }
530
531 return 0;
532}
533
534/**
535 * Reads data from a socket into buf, processing any ancillary data
536 * and adding it to thisJ.
537 *
538 * Returns the length of normal data read, or -1 if an exception has
539 * been thrown in this function.
540 */
Elliott Hughes69a017b2011-04-08 14:10:28 -0700541static ssize_t socket_read_all(JNIEnv *env, jobject thisJ, int fd,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800542 void *buffer, size_t len)
543{
544 ssize_t ret;
545 ssize_t bytesread = 0;
546 struct msghdr msg;
547 struct iovec iv;
548 unsigned char *buf = (unsigned char *)buffer;
549 // Enough buffer for a pile of fd's. We throw an exception if
550 // this buffer is too small.
551 struct cmsghdr cmsgbuf[2*sizeof(cmsghdr) + 0x100];
552
553 memset(&msg, 0, sizeof(msg));
554 memset(&iv, 0, sizeof(iv));
555
556 iv.iov_base = buf;
557 iv.iov_len = len;
558
559 msg.msg_iov = &iv;
560 msg.msg_iovlen = 1;
561 msg.msg_control = cmsgbuf;
562 msg.msg_controllen = sizeof(cmsgbuf);
563
564 do {
565 ret = recvmsg(fd, &msg, MSG_NOSIGNAL);
566 } while (ret < 0 && errno == EINTR);
567
568 if (ret < 0 && errno == EPIPE) {
569 // Treat this as an end of stream
570 return 0;
571 }
572
573 if (ret < 0) {
574 jniThrowIOException(env, errno);
575 return -1;
576 }
577
578 if ((msg.msg_flags & (MSG_CTRUNC | MSG_OOB | MSG_ERRQUEUE)) != 0) {
579 // To us, any of the above flags are a fatal error
580
Elliott Hughes69a017b2011-04-08 14:10:28 -0700581 jniThrowException(env, "java/io/IOException",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800582 "Unexpected error or truncation during recvmsg()");
583
584 return -1;
585 }
586
587 if (ret >= 0) {
588 socket_process_cmsg(env, thisJ, &msg);
589 }
590
591 return ret;
592}
593
594/**
595 * Writes all the data in the specified buffer to the specified socket.
596 *
597 * Returns 0 on success or -1 if an exception was thrown.
598 */
599static int socket_write_all(JNIEnv *env, jobject object, int fd,
600 void *buf, size_t len)
601{
602 ssize_t ret;
603 struct msghdr msg;
604 unsigned char *buffer = (unsigned char *)buf;
605 memset(&msg, 0, sizeof(msg));
606
Elliott Hughes69a017b2011-04-08 14:10:28 -0700607 jobjectArray outboundFds
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800608 = (jobjectArray)env->GetObjectField(
609 object, field_outboundFileDescriptors);
610
611 if (env->ExceptionOccurred() != NULL) {
612 return -1;
613 }
614
615 struct cmsghdr *cmsg;
616 int countFds = outboundFds == NULL ? 0 : env->GetArrayLength(outboundFds);
617 int fds[countFds];
618 char msgbuf[CMSG_SPACE(countFds)];
619
620 // Add any pending outbound file descriptors to the message
621 if (outboundFds != NULL) {
622
623 if (env->ExceptionOccurred() != NULL) {
624 return -1;
625 }
626
627 for (int i = 0; i < countFds; i++) {
628 jobject fdObject = env->GetObjectArrayElement(outboundFds, i);
629 if (env->ExceptionOccurred() != NULL) {
630 return -1;
631 }
632
633 fds[i] = jniGetFDFromFileDescriptor(env, fdObject);
634 if (env->ExceptionOccurred() != NULL) {
635 return -1;
636 }
637 }
638
639 // See "man cmsg" really
640 msg.msg_control = msgbuf;
641 msg.msg_controllen = sizeof msgbuf;
642 cmsg = CMSG_FIRSTHDR(&msg);
643 cmsg->cmsg_level = SOL_SOCKET;
644 cmsg->cmsg_type = SCM_RIGHTS;
645 cmsg->cmsg_len = CMSG_LEN(sizeof fds);
646 memcpy(CMSG_DATA(cmsg), fds, sizeof fds);
647 }
648
649 // We only write our msg_control during the first write
650 while (len > 0) {
651 struct iovec iv;
652 memset(&iv, 0, sizeof(iv));
653
654 iv.iov_base = buffer;
655 iv.iov_len = len;
656
657 msg.msg_iov = &iv;
658 msg.msg_iovlen = 1;
Elliott Hughes69a017b2011-04-08 14:10:28 -0700659
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800660 do {
661 ret = sendmsg(fd, &msg, MSG_NOSIGNAL);
662 } while (ret < 0 && errno == EINTR);
663
664 if (ret < 0) {
665 jniThrowIOException(env, errno);
666 return -1;
667 }
668
669 buffer += ret;
670 len -= ret;
671
672 // Wipes out any msg_control too
673 memset(&msg, 0, sizeof(msg));
674 }
675
676 return 0;
677}
678
679static jint socket_read (JNIEnv *env, jobject object, jobject fileDescriptor)
680{
681 int fd;
682 int err;
683
684 if (fileDescriptor == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700685 jniThrowNullPointerException(env, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800686 return (jint)-1;
687 }
688
689 fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
690
691 if (env->ExceptionOccurred() != NULL) {
692 return (jint)0;
693 }
694
695 unsigned char buf;
696
697 err = socket_read_all(env, object, fd, &buf, 1);
698
699 if (err < 0) {
700 jniThrowIOException(env, errno);
701 return (jint)0;
702 }
703
704 if (err == 0) {
705 // end of file
706 return (jint)-1;
707 }
708
709 return (jint)buf;
710}
711
Elliott Hughes69a017b2011-04-08 14:10:28 -0700712static jint socket_readba (JNIEnv *env, jobject object,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800713 jbyteArray buffer, jint off, jint len, jobject fileDescriptor)
714{
715 int fd;
716 jbyte* byteBuffer;
717 int ret;
718
719 if (fileDescriptor == NULL || buffer == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700720 jniThrowNullPointerException(env, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800721 return (jint)-1;
722 }
723
724 if (off < 0 || len < 0 || (off + len) > env->GetArrayLength(buffer)) {
725 jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", NULL);
726 return (jint)-1;
727 }
728
729 if (len == 0) {
730 // because socket_read_all returns 0 on EOF
731 return 0;
732 }
733
734 fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
735
736 if (env->ExceptionOccurred() != NULL) {
737 return (jint)-1;
738 }
739
740 byteBuffer = env->GetByteArrayElements(buffer, NULL);
741
742 if (NULL == byteBuffer) {
743 // an exception will have been thrown
744 return (jint)-1;
745 }
746
Elliott Hughes69a017b2011-04-08 14:10:28 -0700747 ret = socket_read_all(env, object,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800748 fd, byteBuffer + off, len);
749
750 // A return of -1 above means an exception is pending
751
752 env->ReleaseByteArrayElements(buffer, byteBuffer, 0);
753
754 return (jint) ((ret == 0) ? -1 : ret);
755}
756
Elliott Hughes69a017b2011-04-08 14:10:28 -0700757static void socket_write (JNIEnv *env, jobject object,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800758 jint b, jobject fileDescriptor)
759{
760 int fd;
761 int err;
762
763 if (fileDescriptor == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700764 jniThrowNullPointerException(env, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800765 return;
766 }
767
768 fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
769
770 if (env->ExceptionOccurred() != NULL) {
771 return;
772 }
773
774 err = socket_write_all(env, object, fd, &b, 1);
775
776 // A return of -1 above means an exception is pending
777}
778
Elliott Hughes69a017b2011-04-08 14:10:28 -0700779static void socket_writeba (JNIEnv *env, jobject object,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800780 jbyteArray buffer, jint off, jint len, jobject fileDescriptor)
781{
782 int fd;
783 int err;
784 jbyte* byteBuffer;
785
786 if (fileDescriptor == NULL || buffer == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700787 jniThrowNullPointerException(env, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800788 return;
789 }
790
791 if (off < 0 || len < 0 || (off + len) > env->GetArrayLength(buffer)) {
792 jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", NULL);
793 return;
794 }
795
796 fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
797
798 if (env->ExceptionOccurred() != NULL) {
799 return;
800 }
801
802 byteBuffer = env->GetByteArrayElements(buffer,NULL);
803
804 if (NULL == byteBuffer) {
805 // an exception will have been thrown
806 return;
807 }
808
Elliott Hughes69a017b2011-04-08 14:10:28 -0700809 err = socket_write_all(env, object, fd,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800810 byteBuffer + off, len);
811
812 // A return of -1 above means an exception is pending
813
814 env->ReleaseByteArrayElements(buffer, byteBuffer, JNI_ABORT);
815}
816
Elliott Hughes69a017b2011-04-08 14:10:28 -0700817static jobject socket_get_peer_credentials(JNIEnv *env,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800818 jobject object, jobject fileDescriptor)
819{
820 int err;
821 int fd;
822
823 if (fileDescriptor == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700824 jniThrowNullPointerException(env, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800825 return NULL;
826 }
827
828 fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
829
830 if (env->ExceptionOccurred() != NULL) {
831 return NULL;
832 }
833
834 struct ucred creds;
835
836 memset(&creds, 0, sizeof(creds));
837 socklen_t szCreds = sizeof(creds);
838
Elliott Hughes69a017b2011-04-08 14:10:28 -0700839 err = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &creds, &szCreds);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800840
841 if (err < 0) {
842 jniThrowIOException(env, errno);
843 return NULL;
844 }
845
846 if (szCreds == 0) {
847 return NULL;
848 }
849
Elliott Hughes69a017b2011-04-08 14:10:28 -0700850 return env->NewObject(class_Credentials, method_CredentialsInit,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800851 creds.pid, creds.uid, creds.gid);
852}
853
854#if 0
855//TODO change this to return an instance of LocalSocketAddress
Elliott Hughes69a017b2011-04-08 14:10:28 -0700856static jobject socket_getSockName(JNIEnv *env,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800857 jobject object, jobject fileDescriptor)
858{
859 int err;
860 int fd;
861
862 if (fileDescriptor == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700863 jniThrowNullPointerException(env, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800864 return NULL;
865 }
866
867 fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
868
869 if (env->ExceptionOccurred() != NULL) {
870 return NULL;
871 }
872
873 union {
874 struct sockaddr address;
875 struct sockaddr_un un_address;
876 } sa;
877
878 memset(&sa, 0, sizeof(sa));
879
880 socklen_t namelen = sizeof(sa);
881 err = getsockname(fd, &(sa.address), &namelen);
882
883 if (err < 0) {
884 jniThrowIOException(env, errno);
885 return NULL;
886 }
887
888 if (sa.address.sa_family != AF_UNIX) {
889 // We think we're an impl only for AF_UNIX, so this should never happen.
890
891 jniThrowIOException(env, EINVAL);
892 return NULL;
893 }
894
895 if (sa.un_address.sun_path[0] == '\0') {
896 } else {
897 }
898
899
900
901
902}
903#endif
904
905/*
906 * JNI registration.
907 */
908static JNINativeMethod gMethods[] = {
909 /* name, signature, funcPtr */
910 {"getOption_native", "(Ljava/io/FileDescriptor;I)I", (void*)socket_getOption},
911 {"setOption_native", "(Ljava/io/FileDescriptor;III)V", (void*)socket_setOption},
912 {"create_native", "(Z)Ljava/io/FileDescriptor;", (void*)socket_create},
913 {"connectLocal", "(Ljava/io/FileDescriptor;Ljava/lang/String;I)V",
914 (void*)socket_connect_local},
915 {"bindLocal", "(Ljava/io/FileDescriptor;Ljava/lang/String;I)V", (void*)socket_bind_local},
916 {"listen_native", "(Ljava/io/FileDescriptor;I)V", (void*)socket_listen},
917 {"accept", "(Ljava/io/FileDescriptor;Landroid/net/LocalSocketImpl;)Ljava/io/FileDescriptor;", (void*)socket_accept},
918 {"shutdown", "(Ljava/io/FileDescriptor;Z)V", (void*)socket_shutdown},
919 {"available_native", "(Ljava/io/FileDescriptor;)I", (void*) socket_available},
zzy71bfafc2013-04-16 17:17:37 -0700920 {"pending_native", "(Ljava/io/FileDescriptor;)I", (void*) socket_pending},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800921 {"close_native", "(Ljava/io/FileDescriptor;)V", (void*) socket_close},
922 {"read_native", "(Ljava/io/FileDescriptor;)I", (void*) socket_read},
923 {"readba_native", "([BIILjava/io/FileDescriptor;)I", (void*) socket_readba},
924 {"writeba_native", "([BIILjava/io/FileDescriptor;)V", (void*) socket_writeba},
925 {"write_native", "(ILjava/io/FileDescriptor;)V", (void*) socket_write},
Elliott Hughes69a017b2011-04-08 14:10:28 -0700926 {"getPeerCredentials_native",
927 "(Ljava/io/FileDescriptor;)Landroid/net/Credentials;",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800928 (void*) socket_get_peer_credentials}
Elliott Hughes69a017b2011-04-08 14:10:28 -0700929 //,{"getSockName_native", "(Ljava/io/FileDescriptor;)Ljava/lang/String;",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800930 // (void *) socket_getSockName}
931
932};
933
934int register_android_net_LocalSocketImpl(JNIEnv *env)
935{
936 jclass clazz;
937
938 clazz = env->FindClass("android/net/LocalSocketImpl");
939
940 if (clazz == NULL) {
941 goto error;
942 }
943
Elliott Hughes69a017b2011-04-08 14:10:28 -0700944 field_inboundFileDescriptors = env->GetFieldID(clazz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800945 "inboundFileDescriptors", "[Ljava/io/FileDescriptor;");
946
947 if (field_inboundFileDescriptors == NULL) {
948 goto error;
949 }
950
Elliott Hughes69a017b2011-04-08 14:10:28 -0700951 field_outboundFileDescriptors = env->GetFieldID(clazz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800952 "outboundFileDescriptors", "[Ljava/io/FileDescriptor;");
953
954 if (field_outboundFileDescriptors == NULL) {
955 goto error;
956 }
957
958 class_Credentials = env->FindClass("android/net/Credentials");
Elliott Hughes69a017b2011-04-08 14:10:28 -0700959
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800960 if (class_Credentials == NULL) {
961 goto error;
962 }
963
964 class_Credentials = (jclass)env->NewGlobalRef(class_Credentials);
965
966 class_FileDescriptor = env->FindClass("java/io/FileDescriptor");
967
968 if (class_FileDescriptor == NULL) {
969 goto error;
970 }
971
972 class_FileDescriptor = (jclass)env->NewGlobalRef(class_FileDescriptor);
973
Elliott Hughes69a017b2011-04-08 14:10:28 -0700974 method_CredentialsInit
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800975 = env->GetMethodID(class_Credentials, "<init>", "(III)V");
976
977 if (method_CredentialsInit == NULL) {
978 goto error;
979 }
980
981 return jniRegisterNativeMethods(env,
982 "android/net/LocalSocketImpl", gMethods, NELEM(gMethods));
983
984error:
Steve Block3762c312012-01-06 19:20:56 +0000985 ALOGE("Error registering android.net.LocalSocketImpl");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800986 return -1;
987}
988
989};