diff --git a/src/main/java/jnr/unixsocket/UnixSocketChannel.java b/src/main/java/jnr/unixsocket/UnixSocketChannel.java index 7b96bb4..83f745b 100644 --- a/src/main/java/jnr/unixsocket/UnixSocketChannel.java +++ b/src/main/java/jnr/unixsocket/UnixSocketChannel.java @@ -64,6 +64,27 @@ public static final UnixSocketChannel[] pair() throws IOException { }; } + /** + * Create a UnixSocketChannel to wrap an existing file descriptor (presumably itself a UNIX socket). + * + * @param fd the file descriptor to wrap + * @return the new UnixSocketChannel instance + */ + public static final UnixSocketChannel fromFD(int fd) { + return fromFD(fd, SelectionKey.OP_READ | SelectionKey.OP_WRITE); + } + + /** + * Create a UnixSocketChannel to wrap an existing file descriptor (presumably itself a UNIX socket). + * + * @param fd the file descriptor to wrap + * @param ops the SelectionKey operations the socket supports + * @return the new UnixSocketChannel instance + */ + public static final UnixSocketChannel fromFD(int fd, int ops) { + return new UnixSocketChannel(fd, ops); + } + private UnixSocketChannel() throws IOException { super(Native.socket(ProtocolFamily.PF_UNIX, Sock.SOCK_STREAM, 0), SelectionKey.OP_CONNECT | SelectionKey.OP_READ | SelectionKey.OP_WRITE); diff --git a/src/test/java/jnr/unixsocket/ForFDTest.java b/src/test/java/jnr/unixsocket/ForFDTest.java new file mode 100644 index 0000000..19d6e39 --- /dev/null +++ b/src/test/java/jnr/unixsocket/ForFDTest.java @@ -0,0 +1,80 @@ +package jnr.unixsocket; + +import jnr.constants.platform.ProtocolFamily; +import jnr.constants.platform.Sock; +import junit.framework.Assert; +import org.junit.Test; + +import java.io.File; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.StandardCharsets; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertNotNull; +import static junit.framework.Assert.assertTrue; + +/** + * Created by headius on 11/24/15. + */ +public class ForFDTest { + private static final File SOCKADDR = new File("/tmp/jnr-unixsocket-forfd" + System.currentTimeMillis() + ".sock"); + static { SOCKADDR.deleteOnExit(); } + private static final UnixSocketAddress ADDRESS = new UnixSocketAddress(SOCKADDR); + private static final String FOOBAR = "foobar"; + + private volatile Exception serverException; + + @Test + public void testForFD() throws Exception { + int fd = 0; + UnixSocketChannel channel = null; + + try { + final UnixServerSocketChannel server = UnixServerSocketChannel.open(); + server.socket().bind(ADDRESS); + + new Thread("accept thread") { + public void run() { + UnixSocketChannel channel = null; + + try { + channel = server.accept(); + channel.write(ByteBuffer.wrap(FOOBAR.getBytes())); + } catch (Exception e) { + serverException = e; + } finally { + try {channel.close();} catch (Exception e) {} + } + } + }.start(); + + fd = Native.socket(ProtocolFamily.PF_UNIX, Sock.SOCK_STREAM, 0); + + assertTrue("socket failed", fd > 0); + + int ret = Native.connect(fd, ADDRESS.getStruct(), ADDRESS.getStruct().length()); + + assertTrue("connect failed", ret >= 0); + + channel = UnixSocketChannel.fromFD(fd); + + assertNotNull(channel); + + ByteBuffer buf = ByteBuffer.allocate(1024); + + channel.read(buf); + + assertEquals(FOOBAR.length(), buf.position()); + + buf.flip(); + String result = new String(buf.array(), buf.position(), buf.limit(), StandardCharsets.UTF_8); + + assertEquals(FOOBAR, result); + + if (serverException != null) throw serverException; + } finally { + channel.close(); + } + } +}