blob: b9ed28ea665d44013e56c3984ab3c2a406368680 [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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047/* private native void connectLocal(FileDescriptor fd,
48 * String name, int namespace) throws IOException
49 */
50static void
51socket_connect_local(JNIEnv *env, jobject object,
52 jobject fileDescriptor, jstring name, jint namespaceId)
53{
54 int ret;
55 const char *nameUtf8;
56 int fd;
57
58 nameUtf8 = env->GetStringUTFChars(name, NULL);
59
60 fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
61
62 if (env->ExceptionOccurred() != NULL) {
63 return;
64 }
65
66 ret = socket_local_client_connect(
67 fd,
68 nameUtf8,
69 namespaceId,
70 SOCK_STREAM);
71
72 env->ReleaseStringUTFChars(name, nameUtf8);
73
74 if (ret < 0) {
75 jniThrowIOException(env, errno);
76 return;
77 }
78}
79
80#define DEFAULT_BACKLOG 4
81
Elliott Hughes69a017b2011-04-08 14:10:28 -070082/* private native void bindLocal(FileDescriptor fd, String name, namespace)
83 * throws IOException;
84 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085
86static void
87socket_bind_local (JNIEnv *env, jobject object, jobject fileDescriptor,
88 jstring name, jint namespaceId)
89{
90 int ret;
91 int fd;
92 const char *nameUtf8;
93
94
95 if (name == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -070096 jniThrowNullPointerException(env, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080097 }
98
99 fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
100
101 if (env->ExceptionOccurred() != NULL) {
102 return;
103 }
104
105 nameUtf8 = env->GetStringUTFChars(name, NULL);
106
107 ret = socket_local_server_bind(fd, nameUtf8, namespaceId);
108
109 env->ReleaseStringUTFChars(name, nameUtf8);
Elliott Hughes69a017b2011-04-08 14:10:28 -0700110
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800111 if (ret < 0) {
112 jniThrowIOException(env, errno);
113 return;
114 }
115}
116
117/* private native void listen_native(int fd, int backlog) throws IOException; */
118static void
119socket_listen (JNIEnv *env, jobject object, jobject fileDescriptor, int backlog)
120{
121 int ret;
122 int fd;
123
124 fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
125
126 if (env->ExceptionOccurred() != NULL) {
127 return;
128 }
129
130 ret = listen(fd, backlog);
131
132 if (ret < 0) {
133 jniThrowIOException(env, errno);
134 return;
135 }
136}
137
138/* private native FileDescriptor
139** accept (FileDescriptor fd, LocalSocketImpl s)
140** throws IOException;
141*/
142static jobject
143socket_accept (JNIEnv *env, jobject object, jobject fileDescriptor, jobject s)
144{
145 union {
146 struct sockaddr address;
147 struct sockaddr_un un_address;
148 } sa;
Elliott Hughes69a017b2011-04-08 14:10:28 -0700149
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800150 int ret;
151 int retFD;
152 int fd;
153 socklen_t addrlen;
154
155 if (s == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700156 jniThrowNullPointerException(env, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800157 return NULL;
158 }
159
160 fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
161
162 if (env->ExceptionOccurred() != NULL) {
163 return NULL;
164 }
165
166 do {
167 addrlen = sizeof(sa);
168 ret = accept(fd, &(sa.address), &addrlen);
169 } while (ret < 0 && errno == EINTR);
170
171 if (ret < 0) {
172 jniThrowIOException(env, errno);
173 return NULL;
174 }
175
176 retFD = ret;
177
178 return jniCreateFileDescriptor(env, retFD);
179}
180
181/* private native void shutdown(FileDescriptor fd, boolean shutdownInput) */
182
183static void
184socket_shutdown (JNIEnv *env, jobject object, jobject fileDescriptor,
185 jboolean shutdownInput)
186{
187 int ret;
188 int fd;
189
190 fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
191
192 if (env->ExceptionOccurred() != NULL) {
193 return;
194 }
195
196 ret = shutdown(fd, shutdownInput ? SHUT_RD : SHUT_WR);
197
198 if (ret < 0) {
199 jniThrowIOException(env, errno);
200 return;
201 }
202}
203
204static bool
205java_opt_to_real(int optID, int* opt, int* level)
206{
207 switch (optID)
208 {
209 case 4098:
210 *opt = SO_RCVBUF;
211 *level = SOL_SOCKET;
212 return true;
213 case 4097:
214 *opt = SO_SNDBUF;
215 *level = SOL_SOCKET;
216 return true;
217 case 4102:
218 *opt = SO_SNDTIMEO;
219 *level = SOL_SOCKET;
220 return true;
221 case 128:
222 *opt = SO_LINGER;
223 *level = SOL_SOCKET;
224 return true;
225 case 1:
226 *opt = TCP_NODELAY;
227 *level = IPPROTO_TCP;
228 return true;
229 case 4:
230 *opt = SO_REUSEADDR;
231 *level = SOL_SOCKET;
232 return true;
233
234 }
235 return false;
236}
237
238static jint
239socket_getOption(JNIEnv *env, jobject object, jobject fileDescriptor, int optID)
240{
241 int ret, value;
242 int opt, level;
243 int fd;
244
245 socklen_t size = sizeof(int);
246
247 if (!java_opt_to_real(optID, &opt, &level)) {
248 jniThrowIOException(env, -1);
249 return 0;
250 }
251
252 fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
253
254 if (env->ExceptionOccurred() != NULL) {
255 return 0;
256 }
257
258 switch (opt)
259 {
260 case SO_LINGER:
261 {
262 struct linger lingr;
263 size = sizeof(lingr);
264 ret = getsockopt(fd, level, opt, &lingr, &size);
265 if (!lingr.l_onoff) {
266 value = -1;
267 } else {
268 value = lingr.l_linger;
269 }
270 break;
271 }
272 default:
273 ret = getsockopt(fd, level, opt, &value, &size);
274 break;
275 }
276
277
278 if (ret != 0) {
279 jniThrowIOException(env, errno);
280 return 0;
281 }
282
283 return value;
284}
285
286static void socket_setOption(
287 JNIEnv *env, jobject object, jobject fileDescriptor, int optID,
288 jint boolValue, jint intValue) {
289 int ret;
290 int optname;
291 int level;
292 int fd;
293
294 if (!java_opt_to_real(optID, &optname, &level)) {
295 jniThrowIOException(env, -1);
296 return;
297 }
298
299 fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
300
301 if (env->ExceptionOccurred() != NULL) {
302 return;
303 }
304
305 switch (optname) {
306 case SO_LINGER: {
307 /*
308 * SO_LINGER is special because it needs to use a special
309 * "linger" struct as well as use the incoming boolean
310 * argument specially.
311 */
312 struct linger lingr;
313 lingr.l_onoff = boolValue ? 1 : 0; // Force it to be 0 or 1.
314 lingr.l_linger = intValue;
315 ret = setsockopt(fd, level, optname, &lingr, sizeof(lingr));
316 break;
317 }
318 case SO_SNDTIMEO: {
319 /*
320 * SO_TIMEOUT from the core library gets converted to
321 * SO_SNDTIMEO, but the option is supposed to set both
322 * send and receive timeouts. Note: The incoming timeout
323 * value is in milliseconds.
324 */
325 struct timeval timeout;
326 timeout.tv_sec = intValue / 1000;
327 timeout.tv_usec = (intValue % 1000) * 1000;
Elliott Hughes69a017b2011-04-08 14:10:28 -0700328
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800329 ret = setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO,
330 (void *)&timeout, sizeof(timeout));
331
332 if (ret == 0) {
333 ret = setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO,
334 (void *)&timeout, sizeof(timeout));
335 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700336
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800337 break;
338 }
339 default: {
340 /*
341 * In all other cases, the translated option level and
342 * optname may be used directly for a call to setsockopt().
343 */
344 ret = setsockopt(fd, level, optname, &intValue, sizeof(intValue));
345 break;
346 }
347 }
348
349 if (ret != 0) {
350 jniThrowIOException(env, errno);
351 return;
352 }
353}
zzy71bfafc2013-04-16 17:17:37 -0700354static jint socket_pending (JNIEnv *env, jobject object,
355 jobject fileDescriptor)
356{
357 int fd;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800358
zzy71bfafc2013-04-16 17:17:37 -0700359 fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
360
361 if (env->ExceptionOccurred() != NULL) {
362 return (jint)-1;
363 }
364
365 int pending;
366 int ret = ioctl(fd, TIOCOUTQ, &pending);
367
368 // If this were a non-socket fd, there would be other cases to worry
369 // about...
370
371 //ALOGD("socket_pending, ioctl ret:%d, pending:%d", ret, pending);
372 if (ret < 0) {
373 jniThrowIOException(env, errno);
374 return (jint) 0;
375 }
376
377 return (jint)pending;
378}
Elliott Hughes69a017b2011-04-08 14:10:28 -0700379static jint socket_available (JNIEnv *env, jobject object,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800380 jobject fileDescriptor)
381{
382 int fd;
383
384 fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
385
386 if (env->ExceptionOccurred() != NULL) {
387 return (jint)-1;
388 }
389
390#if 1
391 int avail;
392 int ret = ioctl(fd, FIONREAD, &avail);
393
394 // If this were a non-socket fd, there would be other cases to worry
395 // about...
396
397 if (ret < 0) {
398 jniThrowIOException(env, errno);
399 return (jint) 0;
400 }
401
402 return (jint)avail;
403#else
404// there appears to be a bionic bug that prevents this version from working.
Elliott Hughes69a017b2011-04-08 14:10:28 -0700405
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800406 ssize_t ret;
407 struct msghdr msg;
408
409 memset(&msg, 0, sizeof(msg));
410
411 do {
412 ret = recvmsg(fd, &msg, MSG_PEEK | MSG_DONTWAIT | MSG_NOSIGNAL);
413 } while (ret < 0 && errno == EINTR);
414
Elliott Hughes69a017b2011-04-08 14:10:28 -0700415
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800416 // MSG_PEEK returns 0 on EOF and EWOULDBLOCK on none available
417 if (ret < 0 && errno == EWOULDBLOCK) {
418 return 0;
419 } if (ret < 0) {
420 jniThrowIOException(env, errno);
421 return -1;
422 }
423
424 return (jint)ret;
425#endif
426}
427
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800428/**
Elliott Hughes69a017b2011-04-08 14:10:28 -0700429 * Processes ancillary data, handling only
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800430 * SCM_RIGHTS. Creates appropriate objects and sets appropriate
431 * fields in the LocalSocketImpl object. Returns 0 on success
432 * or -1 if an exception was thrown.
433 */
434static int socket_process_cmsg(JNIEnv *env, jobject thisJ, struct msghdr * pMsg)
435{
436 struct cmsghdr *cmsgptr;
437
Elliott Hughes69a017b2011-04-08 14:10:28 -0700438 for (cmsgptr = CMSG_FIRSTHDR(pMsg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800439 cmsgptr != NULL; cmsgptr = CMSG_NXTHDR(pMsg, cmsgptr)) {
440
441 if (cmsgptr->cmsg_level != SOL_SOCKET) {
442 continue;
443 }
444
445 if (cmsgptr->cmsg_type == SCM_RIGHTS) {
446 int *pDescriptors = (int *)CMSG_DATA(cmsgptr);
447 jobjectArray fdArray;
Elliott Hughes69a017b2011-04-08 14:10:28 -0700448 int count
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800449 = ((cmsgptr->cmsg_len - CMSG_LEN(0)) / sizeof(int));
450
451 if (count < 0) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700452 jniThrowException(env, "java/io/IOException",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800453 "invalid cmsg length");
454 }
455
456 fdArray = env->NewObjectArray(count, class_FileDescriptor, NULL);
457
458 if (fdArray == NULL) {
459 return -1;
460 }
461
462 for (int i = 0; i < count; i++) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700463 jobject fdObject
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800464 = jniCreateFileDescriptor(env, pDescriptors[i]);
465
466 if (env->ExceptionOccurred() != NULL) {
467 return -1;
468 }
469
470 env->SetObjectArrayElement(fdArray, i, fdObject);
471
472 if (env->ExceptionOccurred() != NULL) {
473 return -1;
474 }
475 }
476
477 env->SetObjectField(thisJ, field_inboundFileDescriptors, fdArray);
478
479 if (env->ExceptionOccurred() != NULL) {
480 return -1;
481 }
482 }
483 }
484
485 return 0;
486}
487
488/**
489 * Reads data from a socket into buf, processing any ancillary data
490 * and adding it to thisJ.
491 *
492 * Returns the length of normal data read, or -1 if an exception has
493 * been thrown in this function.
494 */
Elliott Hughes69a017b2011-04-08 14:10:28 -0700495static ssize_t socket_read_all(JNIEnv *env, jobject thisJ, int fd,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800496 void *buffer, size_t len)
497{
498 ssize_t ret;
499 ssize_t bytesread = 0;
500 struct msghdr msg;
501 struct iovec iv;
502 unsigned char *buf = (unsigned char *)buffer;
503 // Enough buffer for a pile of fd's. We throw an exception if
504 // this buffer is too small.
505 struct cmsghdr cmsgbuf[2*sizeof(cmsghdr) + 0x100];
506
507 memset(&msg, 0, sizeof(msg));
508 memset(&iv, 0, sizeof(iv));
509
510 iv.iov_base = buf;
511 iv.iov_len = len;
512
513 msg.msg_iov = &iv;
514 msg.msg_iovlen = 1;
515 msg.msg_control = cmsgbuf;
516 msg.msg_controllen = sizeof(cmsgbuf);
517
518 do {
519 ret = recvmsg(fd, &msg, MSG_NOSIGNAL);
520 } while (ret < 0 && errno == EINTR);
521
522 if (ret < 0 && errno == EPIPE) {
523 // Treat this as an end of stream
524 return 0;
525 }
526
527 if (ret < 0) {
528 jniThrowIOException(env, errno);
529 return -1;
530 }
531
532 if ((msg.msg_flags & (MSG_CTRUNC | MSG_OOB | MSG_ERRQUEUE)) != 0) {
533 // To us, any of the above flags are a fatal error
534
Elliott Hughes69a017b2011-04-08 14:10:28 -0700535 jniThrowException(env, "java/io/IOException",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800536 "Unexpected error or truncation during recvmsg()");
537
538 return -1;
539 }
540
541 if (ret >= 0) {
542 socket_process_cmsg(env, thisJ, &msg);
543 }
544
545 return ret;
546}
547
548/**
549 * Writes all the data in the specified buffer to the specified socket.
550 *
551 * Returns 0 on success or -1 if an exception was thrown.
552 */
553static int socket_write_all(JNIEnv *env, jobject object, int fd,
554 void *buf, size_t len)
555{
556 ssize_t ret;
557 struct msghdr msg;
558 unsigned char *buffer = (unsigned char *)buf;
559 memset(&msg, 0, sizeof(msg));
560
Elliott Hughes69a017b2011-04-08 14:10:28 -0700561 jobjectArray outboundFds
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800562 = (jobjectArray)env->GetObjectField(
563 object, field_outboundFileDescriptors);
564
565 if (env->ExceptionOccurred() != NULL) {
566 return -1;
567 }
568
569 struct cmsghdr *cmsg;
570 int countFds = outboundFds == NULL ? 0 : env->GetArrayLength(outboundFds);
571 int fds[countFds];
572 char msgbuf[CMSG_SPACE(countFds)];
573
574 // Add any pending outbound file descriptors to the message
575 if (outboundFds != NULL) {
576
577 if (env->ExceptionOccurred() != NULL) {
578 return -1;
579 }
580
581 for (int i = 0; i < countFds; i++) {
582 jobject fdObject = env->GetObjectArrayElement(outboundFds, i);
583 if (env->ExceptionOccurred() != NULL) {
584 return -1;
585 }
586
587 fds[i] = jniGetFDFromFileDescriptor(env, fdObject);
588 if (env->ExceptionOccurred() != NULL) {
589 return -1;
590 }
591 }
592
593 // See "man cmsg" really
594 msg.msg_control = msgbuf;
595 msg.msg_controllen = sizeof msgbuf;
596 cmsg = CMSG_FIRSTHDR(&msg);
597 cmsg->cmsg_level = SOL_SOCKET;
598 cmsg->cmsg_type = SCM_RIGHTS;
599 cmsg->cmsg_len = CMSG_LEN(sizeof fds);
600 memcpy(CMSG_DATA(cmsg), fds, sizeof fds);
601 }
602
603 // We only write our msg_control during the first write
604 while (len > 0) {
605 struct iovec iv;
606 memset(&iv, 0, sizeof(iv));
607
608 iv.iov_base = buffer;
609 iv.iov_len = len;
610
611 msg.msg_iov = &iv;
612 msg.msg_iovlen = 1;
Elliott Hughes69a017b2011-04-08 14:10:28 -0700613
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800614 do {
615 ret = sendmsg(fd, &msg, MSG_NOSIGNAL);
616 } while (ret < 0 && errno == EINTR);
617
618 if (ret < 0) {
619 jniThrowIOException(env, errno);
620 return -1;
621 }
622
623 buffer += ret;
624 len -= ret;
625
626 // Wipes out any msg_control too
627 memset(&msg, 0, sizeof(msg));
628 }
629
630 return 0;
631}
632
633static jint socket_read (JNIEnv *env, jobject object, jobject fileDescriptor)
634{
635 int fd;
636 int err;
637
638 if (fileDescriptor == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700639 jniThrowNullPointerException(env, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800640 return (jint)-1;
641 }
642
643 fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
644
645 if (env->ExceptionOccurred() != NULL) {
646 return (jint)0;
647 }
648
649 unsigned char buf;
650
651 err = socket_read_all(env, object, fd, &buf, 1);
652
653 if (err < 0) {
654 jniThrowIOException(env, errno);
655 return (jint)0;
656 }
657
658 if (err == 0) {
659 // end of file
660 return (jint)-1;
661 }
662
663 return (jint)buf;
664}
665
Elliott Hughes69a017b2011-04-08 14:10:28 -0700666static jint socket_readba (JNIEnv *env, jobject object,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800667 jbyteArray buffer, jint off, jint len, jobject fileDescriptor)
668{
669 int fd;
670 jbyte* byteBuffer;
671 int ret;
672
673 if (fileDescriptor == NULL || buffer == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700674 jniThrowNullPointerException(env, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800675 return (jint)-1;
676 }
677
678 if (off < 0 || len < 0 || (off + len) > env->GetArrayLength(buffer)) {
679 jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", NULL);
680 return (jint)-1;
681 }
682
683 if (len == 0) {
684 // because socket_read_all returns 0 on EOF
685 return 0;
686 }
687
688 fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
689
690 if (env->ExceptionOccurred() != NULL) {
691 return (jint)-1;
692 }
693
694 byteBuffer = env->GetByteArrayElements(buffer, NULL);
695
696 if (NULL == byteBuffer) {
697 // an exception will have been thrown
698 return (jint)-1;
699 }
700
Elliott Hughes69a017b2011-04-08 14:10:28 -0700701 ret = socket_read_all(env, object,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800702 fd, byteBuffer + off, len);
703
704 // A return of -1 above means an exception is pending
705
706 env->ReleaseByteArrayElements(buffer, byteBuffer, 0);
707
708 return (jint) ((ret == 0) ? -1 : ret);
709}
710
Elliott Hughes69a017b2011-04-08 14:10:28 -0700711static void socket_write (JNIEnv *env, jobject object,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800712 jint b, jobject fileDescriptor)
713{
714 int fd;
715 int err;
716
717 if (fileDescriptor == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700718 jniThrowNullPointerException(env, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800719 return;
720 }
721
722 fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
723
724 if (env->ExceptionOccurred() != NULL) {
725 return;
726 }
727
728 err = socket_write_all(env, object, fd, &b, 1);
729
730 // A return of -1 above means an exception is pending
731}
732
Elliott Hughes69a017b2011-04-08 14:10:28 -0700733static void socket_writeba (JNIEnv *env, jobject object,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800734 jbyteArray buffer, jint off, jint len, jobject fileDescriptor)
735{
736 int fd;
737 int err;
738 jbyte* byteBuffer;
739
740 if (fileDescriptor == NULL || buffer == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700741 jniThrowNullPointerException(env, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800742 return;
743 }
744
745 if (off < 0 || len < 0 || (off + len) > env->GetArrayLength(buffer)) {
746 jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", NULL);
747 return;
748 }
749
750 fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
751
752 if (env->ExceptionOccurred() != NULL) {
753 return;
754 }
755
756 byteBuffer = env->GetByteArrayElements(buffer,NULL);
757
758 if (NULL == byteBuffer) {
759 // an exception will have been thrown
760 return;
761 }
762
Elliott Hughes69a017b2011-04-08 14:10:28 -0700763 err = socket_write_all(env, object, fd,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800764 byteBuffer + off, len);
765
766 // A return of -1 above means an exception is pending
767
768 env->ReleaseByteArrayElements(buffer, byteBuffer, JNI_ABORT);
769}
770
Elliott Hughes69a017b2011-04-08 14:10:28 -0700771static jobject socket_get_peer_credentials(JNIEnv *env,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800772 jobject object, jobject fileDescriptor)
773{
774 int err;
775 int fd;
776
777 if (fileDescriptor == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700778 jniThrowNullPointerException(env, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800779 return NULL;
780 }
781
782 fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
783
784 if (env->ExceptionOccurred() != NULL) {
785 return NULL;
786 }
787
788 struct ucred creds;
789
790 memset(&creds, 0, sizeof(creds));
791 socklen_t szCreds = sizeof(creds);
792
Elliott Hughes69a017b2011-04-08 14:10:28 -0700793 err = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &creds, &szCreds);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800794
795 if (err < 0) {
796 jniThrowIOException(env, errno);
797 return NULL;
798 }
799
800 if (szCreds == 0) {
801 return NULL;
802 }
803
Elliott Hughes69a017b2011-04-08 14:10:28 -0700804 return env->NewObject(class_Credentials, method_CredentialsInit,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800805 creds.pid, creds.uid, creds.gid);
806}
807
808#if 0
809//TODO change this to return an instance of LocalSocketAddress
Elliott Hughes69a017b2011-04-08 14:10:28 -0700810static jobject socket_getSockName(JNIEnv *env,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800811 jobject object, jobject fileDescriptor)
812{
813 int err;
814 int fd;
815
816 if (fileDescriptor == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700817 jniThrowNullPointerException(env, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800818 return NULL;
819 }
820
821 fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
822
823 if (env->ExceptionOccurred() != NULL) {
824 return NULL;
825 }
826
827 union {
828 struct sockaddr address;
829 struct sockaddr_un un_address;
830 } sa;
831
832 memset(&sa, 0, sizeof(sa));
833
834 socklen_t namelen = sizeof(sa);
835 err = getsockname(fd, &(sa.address), &namelen);
836
837 if (err < 0) {
838 jniThrowIOException(env, errno);
839 return NULL;
840 }
841
842 if (sa.address.sa_family != AF_UNIX) {
843 // We think we're an impl only for AF_UNIX, so this should never happen.
844
845 jniThrowIOException(env, EINVAL);
846 return NULL;
847 }
848
849 if (sa.un_address.sun_path[0] == '\0') {
850 } else {
851 }
852
853
854
855
856}
857#endif
858
859/*
860 * JNI registration.
861 */
862static JNINativeMethod gMethods[] = {
863 /* name, signature, funcPtr */
864 {"getOption_native", "(Ljava/io/FileDescriptor;I)I", (void*)socket_getOption},
865 {"setOption_native", "(Ljava/io/FileDescriptor;III)V", (void*)socket_setOption},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800866 {"connectLocal", "(Ljava/io/FileDescriptor;Ljava/lang/String;I)V",
867 (void*)socket_connect_local},
868 {"bindLocal", "(Ljava/io/FileDescriptor;Ljava/lang/String;I)V", (void*)socket_bind_local},
869 {"listen_native", "(Ljava/io/FileDescriptor;I)V", (void*)socket_listen},
870 {"accept", "(Ljava/io/FileDescriptor;Landroid/net/LocalSocketImpl;)Ljava/io/FileDescriptor;", (void*)socket_accept},
871 {"shutdown", "(Ljava/io/FileDescriptor;Z)V", (void*)socket_shutdown},
872 {"available_native", "(Ljava/io/FileDescriptor;)I", (void*) socket_available},
zzy71bfafc2013-04-16 17:17:37 -0700873 {"pending_native", "(Ljava/io/FileDescriptor;)I", (void*) socket_pending},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800874 {"read_native", "(Ljava/io/FileDescriptor;)I", (void*) socket_read},
875 {"readba_native", "([BIILjava/io/FileDescriptor;)I", (void*) socket_readba},
876 {"writeba_native", "([BIILjava/io/FileDescriptor;)V", (void*) socket_writeba},
877 {"write_native", "(ILjava/io/FileDescriptor;)V", (void*) socket_write},
Elliott Hughes69a017b2011-04-08 14:10:28 -0700878 {"getPeerCredentials_native",
879 "(Ljava/io/FileDescriptor;)Landroid/net/Credentials;",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800880 (void*) socket_get_peer_credentials}
Elliott Hughes69a017b2011-04-08 14:10:28 -0700881 //,{"getSockName_native", "(Ljava/io/FileDescriptor;)Ljava/lang/String;",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800882 // (void *) socket_getSockName}
883
884};
885
886int register_android_net_LocalSocketImpl(JNIEnv *env)
887{
888 jclass clazz;
889
890 clazz = env->FindClass("android/net/LocalSocketImpl");
891
892 if (clazz == NULL) {
893 goto error;
894 }
895
Elliott Hughes69a017b2011-04-08 14:10:28 -0700896 field_inboundFileDescriptors = env->GetFieldID(clazz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800897 "inboundFileDescriptors", "[Ljava/io/FileDescriptor;");
898
899 if (field_inboundFileDescriptors == NULL) {
900 goto error;
901 }
902
Elliott Hughes69a017b2011-04-08 14:10:28 -0700903 field_outboundFileDescriptors = env->GetFieldID(clazz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800904 "outboundFileDescriptors", "[Ljava/io/FileDescriptor;");
905
906 if (field_outboundFileDescriptors == NULL) {
907 goto error;
908 }
909
910 class_Credentials = env->FindClass("android/net/Credentials");
Elliott Hughes69a017b2011-04-08 14:10:28 -0700911
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800912 if (class_Credentials == NULL) {
913 goto error;
914 }
915
916 class_Credentials = (jclass)env->NewGlobalRef(class_Credentials);
917
918 class_FileDescriptor = env->FindClass("java/io/FileDescriptor");
919
920 if (class_FileDescriptor == NULL) {
921 goto error;
922 }
923
924 class_FileDescriptor = (jclass)env->NewGlobalRef(class_FileDescriptor);
925
Elliott Hughes69a017b2011-04-08 14:10:28 -0700926 method_CredentialsInit
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800927 = env->GetMethodID(class_Credentials, "<init>", "(III)V");
928
929 if (method_CredentialsInit == NULL) {
930 goto error;
931 }
932
933 return jniRegisterNativeMethods(env,
934 "android/net/LocalSocketImpl", gMethods, NELEM(gMethods));
935
936error:
Steve Block3762c312012-01-06 19:20:56 +0000937 ALOGE("Error registering android.net.LocalSocketImpl");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800938 return -1;
939}
940
941};