blob: 1163b860977d8960e4f504ee499f92d03582c48d [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
Steven Moreland2279b252017-07-19 09:50:45 -070019#include <nativehelper/JNIHelp.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080020#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
Josh Gao79e3be82019-02-11 14:37:21 -080036#include <android-base/cmsg.h>
37#include <android-base/macros.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038#include <cutils/sockets.h>
39#include <netinet/tcp.h>
Steven Moreland2279b252017-07-19 09:50:45 -070040#include <nativehelper/ScopedUtfChars.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041
Josh Gao79e3be82019-02-11 14:37:21 -080042using android::base::ReceiveFileDescriptorVector;
43using android::base::SendFileDescriptorVector;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044
Josh Gao79e3be82019-02-11 14:37:21 -080045namespace android {
Andreas Gampe0f0b4912014-11-12 08:03:48 -080046
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047static jfieldID field_inboundFileDescriptors;
48static jfieldID field_outboundFileDescriptors;
49static jclass class_Credentials;
50static jclass class_FileDescriptor;
51static jmethodID method_CredentialsInit;
52
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053/* private native void connectLocal(FileDescriptor fd,
54 * String name, int namespace) throws IOException
55 */
56static void
57socket_connect_local(JNIEnv *env, jobject object,
58 jobject fileDescriptor, jstring name, jint namespaceId)
59{
60 int ret;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061 int fd;
62
Torne (Richard Coles)771b1872017-03-16 15:52:46 +000063 if (name == NULL) {
64 jniThrowNullPointerException(env, NULL);
65 return;
66 }
67
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080068 fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
69
Mathieu Chartier98671c32014-08-20 10:04:08 -070070 if (env->ExceptionCheck()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080071 return;
72 }
73
You Kim092eb8d2012-12-04 00:46:17 +090074 ScopedUtfChars nameUtf8(env, name);
75
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080076 ret = socket_local_client_connect(
77 fd,
You Kim092eb8d2012-12-04 00:46:17 +090078 nameUtf8.c_str(),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079 namespaceId,
80 SOCK_STREAM);
81
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080082 if (ret < 0) {
83 jniThrowIOException(env, errno);
84 return;
85 }
86}
87
88#define DEFAULT_BACKLOG 4
89
Elliott Hughes69a017b2011-04-08 14:10:28 -070090/* private native void bindLocal(FileDescriptor fd, String name, namespace)
91 * throws IOException;
92 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080093
94static void
95socket_bind_local (JNIEnv *env, jobject object, jobject fileDescriptor,
96 jstring name, jint namespaceId)
97{
98 int ret;
99 int fd;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800100
101 if (name == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700102 jniThrowNullPointerException(env, NULL);
You Kim092eb8d2012-12-04 00:46:17 +0900103 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104 }
105
106 fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
107
Mathieu Chartier98671c32014-08-20 10:04:08 -0700108 if (env->ExceptionCheck()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800109 return;
110 }
111
You Kim092eb8d2012-12-04 00:46:17 +0900112 ScopedUtfChars nameUtf8(env, name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800113
You Kim092eb8d2012-12-04 00:46:17 +0900114 ret = socket_local_server_bind(fd, nameUtf8.c_str(), namespaceId);
Elliott Hughes69a017b2011-04-08 14:10:28 -0700115
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800116 if (ret < 0) {
117 jniThrowIOException(env, errno);
118 return;
119 }
120}
121
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800122/**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800123 * Reads data from a socket into buf, processing any ancillary data
124 * and adding it to thisJ.
125 *
126 * Returns the length of normal data read, or -1 if an exception has
127 * been thrown in this function.
128 */
Elliott Hughes69a017b2011-04-08 14:10:28 -0700129static ssize_t socket_read_all(JNIEnv *env, jobject thisJ, int fd,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800130 void *buffer, size_t len)
131{
132 ssize_t ret;
Josh Gao79e3be82019-02-11 14:37:21 -0800133 std::vector<android::base::unique_fd> received_fds;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800134
Josh Gao79e3be82019-02-11 14:37:21 -0800135 ret = ReceiveFileDescriptorVector(fd, buffer, len, 64, &received_fds);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800136
137 if (ret < 0) {
Josh Gao79e3be82019-02-11 14:37:21 -0800138 if (errno == EPIPE) {
139 // Treat this as an end of stream
140 return 0;
141 }
142
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800143 jniThrowIOException(env, errno);
144 return -1;
145 }
146
Josh Gao79e3be82019-02-11 14:37:21 -0800147 if (received_fds.size() > 0) {
148 jobjectArray fdArray = env->NewObjectArray(received_fds.size(), class_FileDescriptor, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800149
Josh Gao79e3be82019-02-11 14:37:21 -0800150 if (fdArray == NULL) {
151 // NewObjectArray has thrown.
152 return -1;
153 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800154
Josh Gao79e3be82019-02-11 14:37:21 -0800155 for (size_t i = 0; i < received_fds.size(); i++) {
156 jobject fdObject = jniCreateFileDescriptor(env, received_fds[i].get());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800157
Josh Gao79e3be82019-02-11 14:37:21 -0800158 if (env->ExceptionCheck()) {
159 return -1;
160 }
161
162 env->SetObjectArrayElement(fdArray, i, fdObject);
163
164 if (env->ExceptionCheck()) {
165 return -1;
166 }
167 }
168
169 for (auto &fd : received_fds) {
170 // The fds are stored in java.io.FileDescriptors now.
171 static_cast<void>(fd.release());
172 }
173
174 env->SetObjectField(thisJ, field_inboundFileDescriptors, fdArray);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800175 }
176
177 return ret;
178}
179
180/**
181 * Writes all the data in the specified buffer to the specified socket.
182 *
183 * Returns 0 on success or -1 if an exception was thrown.
184 */
185static int socket_write_all(JNIEnv *env, jobject object, int fd,
186 void *buf, size_t len)
187{
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800188 struct msghdr msg;
189 unsigned char *buffer = (unsigned char *)buf;
190 memset(&msg, 0, sizeof(msg));
191
Elliott Hughes69a017b2011-04-08 14:10:28 -0700192 jobjectArray outboundFds
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800193 = (jobjectArray)env->GetObjectField(
194 object, field_outboundFileDescriptors);
195
Mathieu Chartier98671c32014-08-20 10:04:08 -0700196 if (env->ExceptionCheck()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800197 return -1;
198 }
199
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800200 int countFds = outboundFds == NULL ? 0 : env->GetArrayLength(outboundFds);
Josh Gao79e3be82019-02-11 14:37:21 -0800201 std::vector<int> fds;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800202
203 // Add any pending outbound file descriptors to the message
204 if (outboundFds != NULL) {
Mathieu Chartier98671c32014-08-20 10:04:08 -0700205 if (env->ExceptionCheck()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800206 return -1;
207 }
208
209 for (int i = 0; i < countFds; i++) {
210 jobject fdObject = env->GetObjectArrayElement(outboundFds, i);
Mathieu Chartier98671c32014-08-20 10:04:08 -0700211 if (env->ExceptionCheck()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800212 return -1;
213 }
214
Josh Gao79e3be82019-02-11 14:37:21 -0800215 fds.push_back(jniGetFDFromFileDescriptor(env, fdObject));
Mathieu Chartier98671c32014-08-20 10:04:08 -0700216 if (env->ExceptionCheck()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800217 return -1;
218 }
219 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800220 }
221
Josh Gao79e3be82019-02-11 14:37:21 -0800222 ssize_t rc = SendFileDescriptorVector(fd, buffer, len, fds);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800223
Josh Gao79e3be82019-02-11 14:37:21 -0800224 while (rc != len) {
225 if (rc == -1) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800226 jniThrowIOException(env, errno);
227 return -1;
228 }
229
Josh Gao79e3be82019-02-11 14:37:21 -0800230 buffer += rc;
231 len -= rc;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800232
Josh Gao79e3be82019-02-11 14:37:21 -0800233 rc = send(fd, buffer, len, MSG_NOSIGNAL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800234 }
235
236 return 0;
237}
238
239static jint socket_read (JNIEnv *env, jobject object, jobject fileDescriptor)
240{
241 int fd;
242 int err;
243
244 if (fileDescriptor == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700245 jniThrowNullPointerException(env, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800246 return (jint)-1;
247 }
248
249 fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
250
Mathieu Chartier98671c32014-08-20 10:04:08 -0700251 if (env->ExceptionCheck()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800252 return (jint)0;
253 }
254
255 unsigned char buf;
256
257 err = socket_read_all(env, object, fd, &buf, 1);
258
259 if (err < 0) {
260 jniThrowIOException(env, errno);
261 return (jint)0;
262 }
263
264 if (err == 0) {
265 // end of file
266 return (jint)-1;
267 }
268
269 return (jint)buf;
270}
271
Elliott Hughes69a017b2011-04-08 14:10:28 -0700272static jint socket_readba (JNIEnv *env, jobject object,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800273 jbyteArray buffer, jint off, jint len, jobject fileDescriptor)
274{
275 int fd;
276 jbyte* byteBuffer;
277 int ret;
278
279 if (fileDescriptor == NULL || buffer == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700280 jniThrowNullPointerException(env, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800281 return (jint)-1;
282 }
283
284 if (off < 0 || len < 0 || (off + len) > env->GetArrayLength(buffer)) {
285 jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", NULL);
286 return (jint)-1;
287 }
288
289 if (len == 0) {
290 // because socket_read_all returns 0 on EOF
291 return 0;
292 }
293
294 fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
295
Mathieu Chartier98671c32014-08-20 10:04:08 -0700296 if (env->ExceptionCheck()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800297 return (jint)-1;
298 }
299
300 byteBuffer = env->GetByteArrayElements(buffer, NULL);
301
302 if (NULL == byteBuffer) {
303 // an exception will have been thrown
304 return (jint)-1;
305 }
306
Elliott Hughes69a017b2011-04-08 14:10:28 -0700307 ret = socket_read_all(env, object,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800308 fd, byteBuffer + off, len);
309
310 // A return of -1 above means an exception is pending
311
312 env->ReleaseByteArrayElements(buffer, byteBuffer, 0);
313
314 return (jint) ((ret == 0) ? -1 : ret);
315}
316
Elliott Hughes69a017b2011-04-08 14:10:28 -0700317static void socket_write (JNIEnv *env, jobject object,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800318 jint b, jobject fileDescriptor)
319{
320 int fd;
321 int err;
322
323 if (fileDescriptor == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700324 jniThrowNullPointerException(env, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800325 return;
326 }
327
328 fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
329
Mathieu Chartier98671c32014-08-20 10:04:08 -0700330 if (env->ExceptionCheck()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800331 return;
332 }
333
334 err = socket_write_all(env, object, fd, &b, 1);
Andreas Gampe0f0b4912014-11-12 08:03:48 -0800335 UNUSED(err);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800336 // A return of -1 above means an exception is pending
337}
338
Elliott Hughes69a017b2011-04-08 14:10:28 -0700339static void socket_writeba (JNIEnv *env, jobject object,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800340 jbyteArray buffer, jint off, jint len, jobject fileDescriptor)
341{
342 int fd;
343 int err;
344 jbyte* byteBuffer;
345
346 if (fileDescriptor == NULL || buffer == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700347 jniThrowNullPointerException(env, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800348 return;
349 }
350
351 if (off < 0 || len < 0 || (off + len) > env->GetArrayLength(buffer)) {
352 jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", NULL);
353 return;
354 }
355
356 fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
357
Mathieu Chartier98671c32014-08-20 10:04:08 -0700358 if (env->ExceptionCheck()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800359 return;
360 }
361
362 byteBuffer = env->GetByteArrayElements(buffer,NULL);
363
364 if (NULL == byteBuffer) {
365 // an exception will have been thrown
366 return;
367 }
368
Elliott Hughes69a017b2011-04-08 14:10:28 -0700369 err = socket_write_all(env, object, fd,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800370 byteBuffer + off, len);
Andreas Gampe0f0b4912014-11-12 08:03:48 -0800371 UNUSED(err);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800372 // A return of -1 above means an exception is pending
373
374 env->ReleaseByteArrayElements(buffer, byteBuffer, JNI_ABORT);
375}
376
Elliott Hughes69a017b2011-04-08 14:10:28 -0700377static jobject socket_get_peer_credentials(JNIEnv *env,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800378 jobject object, jobject fileDescriptor)
379{
380 int err;
381 int fd;
382
383 if (fileDescriptor == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700384 jniThrowNullPointerException(env, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800385 return NULL;
386 }
387
388 fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
389
Mathieu Chartier98671c32014-08-20 10:04:08 -0700390 if (env->ExceptionCheck()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800391 return NULL;
392 }
393
394 struct ucred creds;
395
396 memset(&creds, 0, sizeof(creds));
397 socklen_t szCreds = sizeof(creds);
398
Elliott Hughes69a017b2011-04-08 14:10:28 -0700399 err = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &creds, &szCreds);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800400
401 if (err < 0) {
402 jniThrowIOException(env, errno);
403 return NULL;
404 }
405
406 if (szCreds == 0) {
407 return NULL;
408 }
409
Elliott Hughes69a017b2011-04-08 14:10:28 -0700410 return env->NewObject(class_Credentials, method_CredentialsInit,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800411 creds.pid, creds.uid, creds.gid);
412}
413
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800414/*
415 * JNI registration.
416 */
Daniel Micay76f6a862015-09-19 17:31:01 -0400417static const JNINativeMethod gMethods[] = {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800418 /* name, signature, funcPtr */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800419 {"connectLocal", "(Ljava/io/FileDescriptor;Ljava/lang/String;I)V",
420 (void*)socket_connect_local},
421 {"bindLocal", "(Ljava/io/FileDescriptor;Ljava/lang/String;I)V", (void*)socket_bind_local},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800422 {"read_native", "(Ljava/io/FileDescriptor;)I", (void*) socket_read},
423 {"readba_native", "([BIILjava/io/FileDescriptor;)I", (void*) socket_readba},
424 {"writeba_native", "([BIILjava/io/FileDescriptor;)V", (void*) socket_writeba},
425 {"write_native", "(ILjava/io/FileDescriptor;)V", (void*) socket_write},
Elliott Hughes69a017b2011-04-08 14:10:28 -0700426 {"getPeerCredentials_native",
427 "(Ljava/io/FileDescriptor;)Landroid/net/Credentials;",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800428 (void*) socket_get_peer_credentials}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800429};
430
431int register_android_net_LocalSocketImpl(JNIEnv *env)
432{
433 jclass clazz;
434
435 clazz = env->FindClass("android/net/LocalSocketImpl");
436
437 if (clazz == NULL) {
438 goto error;
439 }
440
Elliott Hughes69a017b2011-04-08 14:10:28 -0700441 field_inboundFileDescriptors = env->GetFieldID(clazz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800442 "inboundFileDescriptors", "[Ljava/io/FileDescriptor;");
443
444 if (field_inboundFileDescriptors == NULL) {
445 goto error;
446 }
447
Elliott Hughes69a017b2011-04-08 14:10:28 -0700448 field_outboundFileDescriptors = env->GetFieldID(clazz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800449 "outboundFileDescriptors", "[Ljava/io/FileDescriptor;");
450
451 if (field_outboundFileDescriptors == NULL) {
452 goto error;
453 }
454
455 class_Credentials = env->FindClass("android/net/Credentials");
Elliott Hughes69a017b2011-04-08 14:10:28 -0700456
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800457 if (class_Credentials == NULL) {
458 goto error;
459 }
460
461 class_Credentials = (jclass)env->NewGlobalRef(class_Credentials);
462
463 class_FileDescriptor = env->FindClass("java/io/FileDescriptor");
464
465 if (class_FileDescriptor == NULL) {
466 goto error;
467 }
468
469 class_FileDescriptor = (jclass)env->NewGlobalRef(class_FileDescriptor);
470
Elliott Hughes69a017b2011-04-08 14:10:28 -0700471 method_CredentialsInit
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800472 = env->GetMethodID(class_Credentials, "<init>", "(III)V");
473
474 if (method_CredentialsInit == NULL) {
475 goto error;
476 }
477
478 return jniRegisterNativeMethods(env,
479 "android/net/LocalSocketImpl", gMethods, NELEM(gMethods));
480
481error:
Steve Block3762c312012-01-06 19:20:56 +0000482 ALOGE("Error registering android.net.LocalSocketImpl");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800483 return -1;
484}
485
486};