Skip to content

Commit e6ca988

Browse files
yawkatnormanmaurer
authored andcommitted
Add support for abstract domain sockets
Motivation: Because of java custom UTF encoding, it was previously impossible to use nul-bytes in domain socket names, which is required for abstract domain sockets. Modifications: - Pass the encoded string byte array to the native code - Modify native code accordingly to work with nul-bytes in the the array. - Move the string encoding to UTF-8 in java code. Result: Unix domain socket addresses will work properly if they contain nul- bytes. Address encoding for these addresses changes from UTF-8-like to real UTF-8.
1 parent ea18f73 commit e6ca988

3 files changed

Lines changed: 57 additions & 15 deletions

File tree

transport-native-epoll/src/main/c/io_netty_channel_epoll_Native.c

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1482,44 +1482,57 @@ JNIEXPORT jint JNICALL Java_io_netty_channel_epoll_Native_socketDomain(JNIEnv* e
14821482
return fd;
14831483
}
14841484

1485-
JNIEXPORT jint JNICALL Java_io_netty_channel_epoll_Native_bindDomainSocket(JNIEnv* env, jclass clazz, jint fd, jstring socketPath) {
1485+
// macro to calculate the length of a sockaddr_un struct for a given path length.
1486+
// see sys/un.h#SUN_LEN, this is modified to allow nul bytes
1487+
#define _UNIX_ADDR_LENGTH(path_len) (((struct sockaddr_un *) 0)->sun_path) + path_len
1488+
1489+
JNIEXPORT jint JNICALL Java_io_netty_channel_epoll_Native_bindDomainSocket(JNIEnv* env, jclass clazz, jint fd, jbyteArray socketPath) {
14861490
struct sockaddr_un addr;
14871491

14881492
memset(&addr, 0, sizeof(addr));
14891493
addr.sun_family = AF_UNIX;
14901494

1491-
const char* socket_path = (*env)->GetStringUTFChars(env, socketPath, 0);
1492-
memcpy(addr.sun_path, socket_path, strlen(socket_path));
1495+
const jbyte* socket_path = (*env)->GetByteArrayElements(env, socketPath, 0);
1496+
jint socket_path_len = (*env)->GetArrayLength(env, socketPath);
1497+
if (socket_path_len > sizeof(addr.sun_path)) {
1498+
socket_path_len = sizeof(addr.sun_path);
1499+
}
1500+
memcpy(addr.sun_path, socket_path, socket_path_len);
14931501

14941502
if (unlink(socket_path) == -1 && errno != ENOENT) {
14951503
return -errno;
14961504
}
14971505

1498-
int res = bind(fd, (struct sockaddr*) &addr, sizeof(addr));
1499-
(*env)->ReleaseStringUTFChars(env, socketPath, socket_path);
1506+
int res = bind(fd, (struct sockaddr*) &addr, _UNIX_ADDR_LENGTH(socket_path_len));
1507+
(*env)->ReleaseByteArrayElements(env, socketPath, socket_path, 0);
15001508

15011509
if (res == -1) {
15021510
return -errno;
15031511
}
15041512
return res;
15051513
}
15061514

1507-
JNIEXPORT jint JNICALL Java_io_netty_channel_epoll_Native_connectDomainSocket(JNIEnv* env, jclass clazz, jint fd, jstring socketPath) {
1515+
JNIEXPORT jint JNICALL Java_io_netty_channel_epoll_Native_connectDomainSocket(JNIEnv* env, jclass clazz, jint fd, jbyteArray socketPath) {
15081516
struct sockaddr_un addr;
1517+
jint socket_path_len;
15091518

15101519
memset(&addr, 0, sizeof(addr));
15111520
addr.sun_family = AF_UNIX;
15121521

1513-
const char* socket_path = (*env)->GetStringUTFChars(env, socketPath, 0);
1514-
strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path) - 1);
1522+
const jbyte* socket_path = (*env)->GetByteArrayElements(env, socketPath, 0);
1523+
socket_path_len = (*env)->GetArrayLength(env, socketPath);
1524+
if (socket_path_len > sizeof(addr.sun_path)) {
1525+
socket_path_len = sizeof(addr.sun_path);
1526+
}
1527+
memcpy(addr.sun_path, socket_path, socket_path_len);
15151528

15161529
int res;
15171530
int err;
15181531
do {
1519-
res = connect(fd, (struct sockaddr*) &addr, sizeof(addr));
1532+
res = connect(fd, (struct sockaddr*) &addr, _UNIX_ADDR_LENGTH(socket_path_len));
15201533
} while (res == -1 && ((err = errno) == EINTR));
15211534

1522-
(*env)->ReleaseStringUTFChars(env, socketPath, socket_path);
1535+
(*env)->ReleaseByteArrayElements(env, socketPath, socket_path, 0);
15231536

15241537
if (res < 0) {
15251538
return -err;
@@ -1688,4 +1701,4 @@ JNIEXPORT jint JNICALL Java_io_netty_channel_epoll_Native_splice0(JNIEnv* env, j
16881701

16891702
JNIEXPORT jlong JNICALL Java_io_netty_channel_epoll_Native_ssizeMax(JNIEnv* env, jclass clazz) {
16901703
return SSIZE_MAX;
1691-
}
1704+
}

transport-native-epoll/src/main/java/io/netty/channel/epoll/Native.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import io.netty.channel.ChannelException;
2020
import io.netty.channel.DefaultFileRegion;
2121
import io.netty.channel.unix.DomainSocketAddress;
22+
import io.netty.util.CharsetUtil;
2223
import io.netty.util.internal.EmptyArrays;
2324
import io.netty.util.internal.NativeLibraryLoader;
2425
import io.netty.util.internal.PlatformDependent;
@@ -435,7 +436,7 @@ public static void bind(int fd, SocketAddress socketAddress) throws IOException
435436
}
436437
} else if (socketAddress instanceof DomainSocketAddress) {
437438
DomainSocketAddress addr = (DomainSocketAddress) socketAddress;
438-
int res = bindDomainSocket(fd, addr.path());
439+
int res = bindDomainSocket(fd, addr.path().getBytes(CharsetUtil.UTF_8));
439440
if (res < 0) {
440441
throw newIOException("bind", res);
441442
}
@@ -445,7 +446,7 @@ public static void bind(int fd, SocketAddress socketAddress) throws IOException
445446
}
446447

447448
private static native int bind(int fd, byte[] address, int scopeId, int port);
448-
private static native int bindDomainSocket(int fd, String path);
449+
private static native int bindDomainSocket(int fd, byte[] path);
449450

450451
public static void listen(int fd, int backlog) throws IOException {
451452
int res = listen0(fd, backlog);
@@ -464,7 +465,7 @@ public static boolean connect(int fd, SocketAddress socketAddress) throws IOExce
464465
res = connect(fd, address.address, address.scopeId, inetSocketAddress.getPort());
465466
} else if (socketAddress instanceof DomainSocketAddress) {
466467
DomainSocketAddress unixDomainSocketAddress = (DomainSocketAddress) socketAddress;
467-
res = connectDomainSocket(fd, unixDomainSocketAddress.path());
468+
res = connectDomainSocket(fd, unixDomainSocketAddress.path().getBytes(CharsetUtil.UTF_8));
468469
} else {
469470
throw new Error("Unexpected SocketAddress implementation " + socketAddress);
470471
}
@@ -479,7 +480,7 @@ public static boolean connect(int fd, SocketAddress socketAddress) throws IOExce
479480
}
480481

481482
private static native int connect(int fd, byte[] address, int scopeId, int port);
482-
private static native int connectDomainSocket(int fd, String path);
483+
private static native int connectDomainSocket(int fd, byte[] path);
483484

484485
public static boolean finishConnect(int fd) throws IOException {
485486
int res = finishConnect0(fd);
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Copyright 2015 The Netty Project
3+
*
4+
* The Netty Project licenses this file to you under the Apache License,
5+
* version 2.0 (the "License"); you may not use this file except in compliance
6+
* with the License. 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, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations
14+
* under the License.
15+
*/
16+
package io.netty.channel.epoll;
17+
18+
import io.netty.channel.unix.DomainSocketAddress;
19+
import java.net.SocketAddress;
20+
import java.util.UUID;
21+
22+
public class EpollAbstractDomainSocketEchoTest extends EpollDomainSocketEchoTest {
23+
@Override
24+
protected SocketAddress newSocketAddress() {
25+
// these don't actually show up in the file system so creating a temp file isn't reliable
26+
return new DomainSocketAddress("\0/tmp/" + UUID.randomUUID());
27+
}
28+
}

0 commit comments

Comments
 (0)