mirror of
https://github.com/openjdk/jdk.git
synced 2026-02-02 14:38:28 +00:00
195 lines
5.8 KiB
C
195 lines
5.8 KiB
C
/*
|
|
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* This code is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License version 2 only, as
|
|
* published by the Free Software Foundation. Oracle designates this
|
|
* particular file as subject to the "Classpath" exception as provided
|
|
* by Oracle in the LICENSE file that accompanied this code.
|
|
*
|
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
* accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU General Public License version
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
* or visit www.oracle.com if you need additional information or have any
|
|
* questions.
|
|
*/
|
|
|
|
#include <poll.h>
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <string.h>
|
|
#include <stddef.h>
|
|
#include <netinet/in.h>
|
|
#include <netinet/tcp.h>
|
|
#include <limits.h>
|
|
|
|
#include "jni.h"
|
|
#include "java_props.h"
|
|
#include "jni_util.h"
|
|
#include "jvm.h"
|
|
#include "jlong.h"
|
|
#include "sun_nio_ch_Net.h"
|
|
#include "nio_util.h"
|
|
#include "nio.h"
|
|
|
|
/* Subtle platform differences in how unnamed sockets (empty path)
|
|
* are returned from getsockname()
|
|
*/
|
|
#ifdef MACOSX
|
|
#define ZERO_PATHLEN(len) (JNI_FALSE)
|
|
#else
|
|
#define ZERO_PATHLEN(len) (len == offsetof(struct sockaddr_un, sun_path))
|
|
#endif
|
|
|
|
jbyteArray sockaddrToUnixAddressBytes(JNIEnv *env, struct sockaddr_un *sa, socklen_t len)
|
|
{
|
|
if (sa->sun_family == AF_UNIX) {
|
|
int namelen;
|
|
if (ZERO_PATHLEN(len)) {
|
|
namelen = 0;
|
|
} else {
|
|
namelen = strlen(sa->sun_path);
|
|
}
|
|
jbyteArray name = (*env)->NewByteArray(env, namelen);
|
|
if (namelen != 0) {
|
|
(*env)->SetByteArrayRegion(env, name, 0, namelen, (jbyte*)sa->sun_path);
|
|
if ((*env)->ExceptionOccurred(env)) {
|
|
return NULL;
|
|
}
|
|
}
|
|
return name;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
jint unixSocketAddressToSockaddr(JNIEnv *env, jbyteArray path, struct sockaddr_un *sa, int *len)
|
|
{
|
|
memset(sa, 0, sizeof(struct sockaddr_un));
|
|
sa->sun_family = AF_UNIX;
|
|
int ret;
|
|
const char* pname = (const char *)(*env)->GetByteArrayElements(env, path, NULL);
|
|
if (pname == NULL) {
|
|
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Unix domain path not present");
|
|
return -1;
|
|
}
|
|
size_t name_len = (*env)->GetArrayLength(env, path);
|
|
if (name_len > MAX_UNIX_DOMAIN_PATH_LEN) {
|
|
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Unix domain path too long");
|
|
ret = -1;
|
|
} else {
|
|
memcpy(sa->sun_path, pname, name_len);
|
|
*len = (int)(offsetof(struct sockaddr_un, sun_path) + name_len + 1);
|
|
ret = 0;
|
|
}
|
|
(*env)->ReleaseByteArrayElements(env, path, (jbyte *)pname, 0);
|
|
return ret;
|
|
}
|
|
|
|
JNIEXPORT jboolean JNICALL
|
|
Java_sun_nio_ch_UnixDomainSockets_init(JNIEnv *env, jclass cl)
|
|
{
|
|
return JNI_TRUE;
|
|
}
|
|
|
|
JNIEXPORT jint JNICALL
|
|
Java_sun_nio_ch_UnixDomainSockets_socket0(JNIEnv *env, jclass cl)
|
|
{
|
|
int fd = socket(PF_UNIX, SOCK_STREAM, 0);
|
|
if (fd < 0) {
|
|
return handleSocketError(env, errno);
|
|
}
|
|
return fd;
|
|
}
|
|
|
|
JNIEXPORT void JNICALL
|
|
Java_sun_nio_ch_UnixDomainSockets_bind0(JNIEnv *env, jclass clazz, jobject fdo, jbyteArray path)
|
|
{
|
|
struct sockaddr_un sa;
|
|
int sa_len = 0;
|
|
int rv = 0;
|
|
|
|
if (unixSocketAddressToSockaddr(env, path, &sa, &sa_len) != 0)
|
|
return;
|
|
|
|
rv = bind(fdval(env, fdo), (struct sockaddr *)&sa, sa_len);
|
|
if (rv != 0) {
|
|
handleSocketError(env, errno);
|
|
}
|
|
}
|
|
|
|
JNIEXPORT jint JNICALL
|
|
Java_sun_nio_ch_UnixDomainSockets_connect0(JNIEnv *env, jclass clazz, jobject fdo, jbyteArray path)
|
|
{
|
|
struct sockaddr_un sa;
|
|
int sa_len = 0;
|
|
int rv;
|
|
|
|
if (unixSocketAddressToSockaddr(env, path, &sa, &sa_len) != 0) {
|
|
return IOS_THROWN;
|
|
}
|
|
|
|
rv = connect(fdval(env, fdo), (struct sockaddr *)&sa, sa_len);
|
|
if (rv != 0) {
|
|
if (errno == EINPROGRESS) {
|
|
return IOS_UNAVAILABLE;
|
|
} else if (errno == EINTR) {
|
|
return IOS_INTERRUPTED;
|
|
}
|
|
return handleSocketError(env, errno);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
JNIEXPORT jint JNICALL
|
|
Java_sun_nio_ch_UnixDomainSockets_accept0(JNIEnv *env, jclass clazz, jobject fdo, jobject newfdo,
|
|
jobjectArray array)
|
|
{
|
|
jint fd = fdval(env, fdo);
|
|
jint newfd;
|
|
struct sockaddr_un sa;
|
|
socklen_t sa_len = sizeof(struct sockaddr_un);
|
|
jbyteArray address;
|
|
|
|
newfd = accept(fd, (struct sockaddr *)&sa, &sa_len);
|
|
if (newfd < 0) {
|
|
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
|
return IOS_UNAVAILABLE;
|
|
if (errno == EINTR)
|
|
return IOS_INTERRUPTED;
|
|
JNU_ThrowIOExceptionWithLastError(env, "Accept failed");
|
|
return IOS_THROWN;
|
|
}
|
|
|
|
setfdval(env, newfdo, newfd);
|
|
|
|
address = sockaddrToUnixAddressBytes(env, &sa, sa_len);
|
|
CHECK_NULL_RETURN(address, IOS_THROWN);
|
|
|
|
(*env)->SetObjectArrayElement(env, array, 0, address);
|
|
|
|
return 1;
|
|
}
|
|
|
|
JNIEXPORT jbyteArray JNICALL
|
|
Java_sun_nio_ch_UnixDomainSockets_localAddress0(JNIEnv *env, jclass clazz, jobject fdo)
|
|
{
|
|
struct sockaddr_un sa;
|
|
socklen_t sa_len = sizeof(struct sockaddr_un);
|
|
int port;
|
|
if (getsockname(fdval(env, fdo), (struct sockaddr *)&sa, &sa_len) < 0) {
|
|
handleSocketError(env, errno);
|
|
return NULL;
|
|
}
|
|
return sockaddrToUnixAddressBytes(env, &sa, sa_len);
|
|
}
|
|
|