Skip to content

Commit

Permalink
AFUNIXSocketAddress: Allow converting from UnixDomainSocketAddress
Browse files Browse the repository at this point in the history
Add interoperability with Java 16+ UnixDomainSocketAddress.

Add AFUNIXSocketAddress.of(Socketaddress)/improve .unwrap to convert
UnixDomainSocketAddress on supported platforms.

Change Maven scripts to include multi-release code for Java 8-15
backwards compatibility.

Add missing check for AFUNIXSocketAddress.of(Path) to only allow Paths
in the default file system (similar to what UnixDomainSocketAddress
does).

Change minimum Java version for building junixsocket to Java 16.

Update documentation to reflect these changes.
  • Loading branch information
kohlschuetter committed Jul 14, 2023
1 parent caa5a93 commit d226bd3
Show file tree
Hide file tree
Showing 13 changed files with 577 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.function.Supplier;

import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
Expand All @@ -44,7 +45,7 @@
*
* @author Christian Kohlschütter
*/
@SuppressWarnings("PMD.CouplingBetweenObjects")
@SuppressWarnings({"PMD.CouplingBetweenObjects", "PMD.CyclomaticComplexity"})
public abstract class AFSocketAddress extends InetSocketAddress {
private static final long serialVersionUID = 1L;

Expand Down Expand Up @@ -484,16 +485,26 @@ protected static final <A extends AFSocketAddress> A unwrap(String hostname, int

static final int unwrapAddressDirectBufferInternal(ByteBuffer socketAddressBuffer,
SocketAddress address) throws SocketException {
if (!NativeUnixSocket.isLoaded()) {
throw new SocketException("Unsupported operation; junixsocket native library is not loaded");
}
Objects.requireNonNull(address);
// FIXME: add support for UnixDomainSocketAddress

if (!(address instanceof AFSocketAddress)) {
throw new SocketException("Unsupported address");
Supplier<? extends AFSocketAddress> supp = AFUNIXSocketAddress.supportedAddressSupplier(
address);
address = supp == null ? null : supp.get();
if (address == null) {
throw new SocketException("Unsupported address");
}
}

byte[] addr = ((AFSocketAddress) address).getBytes();
int domain = ((AFSocketAddress) address).getAddressFamily().getDomain();
int len = NativeUnixSocket.isLoaded() ? NativeUnixSocket.bytesToSockAddr(domain,
socketAddressBuffer, addr) : -1;
AFSocketAddress socketAddress = (AFSocketAddress) address;

byte[] addr = socketAddress.getBytes();
int domain = socketAddress.getAddressFamily().getDomain();

int len = NativeUnixSocket.bytesToSockAddr(domain, socketAddressBuffer, addr);
if (len == -1) {
throw new SocketException("Unsupported domain");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import java.util.Locale;
import java.util.Objects;
import java.util.Set;
import java.util.function.Supplier;

import org.eclipse.jdt.annotation.NonNull;

Expand Down Expand Up @@ -180,7 +181,7 @@ public static AFUNIXSocketAddress of(final byte[] socketAddress, int port)
* @return A corresponding {@link AFUNIXSocketAddress} instance.
* @throws SocketException if the operation fails.
*/
public static AFUNIXSocketAddress of(final Path socketPath) throws SocketException {
public static AFUNIXSocketAddress of(Path socketPath) throws SocketException {
return of(socketPath, 0);
}

Expand All @@ -193,7 +194,11 @@ public static AFUNIXSocketAddress of(final Path socketPath) throws SocketExcepti
* @return A corresponding {@link AFUNIXSocketAddress} instance.
* @throws SocketException if the operation fails.
*/
public static AFUNIXSocketAddress of(final Path socketPath, int port) throws SocketException {
public static AFUNIXSocketAddress of(Path socketPath, int port) throws SocketException {
if (!PathUtil.isPathInDefaultFileSystem(socketPath)) {
throw new SocketException("Path is not in the default file system");
}

return of(socketPath.toString().getBytes(ADDRESS_CHARSET), port);
}

Expand Down Expand Up @@ -262,6 +267,24 @@ public static AFUNIXSocketAddress ofNewTempPath(int port) throws IOException {
return of(newTempPath(true), port);
}

/**
* Returns an {@link AFUNIXSocketAddress} based on the given {@link SocketAddress}.
*
* This either simply casts an existing {@link AFUNIXSocketAddress}, or converts a
* {@code UnixDomainSocketAddress} to it.
*
* @param address The address to convert.
* @return A corresponding {@link AFUNIXSocketAddress} instance.
* @throws SocketException if the operation fails.
*/
public static AFUNIXSocketAddress of(SocketAddress address) throws IOException {
AFUNIXSocketAddress addr = unwrap(Objects.requireNonNull(address));
if (addr == null) {
throw new SocketException("Could not convert SocketAddress to AFUNIXSocketAddress");
}
return addr;
}

static File newTempPath(boolean deleteOnExit) throws IOException {
File f = File.createTempFile("jux", ".sock");
if (deleteOnExit) {
Expand Down Expand Up @@ -298,10 +321,11 @@ public static AFUNIXSocketAddress unwrap(InetAddress address, int port) throws S
public static AFUNIXSocketAddress unwrap(SocketAddress address) throws SocketException {
// FIXME: add support for UnixDomainSocketAddress
Objects.requireNonNull(address);
if (!isSupportedAddress(address)) {
Supplier<AFUNIXSocketAddress> supplier = supportedAddressSupplier(address);
if (supplier == null) {
throw new SocketException("Unsupported address");
}
return (AFUNIXSocketAddress) address;
return supplier.get();
}

/**
Expand Down Expand Up @@ -482,7 +506,24 @@ public static boolean isSupportedAddress(InetAddress addr) {
* @see #unwrap(InetAddress, int)
*/
public static boolean isSupportedAddress(SocketAddress addr) {
return (addr instanceof AFUNIXSocketAddress);
return supportedAddressSupplier(addr) != null;
}

/**
* Checks if the given address can be unwrapped to an {@link AFUNIXSocketAddress}, and if so,
* returns a supplier function; if not, {@code null} is returned.
*
* @param addr The address.
* @return The supplier, or {@code null}.
*/
static Supplier<AFUNIXSocketAddress> supportedAddressSupplier(SocketAddress addr) {
if (addr == null) {
return null;
} else if (addr instanceof AFUNIXSocketAddress) {
return () -> ((AFUNIXSocketAddress) addr);
} else {
return SocketAddressUtil.supplyAFUNIXSocketAddress(addr);
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* junixsocket
*
* Copyright 2009-2023 Christian Kohlschütter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.newsclub.net.unix;

import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Path;

/**
* Some {@link Path}-related helper methods.
*
* @author Christian Kohlschütter
*/
final class PathUtil {
private PathUtil() {
throw new IllegalStateException("No instances");
}

/**
* Checks if the given path is in the default file system.
*
* @param p The path.
* @return {@code true} if so.
*/
@SuppressWarnings("PMD.CompareObjectsWithEquals")
static boolean isPathInDefaultFileSystem(Path p) {
FileSystem fs = p.getFileSystem();
if (fs != FileSystems.getDefault() || fs.getClass().getModule() != Object.class.getModule()) {
return false;
}
return true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* junixsocket
*
* Copyright 2009-2023 Christian Kohlschütter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.newsclub.net.unix;

import java.net.SocketAddress;
import java.net.SocketException;
import java.net.UnixDomainSocketAddress;
import java.util.function.Supplier;

/**
* {@link SocketAddress}-related helper methods.
*
* @author Christian Kohlschütter
*/
final class SocketAddressUtil {
private SocketAddressUtil() {
throw new IllegalStateException("No instances");
}

/**
* Try to convert a {@link SocketAddress} that is not a {@link AFSocketAddress} to one that is.
*
* @param address The address.
* @return A supplier for the given address, or {@code null}.
*/
static Supplier<AFUNIXSocketAddress> supplyAFUNIXSocketAddress(SocketAddress address) {
if (address instanceof UnixDomainSocketAddress) {
UnixDomainSocketAddress udsa = (UnixDomainSocketAddress) address;

return () -> {
try {
return AFUNIXSocketAddress.of(udsa.getPath());
} catch (SocketException e) {
return null;
}
};
} else {
return null;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* junixsocket
*
* Copyright 2009-2023 Christian Kohlschütter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.newsclub.net.unix;

import java.net.SocketAddress;
import java.net.SocketException;
import java.util.function.Supplier;

/**
* {@link SocketAddress}-related helper methods.
*
* @author Christian Kohlschütter
*/
final class SocketAddressUtil {
private SocketAddressUtil() {
throw new IllegalStateException("No instances");
}

/**
* Try to convert a {@link SocketAddress} that is not a {@link AFSocketAddress} to one that is.
*
* @param address The address.
* @return A supplier for the given address, or {@code null}.
*/
static Supplier<AFUNIXSocketAddress> supplyAFUNIXSocketAddress(SocketAddress address) {
return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* junixsocket
*
* Copyright 2009-2023 Christian Kohlschütter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.newsclub.net.unix;

import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Path;

/**
* Some {@link Path}-related helper methods.
*
* @author Christian Kohlschütter
*/
final class PathUtil {
private PathUtil() {
throw new IllegalStateException("No instances");
}

/**
* Checks if the given path is in the default file system.
*
* @param p The path.
* @return {@code true} if so.
*/
@SuppressWarnings("PMD.CompareObjectsWithEquals")
static boolean isPathInDefaultFileSystem(Path p) {
FileSystem fs = p.getFileSystem();
if (fs != FileSystems.getDefault()) {
return false;
}
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,9 @@ public SelftestProvider() {

registerTest(org.newsclub.net.unix.domain.ThroughputTest.class);
registerTestJavaInet(org.newsclub.net.unix.java.ThroughputTest.class);
}

registerTest(org.newsclub.net.unix.domain.UnixDomainSocketAddressTest.class);
}

public Set<String> modulesDisabledByDefault() {
return Collections.singleton("junixsocket-common.JavaInet");
Expand Down
Loading

0 comments on commit d226bd3

Please sign in to comment.