Path: blob/master/src/java.base/unix/native/libnio/ch/UnixDomainSockets.c
41133 views
/*1* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425#include <poll.h>26#include <sys/types.h>27#include <sys/socket.h>28#include <string.h>29#include <stddef.h>30#include <netinet/in.h>31#include <netinet/tcp.h>32#include <limits.h>3334#include "jni.h"35#include "java_props.h"36#include "jni_util.h"37#include "jvm.h"38#include "jlong.h"39#include "sun_nio_ch_Net.h"40#include "nio_util.h"41#include "nio.h"4243/* Subtle platform differences in how unnamed sockets (empty path)44* are returned from getsockname()45*/46#ifdef MACOSX47#define ZERO_PATHLEN(len) (JNI_FALSE)48#else49#define ZERO_PATHLEN(len) (len == offsetof(struct sockaddr_un, sun_path))50#endif5152jbyteArray sockaddrToUnixAddressBytes(JNIEnv *env, struct sockaddr_un *sa, socklen_t len)53{54if (sa->sun_family == AF_UNIX) {55int namelen;56if (ZERO_PATHLEN(len)) {57namelen = 0;58} else {59namelen = strlen(sa->sun_path);60}61jbyteArray name = (*env)->NewByteArray(env, namelen);62if (namelen != 0) {63(*env)->SetByteArrayRegion(env, name, 0, namelen, (jbyte*)sa->sun_path);64if ((*env)->ExceptionOccurred(env)) {65return NULL;66}67}68return name;69}70return NULL;71}7273jint unixSocketAddressToSockaddr(JNIEnv *env, jbyteArray path, struct sockaddr_un *sa, int *len)74{75memset(sa, 0, sizeof(struct sockaddr_un));76sa->sun_family = AF_UNIX;77int ret;78const char* pname = (const char *)(*env)->GetByteArrayElements(env, path, NULL);79if (pname == NULL) {80JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Unix domain path not present");81return -1;82}83size_t name_len = (*env)->GetArrayLength(env, path);84if (name_len > MAX_UNIX_DOMAIN_PATH_LEN) {85JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Unix domain path too long");86ret = -1;87} else {88memcpy(sa->sun_path, pname, name_len);89*len = (int)(offsetof(struct sockaddr_un, sun_path) + name_len + 1);90ret = 0;91}92(*env)->ReleaseByteArrayElements(env, path, (jbyte *)pname, 0);93return ret;94}9596JNIEXPORT jboolean JNICALL97Java_sun_nio_ch_UnixDomainSockets_socketSupported(JNIEnv *env, jclass cl)98{99return JNI_TRUE;100}101102JNIEXPORT jint JNICALL103Java_sun_nio_ch_UnixDomainSockets_socket0(JNIEnv *env, jclass cl)104{105int fd = socket(PF_UNIX, SOCK_STREAM, 0);106if (fd < 0) {107return handleSocketError(env, errno);108}109return fd;110}111112JNIEXPORT void JNICALL113Java_sun_nio_ch_UnixDomainSockets_bind0(JNIEnv *env, jclass clazz, jobject fdo, jbyteArray path)114{115struct sockaddr_un sa;116int sa_len = 0;117int rv = 0;118119if (unixSocketAddressToSockaddr(env, path, &sa, &sa_len) != 0)120return;121122rv = bind(fdval(env, fdo), (struct sockaddr *)&sa, sa_len);123if (rv != 0) {124handleSocketError(env, errno);125}126}127128JNIEXPORT jint JNICALL129Java_sun_nio_ch_UnixDomainSockets_connect0(JNIEnv *env, jclass clazz, jobject fdo, jbyteArray path)130{131struct sockaddr_un sa;132int sa_len = 0;133int rv;134135if (unixSocketAddressToSockaddr(env, path, &sa, &sa_len) != 0) {136return IOS_THROWN;137}138139rv = connect(fdval(env, fdo), (struct sockaddr *)&sa, sa_len);140if (rv != 0) {141if (errno == EINPROGRESS) {142return IOS_UNAVAILABLE;143} else if (errno == EINTR) {144return IOS_INTERRUPTED;145}146return handleSocketError(env, errno);147}148return 1;149}150151JNIEXPORT jint JNICALL152Java_sun_nio_ch_UnixDomainSockets_accept0(JNIEnv *env, jclass clazz, jobject fdo, jobject newfdo,153jobjectArray array)154{155jint fd = fdval(env, fdo);156jint newfd;157struct sockaddr_un sa;158socklen_t sa_len = sizeof(struct sockaddr_un);159jbyteArray address;160161newfd = accept(fd, (struct sockaddr *)&sa, &sa_len);162if (newfd < 0) {163if (errno == EAGAIN || errno == EWOULDBLOCK)164return IOS_UNAVAILABLE;165if (errno == EINTR)166return IOS_INTERRUPTED;167JNU_ThrowIOExceptionWithLastError(env, "Accept failed");168return IOS_THROWN;169}170171setfdval(env, newfdo, newfd);172173address = sockaddrToUnixAddressBytes(env, &sa, sa_len);174CHECK_NULL_RETURN(address, IOS_THROWN);175176(*env)->SetObjectArrayElement(env, array, 0, address);177178return 1;179}180181JNIEXPORT jbyteArray JNICALL182Java_sun_nio_ch_UnixDomainSockets_localAddress0(JNIEnv *env, jclass clazz, jobject fdo)183{184struct sockaddr_un sa;185socklen_t sa_len = sizeof(struct sockaddr_un);186int port;187if (getsockname(fdval(env, fdo), (struct sockaddr *)&sa, &sa_len) < 0) {188handleSocketError(env, errno);189return NULL;190}191return sockaddrToUnixAddressBytes(env, &sa, sa_len);192}193194195196