make datagram unix sockets work for sd_notify

This commit is contained in:
Jörg Prante 2024-04-04 19:11:50 +02:00
parent 96f47650b5
commit 75d5f6b2e6
23 changed files with 448 additions and 466 deletions

View file

@ -1,3 +1,3 @@
group = org.xbib group = org.xbib
name = net name = net
version = 4.3.0 version = 4.3.1

View file

@ -19,6 +19,7 @@ test {
'--add-opens=java.base/java.nio=ALL-UNNAMED', '--add-opens=java.base/java.nio=ALL-UNNAMED',
'--add-opens=java.base/java.util=ALL-UNNAMED' '--add-opens=java.base/java.util=ALL-UNNAMED'
systemProperty 'java.util.logging.config.file', 'src/test/resources/logging.properties' systemProperty 'java.util.logging.config.file', 'src/test/resources/logging.properties'
environment 'NOTIFY_SOCKET', '/run/systemd/notify'
testLogging { testLogging {
events 'STARTED', 'PASSED', 'FAILED', 'SKIPPED' events 'STARTED', 'PASSED', 'FAILED', 'SKIPPED'
} }

View file

@ -11,4 +11,5 @@ module org.xbib.net.security.test {
exports org.xbib.net.security.test.eddsa.math.bigint; exports org.xbib.net.security.test.eddsa.math.bigint;
exports org.xbib.net.security.test.eddsa.math.ed25519; exports org.xbib.net.security.test.eddsa.math.ed25519;
exports org.xbib.net.security.test.eddsa.spec; exports org.xbib.net.security.test.eddsa.spec;
uses org.xbib.net.security.CertificateProvider;
} }

View file

@ -4,14 +4,12 @@ module org.xbib.net.socket {
exports org.xbib.net.socket; exports org.xbib.net.socket;
exports org.xbib.net.socket.notify; exports org.xbib.net.socket.notify;
exports org.xbib.net.socket.v4; exports org.xbib.net.socket.v4;
exports org.xbib.net.socket.v4.bsd;
exports org.xbib.net.socket.v4.datagram; exports org.xbib.net.socket.v4.datagram;
exports org.xbib.net.socket.v4.icmp; exports org.xbib.net.socket.v4.icmp;
exports org.xbib.net.socket.v4.ip; exports org.xbib.net.socket.v4.ip;
exports org.xbib.net.socket.v4.ping; exports org.xbib.net.socket.v4.ping;
exports org.xbib.net.socket.v4.unix; exports org.xbib.net.socket.v4.unix;
exports org.xbib.net.socket.v6; exports org.xbib.net.socket.v6;
exports org.xbib.net.socket.v6.bsd;
exports org.xbib.net.socket.v6.datagram; exports org.xbib.net.socket.v6.datagram;
exports org.xbib.net.socket.v6.icmp; exports org.xbib.net.socket.v6.icmp;
exports org.xbib.net.socket.v6.ping; exports org.xbib.net.socket.v6.ping;

View file

@ -1,16 +1,15 @@
package org.xbib.net.socket.notify; package org.xbib.net.socket.notify;
import java.io.IOException; import java.io.IOException;
import java.net.StandardProtocolFamily;
import java.net.UnixDomainSocketAddress;
import java.nio.CharBuffer;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Path; import java.util.logging.Level;
import java.nio.file.Paths; import java.util.logging.Logger;
import org.xbib.net.socket.v4.unix.UnixDatagramSocket;
public class SystemdNotify { public class SystemdNotify {
private static final Logger logger = Logger.getLogger(SystemdNotify.class.getName());
public SystemdNotify() { public SystemdNotify() {
} }
@ -21,12 +20,11 @@ public class SystemdNotify {
public static void sendNotify(String text) throws IOException { public static void sendNotify(String text) throws IOException {
String socketName = System.getenv("NOTIFY_SOCKET"); String socketName = System.getenv("NOTIFY_SOCKET");
if (socketName != null) { if (socketName != null) {
Path path = Paths.get(socketName); UnixDatagramSocket socket = new UnixDatagramSocket(socketName);
UnixDomainSocketAddress socketAddress = UnixDomainSocketAddress.of(path); socket.send(text.getBytes(StandardCharsets.US_ASCII), text.length());
try (SocketChannel channel = SocketChannel.open(StandardProtocolFamily.UNIX)) { socket.close();
channel.connect(socketAddress); } else {
channel.write(StandardCharsets.US_ASCII.encode(CharBuffer.wrap(text))); logger.log(Level.WARNING, "no socket path in NOTIFY_SOCKET environment variable");
}
} }
} }
} }

View file

@ -2,6 +2,8 @@ package org.xbib.net.socket.v4;
public interface Constants { public interface Constants {
int AF_UNIX = 1;
int AF_INET = 2; int AF_INET = 2;
int IPPROTO_IP = 0; int IPPROTO_IP = 0;

View file

@ -1,13 +1,12 @@
package org.xbib.net.socket.v4; package org.xbib.net.socket.v4;
import com.sun.jna.Platform;
import org.xbib.net.socket.v4.datagram.DatagramSocket; import org.xbib.net.socket.v4.datagram.DatagramSocket;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
public class SocketFactory { public class SocketFactory {
public static final int SOCK_DGRAM = Platform.isSolaris() ? 1 : 2; public static final int SOCK_DGRAM = 2;
private SocketFactory() { private SocketFactory() {
} }
@ -23,13 +22,6 @@ public class SocketFactory {
private static String getImplementationClassName() { private static String getImplementationClassName() {
return "org.xbib.net.socket.v4." + getArchName() + ".NativeDatagramSocket"; return "org.xbib.net.socket.v4.unix.NativeDatagramSocket";
}
private static String getArchName() {
return Platform.isWindows() ? "win32"
: Platform.isSolaris() ? "sun"
: (Platform.isMac() || Platform.isFreeBSD() || Platform.isOpenBSD()) ? "bsd"
: "unix";
} }
} }

View file

@ -1,117 +0,0 @@
package org.xbib.net.socket.v4.bsd;
import com.sun.jna.LastErrorException;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.IntByReference;
import org.xbib.net.socket.v4.datagram.DatagramPacket;
import org.xbib.net.socket.v4.datagram.DatagramSocket;
import java.io.IOException;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import static org.xbib.net.socket.v4.Constants.AF_INET;
import static org.xbib.net.socket.v4.Constants.IPPROTO_IP;
import static org.xbib.net.socket.v4.Constants.IP_MTU_DISCOVER;
public class NativeDatagramSocket implements DatagramSocket, AutoCloseable {
static {
Native.register((String) null);
}
private static final int IP_TOS = 3;
private final int socket;
private volatile boolean closed;
public NativeDatagramSocket(int type, int protocol, int port) {
this.socket = socket(AF_INET, type, protocol);
if (socket < 0) {
throw new IllegalStateException("socket < 0");
}
SocketStructure socketStructure = new SocketStructure(port);
bind(socket, socketStructure, socketStructure.size());
closed = false;
}
public native int bind(int socket, SocketStructure address, int address_len) throws LastErrorException;
public native int socket(int family, int type, int protocol) throws LastErrorException;
public native int setsockopt(int socket, int level, int option_name, Pointer value, int len);
public native int sendto(int socket, Buffer buffer, int buflen, int flags, SocketStructure address, int len) throws LastErrorException;
public native int recvfrom(int socket, Buffer buffer, int buflen, int flags, SocketStructure address, int[] len) throws LastErrorException;
public native int close(int socket) throws LastErrorException;
public native String strerror(int errnum);
@Override
public int setTrafficClass(int tc) throws IOException {
IntByReference ptr = new IntByReference(tc);
try {
return setsockopt(socket, IPPROTO_IP, IP_TOS, ptr.getPointer(), Native.POINTER_SIZE);
} catch (LastErrorException e) {
throw new IOException("setsockopt: " + strerror(e.getErrorCode()));
}
}
@Override
public int setFragmentation(boolean frag) throws IOException {
return allowFragmentation(IPPROTO_IP, IP_MTU_DISCOVER, frag);
}
private int allowFragmentation(int level, int option_name, boolean frag) throws IOException {
if (closed) {
return -1;
}
IntByReference dontfragment = new IntByReference(frag ? 0 : 1);
try {
return setsockopt(socket, level, option_name, dontfragment.getPointer(), Native.POINTER_SIZE);
} catch (LastErrorException e) {
throw new IOException("setsockopt: " + strerror(e.getErrorCode()));
}
}
@Override
public int receive(DatagramPacket datagramPacket) {
if (closed) {
return -1;
}
try {
SocketStructure socketStructure = new SocketStructure();
int[] szRef = new int[]{socketStructure.size()};
ByteBuffer buf = datagramPacket.getContent();
int n = recvfrom(socket, buf, buf.capacity(), 0, socketStructure, szRef);
datagramPacket.setLength(n);
datagramPacket.setAddressable(socketStructure);
return n;
} catch (LastErrorException e) {
if (e.getMessage().contains("[9]")) {
// bad file descriptor
return -1;
}
throw e;
}
}
@Override
public int send(DatagramPacket datagramPacket) {
if (closed) {
return -1;
}
ByteBuffer buf = datagramPacket.getContent();
SocketStructure socketStructure = new SocketStructure(datagramPacket.getAddress(), datagramPacket.getPort());
return sendto(socket, buf, buf.remaining(), 0, socketStructure, socketStructure.size());
}
@Override
public void close() {
closed = true;
close(socket);
}
}

View file

@ -1,89 +0,0 @@
package org.xbib.net.socket.v4.bsd;
import static org.xbib.net.socket.v4.Constants.AF_INET;
import com.sun.jna.Structure;
import org.xbib.net.socket.v4.Addressable;
import java.net.Inet4Address;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.List;
public class SocketStructure extends Structure implements Addressable {
public byte sin_len;
public byte sin_family;
public byte[] sin_port;
public byte[] sin_addr;
public byte[] sin_zero;
public SocketStructure() {
this(0);
}
public SocketStructure(int port) {
this(null, port);
}
public SocketStructure(Inet4Address address, int port) {
this(AF_INET, address, port);
}
public SocketStructure(int family, Inet4Address address, int port) {
this.sin_family = (byte) (0xff & family);
this.sin_zero = new byte[8];
this.sin_len = (byte) (0xff & 16);
setAddress(address);
setPort(port);
}
@Override
protected List<String> getFieldOrder() {
return Arrays.asList("sin_len", "sin_family", "sin_port", "sin_addr", "sin_zero");
}
@Override
public Inet4Address getAddress() {
try {
return (Inet4Address) Inet4Address.getByAddress(sin_addr);
} catch (UnknownHostException e) {
return null;
}
}
public void setAddress(Inet4Address address) {
if (address != null) {
byte[] addr = address.getAddress();
assertLen("address", addr, 4);
sin_addr = addr;
} else {
sin_addr = new byte[] { 0, 0, 0, 0 };
}
}
@Override
public int getPort() {
int port = 0;
for (int i = 0; i < 2; i++) {
port = ((port << 8) | (sin_port[i] & 0xff));
}
return port;
}
public void setPort(int port) {
if (port >= 0) {
byte[] p = new byte[]{(byte) (0xff & (port >> 8)), (byte) (0xff & port)};
assertLen("port", p, 2);
sin_port = p;
}
}
private void assertLen(String field, byte[] addr, int len) {
if (addr.length != len) {
throw new IllegalArgumentException(field + " length must be " + len + " bytes");
}
}
}

View file

@ -41,12 +41,8 @@ public class DatagramPacket implements Addressable {
}; };
} }
public Addressable getAddressable() {
return addressable;
}
public Inet4Address getAddress() { public Inet4Address getAddress() {
return addressable != null ?addressable.getAddress() : null; return addressable != null ? addressable.getAddress() : null;
} }
public int getPort() { public int getPort() {

View file

@ -0,0 +1,97 @@
package org.xbib.net.socket.v4.unix;
import com.sun.jna.LastErrorException;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import com.sun.jna.ptr.IntByReference;
import java.nio.Buffer;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
public class CLibrary {
private static final Logger logger = Logger.getLogger(CLibrary.class.getName());
public static final int AF_UNIX = 1;
public static final int AF_INET = 2;
public static final int SOCK_STREAM = 1;
public static final int SOCK_DGRAM = 2;
public static final int PROTOCOL = 0;
public static final CLibrary clib = new CLibrary();
native public int fcntl(int fd, int cmd, int arg) throws LastErrorException;
native public int ioctl(int fd, int cmd, byte[] arg) throws LastErrorException;
native public int ioctl(int fd, int cmd, Pointer p) throws LastErrorException;
native public int open(String path, int flags) throws LastErrorException;
native public int close(int fd) throws LastErrorException;
native public int write(int fd, Buffer buffer, int count) throws LastErrorException;
native public int read(int fd, Buffer buffer, int count) throws LastErrorException;
native public int socket(int domain, int type, int protocol) throws LastErrorException;
native public int connect(int sockfd, SockAddrUn sockaddr, int addrlen) throws LastErrorException;
native public int bind(int sockfd, SockAddrUn sockaddr, int addrlen) throws LastErrorException;
native public int accept(int sockfd, SockAddrUn rem_addr, Pointer opt) throws LastErrorException;
native public int listen(int sockfd, int channel) throws LastErrorException;
native public int getsockopt(int s, int level, int optname, byte[] optval, IntByReference optlen);
native public int setsockopt(int s, int level, int optname, byte[] optval, int optlen);
native public int recv(int s, Buffer buf, int len, int flags) throws LastErrorException;
native public int recvfrom(int s, Buffer buf, int len, int flags, SockAddrUn from, IntByReference fromlen);
native public int send(int s, Buffer msg, int len, int flags) throws LastErrorException;
native public int getpid() throws LastErrorException;
static {
try {
Native.register("c");
} catch (Exception e) {
logger.log(Level.WARNING, "Native.register(\"c\") failed", e);
}
}
private CLibrary() {
}
public static CLibrary getInstance() {
return clib;
}
public static class SockAddrUn extends Structure implements Structure.ByReference {
public short family = AF_UNIX;
public byte[] addr = new byte[108];
public SockAddrUn(String path) {
System.arraycopy(path.getBytes(StandardCharsets.US_ASCII), 0, addr, 0, Math.min(108, path.length()));
}
@Override
protected List<String> getFieldOrder() {
return List.of("family", "addr");
}
}
}

View file

@ -37,8 +37,8 @@ public class NativeDatagramSocket implements DatagramSocket, AutoCloseable {
if (socket < 0) { if (socket < 0) {
throw new IllegalStateException("socket < 0"); throw new IllegalStateException("socket < 0");
} }
SocketStructure socketStructure = new SocketStructure(port); SocketAddressInternet socketAddressInternet = new SocketAddressInternet(port);
bind(socket, socketStructure, socketStructure.size()); bind(socket, socketAddressInternet, socketAddressInternet.size());
closed = false; closed = false;
} catch (LastErrorException e) { } catch (LastErrorException e) {
logger.log(Level.SEVERE, e.getMessage() + ": check if sysctl -w net.ipv4.ping_group_range=\"0 65535\" and check for selinux security:\n" + logger.log(Level.SEVERE, e.getMessage() + ": check if sysctl -w net.ipv4.ping_group_range=\"0 65535\" and check for selinux security:\n" +
@ -48,15 +48,15 @@ public class NativeDatagramSocket implements DatagramSocket, AutoCloseable {
} }
} }
public native int bind(int socket, SocketStructure address, int address_len) throws LastErrorException; public native int bind(int socket, SocketAddressInternet address, int address_len) throws LastErrorException;
public native int socket(int domain, int type, int protocol) throws LastErrorException; public native int socket(int domain, int type, int protocol) throws LastErrorException;
public native int setsockopt(int socket, int level, int option_name, Pointer value, int option_len); public native int setsockopt(int socket, int level, int option_name, Pointer value, int option_len);
public native int sendto(int socket, Buffer buffer, int buflen, int flags, SocketStructure dest_addr, int dest_addr_len) throws LastErrorException; public native int sendto(int socket, Buffer buffer, int buflen, int flags, SocketAddressInternet dest_addr, int dest_addr_len) throws LastErrorException;
public native int recvfrom(int socket, Buffer buffer, int buflen, int flags, SocketStructure in_addr, int[] in_addr_len) throws LastErrorException; public native int recvfrom(int socket, Buffer buffer, int buflen, int flags, SocketAddressInternet in_addr, int[] in_addr_len) throws LastErrorException;
public native int close(int socket) throws LastErrorException; public native int close(int socket) throws LastErrorException;
@ -97,7 +97,7 @@ public class NativeDatagramSocket implements DatagramSocket, AutoCloseable {
if (closed) { if (closed) {
return -1; return -1;
} }
SocketStructure in_addr = new SocketStructure(); SocketAddressInternet in_addr = new SocketAddressInternet();
int[] szRef = new int[]{in_addr.size()}; int[] szRef = new int[]{in_addr.size()};
ByteBuffer buf = datagramPacket.getContent(); ByteBuffer buf = datagramPacket.getContent();
int n = recvfrom(socket, buf, buf.capacity(), 0, in_addr, szRef); int n = recvfrom(socket, buf, buf.capacity(), 0, in_addr, szRef);
@ -111,7 +111,7 @@ public class NativeDatagramSocket implements DatagramSocket, AutoCloseable {
if (closed) { if (closed) {
return -1; return -1;
} }
SocketStructure destAddr = new SocketStructure(datagramPacket.getAddress(), datagramPacket.getPort()); SocketAddressInternet destAddr = new SocketAddressInternet(datagramPacket.getAddress(), datagramPacket.getPort());
ByteBuffer buf = datagramPacket.getContent(); ByteBuffer buf = datagramPacket.getContent();
try { try {
return sendto(socket, buf, buf.remaining(), 0, destAddr, destAddr.size()); return sendto(socket, buf, buf.remaining(), 0, destAddr, destAddr.size());

View file

@ -0,0 +1,62 @@
package org.xbib.net.socket.v4.unix;
import com.sun.jna.LastErrorException;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import java.io.IOException;
import java.net.Socket;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.xbib.net.socket.NetworkUnreachableException;
import org.xbib.net.socket.v4.datagram.DatagramPacket;
import static org.xbib.net.socket.v4.Constants.AF_UNIX;
public class NativeUnixSocket extends Socket {
static {
Native.register((String) null);
}
private static final Logger logger = Logger.getLogger(NativeUnixSocket.class.getName());
private final int socket;
private volatile boolean closed;
public NativeUnixSocket(String path, int type, int protocol) {
try {
this.socket = socket(AF_UNIX, type, protocol);
if (socket < 0) {
throw new IllegalStateException("socket < 0");
}
SocketAddressUnix socketAddressUnix = new SocketAddressUnix(path);
connect(socket, socketAddressUnix);
closed = false;
} catch (LastErrorException e) {
logger.log(Level.SEVERE, e.getMessage(), e);
throw e;
}
}
public native int connect(int socket, SocketAddressUnix socketAddressUnix) throws LastErrorException;
public native int socket(int domain, int type, int protocol) throws LastErrorException;
public native int setsockopt(int socket, int level, int option_name, Pointer value, int option_len);
public native int sendto(int socket, Buffer buffer, int buflen, int flags, SocketAddressUnix socketAddressUnix) throws LastErrorException;
public native int recvfrom(int socket, Buffer buffer, int buflen, int flags, SocketAddressInternet in_addr, int[] in_addr_len) throws LastErrorException;
public native int close(int socket) throws LastErrorException;
public native String strerror(int errnum);
@Override
public void close() throws IOException {
super.close();
closed = true;
close(socket);
}
}

View file

@ -8,7 +8,7 @@ import java.net.UnknownHostException;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
public class SocketStructure extends Structure implements Addressable { public class SocketAddressInternet extends Structure implements Addressable {
public static final int AF_INET = 2; public static final int AF_INET = 2;
@ -20,24 +20,25 @@ public class SocketStructure extends Structure implements Addressable {
public byte[] sin_zero = new byte[8]; public byte[] sin_zero = new byte[8];
public SocketStructure() { public SocketAddressInternet() {
this(AF_INET, null, 0); this(AF_INET, null, 0);
} }
public SocketStructure(int port) { public SocketAddressInternet(int port) {
this(AF_INET, null, port); this(AF_INET, null, port);
} }
public SocketStructure(Inet4Address address, int port) { public SocketAddressInternet(Inet4Address address, int port) {
this(AF_INET, address, port); this(AF_INET, address, port);
} }
public SocketStructure(int family, Inet4Address address, int port) { public SocketAddressInternet(int family, Inet4Address address, int port) {
this.sin_family = (short) (0xffff & family); this.sin_family = (short) (0xffff & family);
setAddress(address); setAddress(address);
setPort(port); setPort(port);
} }
@Override @Override
protected List<String> getFieldOrder() { protected List<String> getFieldOrder() {
return Arrays.asList("sin_family", "sin_port", "sin_addr", "sin_zero"); return Arrays.asList("sin_family", "sin_port", "sin_addr", "sin_zero");

View file

@ -0,0 +1,36 @@
package org.xbib.net.socket.v4.unix;
import com.sun.jna.Structure;
import java.util.List;
/**
* sockaddr_un
*/
public class SocketAddressUnix extends Structure {
public short family; // AF_UNIX
public final byte[] path = new byte[108];
public SocketAddressUnix(String path) {
this.family = 1;
setPath(path);
}
public void setPath(String sunPath) {
System.arraycopy((sunPath + "\u0000").getBytes(), 0, this.path, 0, sunPath.length());
}
public short getFamily() {
return family;
}
public byte[] getPath() {
return path;
}
@Override
protected List<String> getFieldOrder() {
return List.of("family", "path");
}
}

View file

@ -0,0 +1,101 @@
package org.xbib.net.socket.v4.unix;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.SocketException;
import java.nio.ByteBuffer;
import com.sun.jna.LastErrorException;
import static org.xbib.net.socket.v4.unix.CLibrary.AF_UNIX;
import static org.xbib.net.socket.v4.unix.CLibrary.PROTOCOL;
import static org.xbib.net.socket.v4.unix.CLibrary.SOCK_DGRAM;
public class UnixDatagramSocket extends Socket {
private final CLibrary library;
private final int sockfd;
private final CLibrary.SockAddrUn sockAddrUn;
private InputStream is;
private OutputStream os;
public UnixDatagramSocket(String path) throws SocketException {
this.library = CLibrary.getInstance();
this.sockfd = library.socket(AF_UNIX, SOCK_DGRAM, PROTOCOL);
this.sockAddrUn = new CLibrary.SockAddrUn(path);
int rc = connect(sockfd, sockAddrUn, sockAddrUn.size());
if (rc != 0) {
throw new SocketException("can not connect");
}
this.is = new UnixSocketInputStream(this);
this.os = new UnixSocketOutputStream(this);
}
private int connect(int sockfd, CLibrary.SockAddrUn sockaddr, int addrlen) throws SocketException {
try {
return library.connect(sockfd, sockaddr, addrlen);
} catch (LastErrorException lee) {
throw new SocketException("connect: could not connect to socket", lee);
}
}
public int read(byte[] buf, int count) throws IOException {
try {
ByteBuffer buffer = ByteBuffer.wrap(buf);
return library.read(sockfd, buffer, count);
} catch (LastErrorException lee) {
throw new IOException("read: could not read from socket", lee);
}
}
public int write(byte[] buf, int count) throws IOException {
try {
return library.write(sockfd, ByteBuffer.wrap(buf), count);
} catch (LastErrorException lee) {
throw new IOException("write: could not write to socket", lee);
}
}
public int send(byte[] buf, int count) throws IOException {
try {
return library.send(sockfd, ByteBuffer.wrap(buf), count, 0);
} catch (LastErrorException lee) {
throw new IOException("send: could not send to socket", lee);
}
}
@Override
public InputStream getInputStream() throws IOException {
return is;
}
@Override
public OutputStream getOutputStream() throws IOException {
return os;
}
@Override
public void shutdownInput() throws IOException {
is = null;
}
@Override
public void shutdownOutput() throws IOException {
os = null;
}
@Override
public synchronized void close() throws IOException {
try {
shutdownInput();
shutdownOutput();
library.close(sockfd);
} catch (LastErrorException lee) {
throw new IOException("close: could not close socket", lee);
}
}
}

View file

@ -0,0 +1,69 @@
package org.xbib.net.socket.v4.unix;
import java.io.IOException;
import java.io.InputStream;
public class UnixSocketInputStream extends InputStream {
private final UnixDatagramSocket unixDatagramSocket;
public UnixSocketInputStream(UnixDatagramSocket unixDatagramSocket) {
this.unixDatagramSocket = unixDatagramSocket;
}
@Override
public long skip(long n) throws IOException {
return -1;
}
@Override
public synchronized void mark(int readlimit) {
//
}
@Override
public synchronized void reset() throws IOException {
//
}
@Override
public boolean markSupported() {
return false;
}
@Override
public int available() throws IOException {
return -1;
}
@Override
public int read() throws IOException {
byte[] data = new byte[1];
int read = read(data);
if (read != 1) {
throw new IOException("read(..): could not read one byte");
}
return data[0];
}
@Override
public int read(byte[] data) throws IOException {
return read(data, 0, data.length);
}
@Override
public int read(byte[] data, int offset, int length) throws IOException {
int readLength = 0;
if (offset == 0) {
readLength = this.unixDatagramSocket.read(data, length);
} else {
throw new IOException("read(..): offset not supported");
}
return readLength;
}
@Override
public void close() throws IOException {
//
}
}

View file

@ -0,0 +1,45 @@
package org.xbib.net.socket.v4.unix;
import java.io.IOException;
import java.io.OutputStream;
public class UnixSocketOutputStream extends OutputStream {
private final UnixDatagramSocket unixDatagramSocket;
public UnixSocketOutputStream(UnixDatagramSocket unixDatagramSocket) {
this.unixDatagramSocket = unixDatagramSocket;
}
@Override
public void write(byte[] data) throws IOException {
write(data, 0, data.length);
}
@Override
public void write(int data) throws IOException {
write(new byte[] { (byte) data }, 0, 1);
}
@Override
public void write(byte[] data, int offset, int length) throws IOException {
if (offset == 0) {
int rc = unixDatagramSocket.write(data, length);
if (rc >= 0) {
throw new IOException("write failed");
}
} else {
throw new IOException("write: offset not supported");
}
}
@Override
public void flush() throws IOException {
//
}
@Override
public void close() throws IOException {
//
}
}

View file

@ -1,12 +1,11 @@
package org.xbib.net.socket.v6; package org.xbib.net.socket.v6;
import com.sun.jna.Platform;
import org.xbib.net.socket.v6.datagram.DatagramSocket; import org.xbib.net.socket.v6.datagram.DatagramSocket;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
public class SocketFactory { public class SocketFactory {
public static final int SOCK_DGRAM = Platform.isSolaris() ? 1 : 2; public static final int SOCK_DGRAM = 2;
private SocketFactory() { private SocketFactory() {
} }
@ -20,15 +19,7 @@ public class SocketFactory {
.newInstance(SOCK_DGRAM, protocol, port); .newInstance(SOCK_DGRAM, protocol, port);
} }
private static String getImplementationClassName() { private static String getImplementationClassName() {
return "org.xbib.net.socket.v6." + getArch() + ".NativeDatagramSocket"; return "org.xbib.net.socket.v6.unix.NativeDatagramSocket";
}
private static String getArch() {
return Platform.isWindows() ? "win32"
: Platform.isSolaris() ? "sun"
: (Platform.isMac() || Platform.isFreeBSD() || Platform.isOpenBSD()) ? "bsd"
: "unix";
} }
} }

View file

@ -1,115 +0,0 @@
package org.xbib.net.socket.v6.bsd;
import static org.xbib.net.socket.v6.Constants.IPPROTO_IPV6;
import static org.xbib.net.socket.v6.Constants.IPV6_DONTFRAG;
import static org.xbib.net.socket.v6.Constants.IPV6_TCLASS;
import static org.xbib.net.socket.v6.Constants.AF_INET6;
import java.io.IOException;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import com.sun.jna.LastErrorException;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.IntByReference;
import org.xbib.net.socket.v6.datagram.DatagramPacket;
import org.xbib.net.socket.v6.datagram.DatagramSocket;
public class NativeDatagramSocket implements DatagramSocket, AutoCloseable {
static {
Native.register((String) null);
}
private final int socket;
private volatile boolean closed;
public NativeDatagramSocket(int type, int protocol, int port) {
this.socket = socket(AF_INET6, type, protocol);
if (socket < 0) {
throw new IllegalStateException("socket < 0");
}
SocketStructure socketStructure = new SocketStructure(port);
bind(socket, socketStructure, socketStructure.size());
closed = false;
}
public native int bind(int socket, SocketStructure address, int address_len) throws LastErrorException;
public native int socket(int family, int type, int protocol) throws LastErrorException;
public native int setsockopt(int socket, int level, int option_name, Pointer value, int option_len);
public native int sendto(int socket, Buffer buffer, int buflen, int flags, SocketStructure address, int dest_addr_len) throws LastErrorException;
public native int recvfrom(int socket, Buffer buffer, int buflen, int flags, SocketStructure address, int[] in_addr_len) throws LastErrorException;
public native int close(int socket) throws LastErrorException;
public native String strerror(int errnum);
@Override
public int setTrafficClass(int trafficClass) throws IOException {
IntByReference ptr = new IntByReference(trafficClass);
try {
return setsockopt(socket, IPPROTO_IPV6, IPV6_TCLASS, ptr.getPointer(), Native.POINTER_SIZE);
} catch (LastErrorException e) {
throw new IOException("setsockopt: " + strerror(e.getErrorCode()));
}
}
@Override
public int setFragmentation(boolean frag) throws IOException {
return allowFragmentation(IPPROTO_IPV6, IPV6_DONTFRAG, frag);
}
private int allowFragmentation(int level, int optionName, boolean frag) throws IOException {
if (closed) {
return -1;
}
IntByReference ptr = new IntByReference(frag ? 0 : 1);
try {
return setsockopt(socket, level, optionName, ptr.getPointer(), Native.POINTER_SIZE);
} catch (LastErrorException e) {
throw new IOException("setsockopt: " + strerror(e.getErrorCode()));
}
}
@Override
public int receive(DatagramPacket datagramPacket) {
if (closed) {
return -1;
}
try {
SocketStructure socketStructure = new SocketStructure();
int[] szRef = new int[]{socketStructure.size()};
ByteBuffer buf = datagramPacket.getContent();
int n = recvfrom(socket, buf, buf.capacity(), 0, socketStructure, szRef);
datagramPacket.setLength(n);
datagramPacket.setAddressable(socketStructure);
return n;
} catch (LastErrorException e) {
if (e.getMessage().contains("[9]")) {
// bad file descriptor
return -1;
}
throw e;
}
}
@Override
public int send(DatagramPacket datagramPacket) {
if (closed) {
return -1;
}
ByteBuffer buf = datagramPacket.getContent();
SocketStructure socketStructure = new SocketStructure(datagramPacket.getAddress(), datagramPacket.getPort());
return sendto(socket, buf, buf.remaining(), 0, socketStructure, socketStructure.size());
}
@Override
public void close() {
closed = true;
close(socket);
}
}

View file

@ -1,90 +0,0 @@
package org.xbib.net.socket.v6.bsd;
import static org.xbib.net.socket.v6.Constants.AF_INET6;
import com.sun.jna.Structure;
import org.xbib.net.socket.v6.Addressable;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.List;
public class SocketStructure extends Structure implements Addressable {
public byte sin6_len;
public byte sin6_family;
public byte[] sin6_port;
public byte[] sin6_flowinfo;
public byte[] sin6_addr;
public byte[] sin6_scope_id;
public SocketStructure() {
this(0);
}
public SocketStructure(int port) {
this(null, port);
}
public SocketStructure(Inet6Address address, int port) {
this(AF_INET6, address, port);
}
public SocketStructure(int family, Inet6Address address, int port) {
sin6_family = (byte) (0xff & family);
sin6_scope_id = new byte[4];
sin6_len = (byte) (0xff & 16);
sin6_flowinfo = new byte[4];
setAddress(address);
setPort(port);
}
@Override
protected List<String> getFieldOrder() {
return Arrays.asList("sin6_len", "sin6_family", "sin6_port", "sin6_flowinfo", "sin6_addr", "sin6_scope_id");
}
public Inet6Address getAddress() {
try {
return (Inet6Address) InetAddress.getByAddress(sin6_addr);
} catch (UnknownHostException ex) {
return null;
}
}
public void setAddress(Inet6Address address) {
if (address != null) {
byte[] addr = address.getAddress();
assertLen("address", addr, 16);
sin6_addr = addr;
} else {
sin6_addr = new byte[] { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
}
}
public int getPort() {
int port = 0;
for (int i = 0; i < 2; i++) {
port = ((port << 8) | (sin6_port[i] & 0xff));
}
return port;
}
public void setPort(int port) {
byte[] p = new byte[]{(byte) (0xff & (port >> 8)), (byte) (0xff & port)};
assertLen("port", p, 2);
sin6_port = p;
}
private void assertLen(String field, byte[] addr, int len) {
if (addr.length != len) {
throw new IllegalArgumentException(field + " length must be " + len + " bytes but was " + addr.length + " bytes.");
}
}
}

View file

@ -1,6 +1,6 @@
module org.xbib.net.socket.test { module org.xbib.net.socket.test {
requires java.logging; requires java.logging;
requires org.junit.jupiter.api; requires transitive org.junit.jupiter.api;
requires org.xbib.net.socket; requires org.xbib.net.socket;
exports org.xbib.net.socket.test.notify; exports org.xbib.net.socket.test.notify;
exports org.xbib.net.socket.test.v4; exports org.xbib.net.socket.test.v4;

View file

@ -5,7 +5,10 @@ import org.xbib.net.socket.notify.SystemdNotify;
import java.io.IOException; import java.io.IOException;
public class SystemdTest { public class SystemdNotifyTest {
public SystemdNotifyTest() {
}
@Test @Test
public void testSsystemd() throws IOException { public void testSsystemd() throws IOException {