1 /*
2 * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 #include <poll.h>
27 #include <sys/types.h>
28 #include <sys/socket.h>
29 #include <string.h>
30 #include <stddef.h>
31 #include <netinet/in.h>
32 #include <netinet/tcp.h>
33 #include <limits.h>
34
35 #include "io_util.h"
36 #include "jni.h"
37 #include "jni_util.h"
38 #include "jvm.h"
39 #include "jlong.h"
40 #include "sun_nio_ch_Net.h"
41 #include "nio_util.h"
42 #include "nio.h"
43
44 /* Subtle platform differences in how unnamed sockets (empty path)
45 * are returned from getsockname()
46 */
47 #ifdef MACOSX
48 #define ZERO_PATHLEN(len) (JNI_FALSE)
49 #else
50 #define ZERO_PATHLEN(len) (len == offsetof(struct sockaddr_un, sun_path))
51 #endif
52
sockaddrToUnixAddressBytes(JNIEnv * env,struct sockaddr_un * sa,socklen_t len)53 jbyteArray sockaddrToUnixAddressBytes(JNIEnv *env, struct sockaddr_un *sa, socklen_t len)
54 {
55 if (sa->sun_family == AF_UNIX) {
56 int namelen;
57 if (ZERO_PATHLEN(len)) {
58 namelen = 0;
59 } else {
60 namelen = strlen(sa->sun_path);
61 }
62 jbyteArray name = (*env)->NewByteArray(env, namelen);
63 if (namelen != 0) {
64 (*env)->SetByteArrayRegion(env, name, 0, namelen, (jbyte*)sa->sun_path);
65 if ((*env)->ExceptionOccurred(env)) {
66 return NULL;
67 }
68 }
69 return name;
70 }
71 return NULL;
72 }
73
unixSocketAddressToSockaddr(JNIEnv * env,jbyteArray path,struct sockaddr_un * sa,int * len)74 jint unixSocketAddressToSockaddr(JNIEnv *env, jbyteArray path, struct sockaddr_un *sa, int *len)
75 {
76 memset(sa, 0, sizeof(struct sockaddr_un));
77 sa->sun_family = AF_UNIX;
78 int ret;
79 const char* pname = (const char *)(*env)->GetByteArrayElements(env, path, NULL);
80 if (pname == NULL) {
81 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Unix domain path not present");
82 return -1;
83 }
84 size_t name_len = (*env)->GetArrayLength(env, path);
85 if (name_len > MAX_UNIX_DOMAIN_PATH_LEN) {
86 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Unix domain path too long");
87 ret = -1;
88 } else {
89 memcpy(sa->sun_path, pname, name_len);
90 *len = (int)(offsetof(struct sockaddr_un, sun_path) + name_len + 1);
91 ret = 0;
92 }
93 (*env)->ReleaseByteArrayElements(env, path, (jbyte *)pname, 0);
94 return ret;
95 }
96
97 JNIEXPORT jboolean JNICALL
Java_sun_nio_ch_UnixDomainSockets_init(JNIEnv * env,jclass cl)98 Java_sun_nio_ch_UnixDomainSockets_init(JNIEnv *env, jclass cl)
99 {
100 return JNI_TRUE;
101 }
102
103 JNIEXPORT jint JNICALL
Java_sun_nio_ch_UnixDomainSockets_socket0(JNIEnv * env,jclass cl)104 Java_sun_nio_ch_UnixDomainSockets_socket0(JNIEnv *env, jclass cl)
105 {
106 int fd = socket(PF_UNIX, SOCK_STREAM, 0);
107 if (fd < 0) {
108 return handleSocketError(env, errno);
109 }
110 return fd;
111 }
112
113 JNIEXPORT void JNICALL
Java_sun_nio_ch_UnixDomainSockets_bind0(JNIEnv * env,jclass clazz,jobject fdo,jbyteArray path)114 Java_sun_nio_ch_UnixDomainSockets_bind0(JNIEnv *env, jclass clazz, jobject fdo, jbyteArray path)
115 {
116 struct sockaddr_un sa;
117 int sa_len = 0;
118 int rv = 0;
119
120 if (unixSocketAddressToSockaddr(env, path, &sa, &sa_len) != 0)
121 return;
122
123 rv = bind(fdval(env, fdo), (struct sockaddr *)&sa, sa_len);
124 if (rv != 0) {
125 handleSocketError(env, errno);
126 }
127 }
128
129 JNIEXPORT jint JNICALL
Java_sun_nio_ch_UnixDomainSockets_connect0(JNIEnv * env,jclass clazz,jobject fdo,jbyteArray path)130 Java_sun_nio_ch_UnixDomainSockets_connect0(JNIEnv *env, jclass clazz, jobject fdo, jbyteArray path)
131 {
132 struct sockaddr_un sa;
133 int sa_len = 0;
134 int rv;
135
136 if (unixSocketAddressToSockaddr(env, path, &sa, &sa_len) != 0) {
137 return IOS_THROWN;
138 }
139
140 rv = connect(fdval(env, fdo), (struct sockaddr *)&sa, sa_len);
141 if (rv != 0) {
142 if (errno == EINPROGRESS) {
143 return IOS_UNAVAILABLE;
144 } else if (errno == EINTR) {
145 return IOS_INTERRUPTED;
146 }
147 return handleSocketError(env, errno);
148 }
149 return 1;
150 }
151
152 JNIEXPORT jint JNICALL
Java_sun_nio_ch_UnixDomainSockets_accept0(JNIEnv * env,jclass clazz,jobject fdo,jobject newfdo,jobjectArray array)153 Java_sun_nio_ch_UnixDomainSockets_accept0(JNIEnv *env, jclass clazz, jobject fdo, jobject newfdo,
154 jobjectArray array)
155 {
156 jint fd = fdval(env, fdo);
157 jint newfd;
158 struct sockaddr_un sa;
159 socklen_t sa_len = sizeof(struct sockaddr_un);
160 jbyteArray address;
161
162 newfd = accept(fd, (struct sockaddr *)&sa, &sa_len);
163 if (newfd < 0) {
164 if (errno == EAGAIN || errno == EWOULDBLOCK)
165 return IOS_UNAVAILABLE;
166 if (errno == EINTR)
167 return IOS_INTERRUPTED;
168 JNU_ThrowIOExceptionWithLastError(env, "Accept failed");
169 return IOS_THROWN;
170 }
171
172 setfdval(env, newfdo, newfd);
173
174 address = sockaddrToUnixAddressBytes(env, &sa, sa_len);
175 CHECK_NULL_RETURN(address, IOS_THROWN);
176
177 (*env)->SetObjectArrayElement(env, array, 0, address);
178
179 return 1;
180 }
181
182 JNIEXPORT jbyteArray JNICALL
Java_sun_nio_ch_UnixDomainSockets_localAddress0(JNIEnv * env,jclass clazz,jobject fdo)183 Java_sun_nio_ch_UnixDomainSockets_localAddress0(JNIEnv *env, jclass clazz, jobject fdo)
184 {
185 struct sockaddr_un sa;
186 socklen_t sa_len = sizeof(struct sockaddr_un);
187 int port;
188 if (getsockname(fdval(env, fdo), (struct sockaddr *)&sa, &sa_len) < 0) {
189 handleSocketError(env, errno);
190 return NULL;
191 }
192 return sockaddrToUnixAddressBytes(env, &sa, sa_len);
193 }
194