diff -Nru jnr-unixsocket-0.3/debian/changelog jnr-unixsocket-0.8/debian/changelog --- jnr-unixsocket-0.3/debian/changelog 2015-10-19 21:18:27.000000000 +0000 +++ jnr-unixsocket-0.8/debian/changelog 2015-09-21 16:41:39.000000000 +0000 @@ -1,8 +1,12 @@ -jnr-unixsocket (0.3-2ubuntu1) wily; urgency=medium +jnr-unixsocket (0.8-1) unstable; urgency=medium - * Build-depend on junit4 to fix FTBFS. + * Team upload. + * New upstream release + - New dependency on libjnr-posix-java + * Added the missing build dependency on junit4 + * Deduplicated the packages descriptions - -- Logan Rosen Mon, 19 Oct 2015 17:18:20 -0400 + -- Emmanuel Bourg Mon, 21 Sep 2015 18:41:37 +0200 jnr-unixsocket (0.3-2) unstable; urgency=medium diff -Nru jnr-unixsocket-0.3/debian/control jnr-unixsocket-0.8/debian/control --- jnr-unixsocket-0.3/debian/control 2015-10-19 21:18:29.000000000 +0000 +++ jnr-unixsocket-0.8/debian/control 2015-09-21 16:39:58.000000000 +0000 @@ -1,8 +1,7 @@ Source: jnr-unixsocket Section: java Priority: optional -Maintainer: Ubuntu Developers -XSBC-Original-Maintainer: Debian Java Maintainers +Maintainer: Debian Java Maintainers Uploaders: Tim Potter Build-Depends: debhelper (>= 9), default-jdk, @@ -13,13 +12,14 @@ libjnr-constants-java, libjnr-enxio-java, libjnr-ffi-java, + libjnr-posix-java, libjnr-x86asm-java (>= 1.0.2), libmaven-javadoc-plugin-java, maven-debian-helper Standards-Version: 3.9.6 Homepage: https://github.com/jnr/jnr-unixsocket Vcs-Git: git://anonscm.debian.org/pkg-java/jnr-unixsocket.git -Vcs-Browser: http://anonscm.debian.org/gitweb/?p=pkg-java/jnr-unixsocket.git +Vcs-Browser: http://anonscm.debian.org/cgit/pkg-java/jnr-unixsocket.git Package: libjnr-unixsocket-java Architecture: all @@ -39,7 +39,7 @@ Section: doc Depends: ${maven:DocDepends}, ${misc:Depends} Suggests: libjnr-unixsocket-java, ${maven:DocOptionalDepends} -Description: Java access to native libraries for unix sockets +Description: Java access to native libraries for unix sockets (documentation) Java Native Runtime (JNR) is a collection of Java libraries to make interfacing with OS-level features easier. JNR uses an alternate method to JNI or JNA to achieve programming simplicity while still diff -Nru jnr-unixsocket-0.3/debian/maven.cleanIgnoreRules jnr-unixsocket-0.8/debian/maven.cleanIgnoreRules --- jnr-unixsocket-0.3/debian/maven.cleanIgnoreRules 2015-05-03 22:42:05.000000000 +0000 +++ jnr-unixsocket-0.8/debian/maven.cleanIgnoreRules 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ - diff -Nru jnr-unixsocket-0.3/debian/maven.publishedRules jnr-unixsocket-0.8/debian/maven.publishedRules --- jnr-unixsocket-0.3/debian/maven.publishedRules 2015-05-03 22:42:05.000000000 +0000 +++ jnr-unixsocket-0.8/debian/maven.publishedRules 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ - diff -Nru jnr-unixsocket-0.3/pom.xml jnr-unixsocket-0.8/pom.xml --- jnr-unixsocket-0.3/pom.xml 2013-04-03 00:45:01.000000000 +0000 +++ jnr-unixsocket-0.8/pom.xml 2015-05-04 19:05:51.000000000 +0000 @@ -10,7 +10,7 @@ com.github.jnr jnr-unixsocket jar - 0.3 + 0.8 jnr-unixsocket Native I/O access for java http://github.com/jnr/jnr-unixsocket @@ -47,19 +47,25 @@ com.github.jnr jnr-ffi - 1.0.3 + 2.0.3 compile com.github.jnr jnr-constants - 0.8.4 + 0.8.7 compile com.github.jnr jnr-enxio - 0.4 + 0.9 + compile + + + com.github.jnr + jnr-posix + 3.0.12 compile diff -Nru jnr-unixsocket-0.3/README.md jnr-unixsocket-0.8/README.md --- jnr-unixsocket-0.3/README.md 1970-01-01 00:00:00.000000000 +0000 +++ jnr-unixsocket-0.8/README.md 2015-05-04 19:05:51.000000000 +0000 @@ -0,0 +1,7 @@ +jnr-unixsocket +============== + +Native I/O access for java. + +Check out the [examples](https://github.com/jnr/jnr-unixsocket/tree/master/src/test/java/jnr/unixsocket/example) for more information. + diff -Nru jnr-unixsocket-0.3/src/main/java/jnr/unixsocket/Credentials.java jnr-unixsocket-0.8/src/main/java/jnr/unixsocket/Credentials.java --- jnr-unixsocket-0.3/src/main/java/jnr/unixsocket/Credentials.java 1970-01-01 00:00:00.000000000 +0000 +++ jnr-unixsocket-0.8/src/main/java/jnr/unixsocket/Credentials.java 2015-05-04 19:05:51.000000000 +0000 @@ -0,0 +1,55 @@ +/* + * This file is part of the JNR project. + * + * 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 jnr.unixsocket; + +import jnr.constants.platform.SocketLevel; +import jnr.constants.platform.SocketOption; + +public final class Credentials { + private final Ucred ucred; + + Credentials(Ucred ucred) { + this.ucred = ucred; + } + + public int getPid() { + return ucred.getPidField().intValue(); + } + + public int getUid() { + return ucred.getUidField().intValue(); + } + + public int getGid() { + return ucred.getGidField().intValue(); + } + + @Override + public java.lang.String toString() { + return java.lang.String.format("[uid=%d gid=%d pid=%d]", getUid(), getGid(), getPid()); + } + + static final Credentials getCredentials(int fd) { + Ucred c = new Ucred(); + int error = Native.getsockopt(fd, SocketLevel.SOL_SOCKET, SocketOption.SO_PEERCRED, c); + if (error != 0) { + throw new UnsupportedOperationException(Native.getLastErrorString()); + } + + return new Credentials(c); + } +} diff -Nru jnr-unixsocket-0.3/src/main/java/jnr/unixsocket/example/UnixClient.java jnr-unixsocket-0.8/src/main/java/jnr/unixsocket/example/UnixClient.java --- jnr-unixsocket-0.3/src/main/java/jnr/unixsocket/example/UnixClient.java 2013-04-03 00:45:01.000000000 +0000 +++ jnr-unixsocket-0.8/src/main/java/jnr/unixsocket/example/UnixClient.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,34 +0,0 @@ - -package jnr.unixsocket.example; - -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.PrintWriter; -import java.nio.CharBuffer; -import java.nio.channels.Channels; -import jnr.unixsocket.UnixSocketAddress; -import jnr.unixsocket.UnixSocketChannel; - -public class UnixClient { - public static void main(String[] args) throws IOException { - java.io.File path = new java.io.File("/tmp/fubar.sock"); - String data = "blah blah"; - UnixSocketAddress address = new UnixSocketAddress(path); - UnixSocketChannel channel = UnixSocketChannel.open(address); - System.out.println("connected to " + channel.getRemoteSocketAddress()); - PrintWriter w = new PrintWriter(Channels.newOutputStream(channel)); - w.print(data); - w.flush(); - - InputStreamReader r = new InputStreamReader(Channels.newInputStream(channel)); - CharBuffer result = CharBuffer.allocate(1024); - r.read(result); - result.flip(); - System.out.println("read from server: " + result.toString()); - if (!result.toString().equals(data)) { - System.out.println("ERROR: data mismatch"); - } else { - System.out.println("SUCCESS"); - } - } -} diff -Nru jnr-unixsocket-0.3/src/main/java/jnr/unixsocket/example/UnixServer.java jnr-unixsocket-0.8/src/main/java/jnr/unixsocket/example/UnixServer.java --- jnr-unixsocket-0.3/src/main/java/jnr/unixsocket/example/UnixServer.java 2013-04-03 00:45:01.000000000 +0000 +++ jnr-unixsocket-0.8/src/main/java/jnr/unixsocket/example/UnixServer.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,98 +0,0 @@ - -package jnr.unixsocket.example; - -import jnr.enxio.channels.NativeSelectorProvider; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.channels.SelectionKey; -import java.nio.channels.Selector; -import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; -import jnr.unixsocket.UnixServerSocket; -import jnr.unixsocket.UnixServerSocketChannel; -import jnr.unixsocket.UnixSocketAddress; -import jnr.unixsocket.UnixSocketChannel; - -public class UnixServer { - - public static void main(String[] args) throws IOException { - java.io.File path = new java.io.File("/tmp/fubar.sock"); - path.deleteOnExit(); - UnixSocketAddress address = new UnixSocketAddress(path); - UnixServerSocketChannel channel = UnixServerSocketChannel.open(); - - try { - Selector sel = NativeSelectorProvider.getInstance().openSelector(); - channel.configureBlocking(false); - channel.socket().bind(address); - channel.register(sel, SelectionKey.OP_ACCEPT, new ServerActor(channel, sel)); - - while (sel.select() > 0) { - Set keys = sel.selectedKeys(); - for (SelectionKey k : keys) { - Actor a = (Actor) k.attachment(); - if (!a.rxready()) { - k.cancel(); - } - } - } - } catch (IOException ex) { - Logger.getLogger(UnixServerSocket.class.getName()).log(Level.SEVERE, null, ex); - } - - } - - static interface Actor { - public boolean rxready(); - } - - static final class ServerActor implements Actor { - private final UnixServerSocketChannel channel; - private final Selector selector; - - public ServerActor(UnixServerSocketChannel channel, Selector selector) { - this.channel = channel; - this.selector = selector; - } - public final boolean rxready() { - try { - UnixSocketChannel client = channel.accept(); - client.configureBlocking(false); - client.register(selector, SelectionKey.OP_READ, new ClientActor(client)); - return true; - } catch (IOException ex) { - return false; - } - } - } - static final class ClientActor implements Actor { - private final UnixSocketChannel channel; - - public ClientActor(UnixSocketChannel channel) { - this.channel = channel; - } - - public final boolean rxready() { - try { - ByteBuffer buf = ByteBuffer.allocate(1024); - int n = channel.read(buf); - UnixSocketAddress remote = channel.getRemoteSocketAddress(); - System.out.printf("Read in %d bytes from %s\n", n, remote); - - if (n > 0) { - buf.flip(); - channel.write(buf); - return true; - } else if (n < 0) { - return false; - } - - } catch (IOException ex) { - ex.printStackTrace(); - return false; - } - return true; - } - } -} diff -Nru jnr-unixsocket-0.3/src/main/java/jnr/unixsocket/Native.java jnr-unixsocket-0.8/src/main/java/jnr/unixsocket/Native.java --- jnr-unixsocket-0.3/src/main/java/jnr/unixsocket/Native.java 2013-04-03 00:45:01.000000000 +0000 +++ jnr-unixsocket-0.8/src/main/java/jnr/unixsocket/Native.java 2015-05-04 19:05:51.000000000 +0000 @@ -18,29 +18,37 @@ package jnr.unixsocket; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + import jnr.constants.platform.ProtocolFamily; import jnr.constants.platform.Sock; import jnr.constants.platform.SocketLevel; import jnr.constants.platform.SocketOption; -import jnr.ffi.*; +import jnr.ffi.LastError; +import jnr.ffi.Library; +import jnr.ffi.LibraryLoader; +import jnr.ffi.Platform; +import jnr.ffi.Pointer; +import jnr.ffi.Runtime; +import jnr.ffi.Struct; import jnr.ffi.annotations.In; import jnr.ffi.annotations.Out; import jnr.ffi.annotations.Transient; import jnr.ffi.byref.IntByReference; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; +import jnr.posix.DefaultNativeTimeval; +import jnr.posix.Timeval; class Native { static final String[] libnames = Platform.getNativePlatform().getOS() == Platform.OS.SOLARIS ? new String[] { "socket", "nsl", "c" } : new String[] { "c" }; public static interface LibC { - static final LibC INSTANCE = Library.loadLibrary(LibC.class, libnames); - public static final int F_GETFL = com.kenai.constantine.platform.Fcntl.F_GETFL.value(); - public static final int F_SETFL = com.kenai.constantine.platform.Fcntl.F_SETFL.value(); - public static final int O_NONBLOCK = com.kenai.constantine.platform.OpenFlags.O_NONBLOCK.value(); + + public static final int F_GETFL = jnr.constants.platform.Fcntl.F_GETFL.intValue(); + public static final int F_SETFL = jnr.constants.platform.Fcntl.F_SETFL.intValue(); + public static final int O_NONBLOCK = jnr.constants.platform.OpenFlags.O_NONBLOCK.intValue(); int socket(int domain, int type, int protocol); int listen(int fd, int backlog); @@ -52,16 +60,28 @@ int socketpair(int domain, int type, int protocol, @Out int[] sv); int fcntl(int fd, int cmd, int data); int getsockopt(int s, int level, int optname, @Out ByteBuffer optval, @In @Out IntByReference optlen); + int getsockopt(int s, int level, int optname, @Out Timeval optval, @In @Out IntByReference optlen); int setsockopt(int s, int level, int optname, @In ByteBuffer optval, int optlen); + int setsockopt(int s, int level, int optname, @In Timeval optval, int optlen); String strerror(int error); } + + static final LibC INSTANCE; + + static { + LibraryLoader loader = LibraryLoader.create(LibC.class); + for (String libraryName : libnames) { + loader.library(libraryName); + } + INSTANCE = loader.load(); + } static final LibC libsocket() { - return LibC.INSTANCE; + return INSTANCE; } static final LibC libc() { - return LibC.INSTANCE; + return INSTANCE; } static int socket(ProtocolFamily domain, Sock type, int protocol) throws IOException { @@ -114,9 +134,47 @@ } public static int setsockopt(int s, SocketLevel level, SocketOption optname, boolean optval) { - ByteBuffer buf = ByteBuffer.allocate(4); - buf.order(ByteOrder.BIG_ENDIAN); - buf.putInt(optval ? 1 : 0).flip(); - return libsocket().setsockopt(s, level.intValue(), optname.intValue(), buf, buf.remaining()); + return setsockopt(s, level, optname, optval ? 1 : 0); + } + + public static int setsockopt(int s, SocketLevel level, SocketOption optname, int optval) { + if (optname == SocketOption.SO_RCVTIMEO) { + DefaultNativeTimeval t = new DefaultNativeTimeval(Runtime.getSystemRuntime()); + t.setTime(new long [] {optval / 1000, (optval % 1000) * 1000}); + return libsocket().setsockopt(s, level.intValue(), optname.intValue(), t, DefaultNativeTimeval.size(t)); + } else { + ByteBuffer buf = ByteBuffer.allocate(4); + buf.order(ByteOrder.BIG_ENDIAN); + buf.putInt(optval).flip(); + return libsocket().setsockopt(s, level.intValue(), optname.intValue(), buf, buf.remaining()); + } + } + + public static int getsockopt (int s, SocketLevel level, int optname) { + IntByReference ref; + if (optname == SocketOption.SO_RCVTIMEO.intValue()) { + DefaultNativeTimeval t = new DefaultNativeTimeval(Runtime.getSystemRuntime()); + ref = new IntByReference(DefaultNativeTimeval.size(t)); + Native.libsocket().getsockopt(s, level.intValue(), optname, t, ref); + return (t.tv_sec.intValue() * 1000) + (t.tv_usec.intValue() / 1000); + } else { + ByteBuffer buf = ByteBuffer.allocate(4); + buf.order(ByteOrder.BIG_ENDIAN); + ref = new IntByReference(4); + Native.libsocket().getsockopt(s, level.intValue(), optname, buf, ref); + return buf.getInt(); + } + } + + public static int getsockopt(int s, SocketLevel level, SocketOption optname, Struct data) { + Pointer struct_ptr = Struct.getMemory(data); + IntByReference ref = new IntByReference(Struct.size(data)); + ByteBuffer buf = ByteBuffer.wrap((byte[])struct_ptr.array()); + + return Native.libsocket().getsockopt(s, level.intValue(), optname.intValue(), buf, ref); + } + + public static boolean getboolsockopt (int s, SocketLevel level, int optname) { + return getsockopt(s, level, optname) != 0; } } diff -Nru jnr-unixsocket-0.3/src/main/java/jnr/unixsocket/SockAddrUnix.java jnr-unixsocket-0.8/src/main/java/jnr/unixsocket/SockAddrUnix.java --- jnr-unixsocket-0.3/src/main/java/jnr/unixsocket/SockAddrUnix.java 2013-04-03 00:45:01.000000000 +0000 +++ jnr-unixsocket-0.8/src/main/java/jnr/unixsocket/SockAddrUnix.java 2015-05-04 19:05:51.000000000 +0000 @@ -18,7 +18,7 @@ package jnr.unixsocket; -import com.kenai.constantine.platform.ProtocolFamily; +import jnr.constants.platform.ProtocolFamily; import jnr.ffi.*; /** @@ -30,17 +30,17 @@ protected abstract UTF8String getPathField(); protected abstract NumberField getFamilyField(); - public SockAddrUnix() { + SockAddrUnix() { super(jnr.ffi.Runtime.getSystemRuntime()); } /** * Sets the protocol family of this unix socket address. * - * @param family The protocol family, usually {@link com.kenai.constantine.platform.ProtocolFamily.PF_UNIX} + * @param family The protocol family, usually {@link ProtocolFamily#PF_UNIX} */ - public final void setFamily(ProtocolFamily family) { - getFamilyField().set(family.value()); + final void setFamily(ProtocolFamily family) { + getFamilyField().set(family.intValue()); } @@ -49,7 +49,7 @@ * * @return The protocol family */ - public final ProtocolFamily getFamily() { + final ProtocolFamily getFamily() { return ProtocolFamily.valueOf(getFamilyField().intValue()); } @@ -58,7 +58,7 @@ * * @param path The unix socket address */ - public final void setPath(java.lang.String path) { + final void setPath(java.lang.String path) { getPathField().set(path); } @@ -67,7 +67,7 @@ * * @return A String */ - public final java.lang.String getPath() { + final java.lang.String getPath() { return getPathField().get(); } @@ -76,7 +76,7 @@ * * @return The maximum size of the address in bytes */ - public int getMaximumLength() { + int getMaximumLength() { return 2 + getPathField().length(); } @@ -85,7 +85,7 @@ * * @return The actual size of this address, in bytes */ - public int length() { + int length() { return 2 + strlen(getPathField()); } @@ -96,7 +96,7 @@ * @return An instance of SockAddrUnix */ static SockAddrUnix create() { - return Platform.getPlatform().isBSD() ? new BSDSockAddrUnix() : new DefaultSockAddrUnix(); + return Platform.getNativePlatform().isBSD() ? new BSDSockAddrUnix() : new DefaultSockAddrUnix(); } private static final int strlen(UTF8String str) { diff -Nru jnr-unixsocket-0.3/src/main/java/jnr/unixsocket/Ucred.java jnr-unixsocket-0.8/src/main/java/jnr/unixsocket/Ucred.java --- jnr-unixsocket-0.3/src/main/java/jnr/unixsocket/Ucred.java 1970-01-01 00:00:00.000000000 +0000 +++ jnr-unixsocket-0.8/src/main/java/jnr/unixsocket/Ucred.java 2015-05-04 19:05:51.000000000 +0000 @@ -0,0 +1,44 @@ +/* + * This file is part of the JNR project. + * + * 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 jnr.unixsocket; + +import jnr.ffi.Struct; + +/** + * Native structure for SCM_CREDENTIALS. See 'man 7 unix'. + */ +final class Ucred extends Struct { + final pid_t pid = new pid_t(); + final uid_t uid = new uid_t(); + final gid_t gid = new gid_t(); + + public Ucred() { + super(jnr.ffi.Runtime.getSystemRuntime()); + } + + final pid_t getPidField() { + return pid; + } + + final uid_t getUidField() { + return uid; + } + + final gid_t getGidField() { + return gid; + } +} diff -Nru jnr-unixsocket-0.3/src/main/java/jnr/unixsocket/UnixServerSocketChannel.java jnr-unixsocket-0.8/src/main/java/jnr/unixsocket/UnixServerSocketChannel.java --- jnr-unixsocket-0.3/src/main/java/jnr/unixsocket/UnixServerSocketChannel.java 2013-04-03 00:45:01.000000000 +0000 +++ jnr-unixsocket-0.8/src/main/java/jnr/unixsocket/UnixServerSocketChannel.java 2015-05-04 19:05:51.000000000 +0000 @@ -40,7 +40,7 @@ } UnixServerSocketChannel(SelectorProvider provider, int fd) { - super(provider, fd, SelectionKey.OP_ACCEPT); + super(provider, fd, SelectionKey.OP_ACCEPT | SelectionKey.OP_READ); this.socket = new UnixServerSocket(this); } diff -Nru jnr-unixsocket-0.3/src/main/java/jnr/unixsocket/UnixSocketAddress.java jnr-unixsocket-0.8/src/main/java/jnr/unixsocket/UnixSocketAddress.java --- jnr-unixsocket-0.3/src/main/java/jnr/unixsocket/UnixSocketAddress.java 2013-04-03 00:45:01.000000000 +0000 +++ jnr-unixsocket-0.8/src/main/java/jnr/unixsocket/UnixSocketAddress.java 2015-05-04 19:05:51.000000000 +0000 @@ -18,7 +18,7 @@ package jnr.unixsocket; -import com.kenai.constantine.platform.ProtocolFamily; +import jnr.constants.platform.ProtocolFamily; public class UnixSocketAddress extends java.net.SocketAddress { private final SockAddrUnix address; diff -Nru jnr-unixsocket-0.3/src/main/java/jnr/unixsocket/UnixSocketChannel.java jnr-unixsocket-0.8/src/main/java/jnr/unixsocket/UnixSocketChannel.java --- jnr-unixsocket-0.3/src/main/java/jnr/unixsocket/UnixSocketChannel.java 2013-04-03 00:45:01.000000000 +0000 +++ jnr-unixsocket-0.8/src/main/java/jnr/unixsocket/UnixSocketChannel.java 2015-05-04 19:05:51.000000000 +0000 @@ -21,6 +21,8 @@ import jnr.constants.platform.Errno; import jnr.constants.platform.ProtocolFamily; import jnr.constants.platform.Sock; +import jnr.constants.platform.SocketLevel; +import jnr.constants.platform.SocketOption; import jnr.enxio.channels.NativeSocketChannel; import jnr.ffi.*; import jnr.ffi.byref.IntByReference; @@ -149,6 +151,25 @@ return localAddress != null ? localAddress : (localAddress = getsockname(getFD())); } + /** + * Retrieves the credentials for this UNIX socket. If this socket channel + * is not in a connected state, this method will return null. + * + * @see man unix 7; SCM_CREDENTIALS + * + * @throws UnsupportedOperationException if the underlying socket library + * doesn't support the SO_PEERCRED option + * + * @return the credentials of the remote; null if not connected + */ + public final Credentials getCredentials() { + if (state != State.CONNECTED) { + return null; + } + + return Credentials.getCredentials(getFD()); + } + static UnixSocketAddress getpeername(int sockfd) { UnixSocketAddress remote = new UnixSocketAddress(); IntByReference len = new IntByReference(remote.getStruct().getMaximumLength()); @@ -170,4 +191,21 @@ return remote; } + + public boolean getKeepAlive() { + int ret = Native.getsockopt(getFD(), SocketLevel.SOL_SOCKET, SocketOption.SO_KEEPALIVE.intValue()); + return (ret == 1) ? true : false; + } + + public void setKeepAlive(boolean on) { + Native.setsockopt(getFD(), SocketLevel.SOL_SOCKET, SocketOption.SO_KEEPALIVE, on); + } + + public int getSoTimeout() { + return Native.getsockopt(getFD(), SocketLevel.SOL_SOCKET, SocketOption.SO_RCVTIMEO.intValue()); + } + + public void setSoTimeout(int timeout) { + Native.setsockopt(getFD(), SocketLevel.SOL_SOCKET, SocketOption.SO_RCVTIMEO, timeout); + } } diff -Nru jnr-unixsocket-0.3/src/main/java/jnr/unixsocket/UnixSocket.java jnr-unixsocket-0.8/src/main/java/jnr/unixsocket/UnixSocket.java --- jnr-unixsocket-0.3/src/main/java/jnr/unixsocket/UnixSocket.java 2013-04-03 00:45:01.000000000 +0000 +++ jnr-unixsocket-0.8/src/main/java/jnr/unixsocket/UnixSocket.java 2015-05-04 19:05:51.000000000 +0000 @@ -51,4 +51,20 @@ return buf.getInt(0) != 0; } + + /** + * Retrieves the credentials for this UNIX socket. Clients calling this + * method will receive the server's credentials, and servers will receive + * the client's credentials. User ID, group ID, and PID are supplied. + * + * @see man unix 7; SCM_CREDENTIALS + * + * @throws UnsupportedOperationException if the underlying socket library + * doesn't support the SO_PEERCRED option + * + * @return the credentials of the remote + */ + public final Credentials getCredentials() { + return Credentials.getCredentials(channel.getFD()); + } } diff -Nru jnr-unixsocket-0.3/src/test/java/jnr/unixsocket/CredentialsFunctionalTest.java jnr-unixsocket-0.8/src/test/java/jnr/unixsocket/CredentialsFunctionalTest.java --- jnr-unixsocket-0.3/src/test/java/jnr/unixsocket/CredentialsFunctionalTest.java 1970-01-01 00:00:00.000000000 +0000 +++ jnr-unixsocket-0.8/src/test/java/jnr/unixsocket/CredentialsFunctionalTest.java 2015-05-04 19:05:51.000000000 +0000 @@ -0,0 +1,119 @@ +/* + * This file is part of the JNR project. + * + * 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 jnr.unixsocket; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; + +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.lang.management.ManagementFactory; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +import jnr.ffi.Platform; +import jnr.ffi.Platform.OS; + +import org.junit.Assume; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +public class CredentialsFunctionalTest { + @Rule public TemporaryFolder tempFolder = new TemporaryFolder(); + + private File serverSocket; + private ExecutorService async = Executors.newSingleThreadExecutor(); + + @Before + public void createSockets() throws IOException { + Assume.assumeTrue(OS.LINUX == Platform.getNativePlatform().getOS()); + + serverSocket = tempFolder.newFile("serverSocket"); + serverSocket.delete(); //JUnit is "helpful" and creates it for us + } + + @Test(timeout=30000) + public void credentials() throws IOException, ExecutionException, InterruptedException { + UnixSocketAddress address = new UnixSocketAddress(serverSocket); + final UnixServerSocket socket = new UnixServerSocket(); + socket.bind(address); + + Future socketFuture = async.submit(new Callable() { + public UnixSocket call() throws Exception { + return socket.accept(); + } + }); + + UnixSocketChannel client = UnixSocketChannel.open(address); + UnixSocket server = socketFuture.get(); + + assertNotNull("Client socket must be non-null.", client); + assertNotNull("Server socket must be non-null.", server); + + Credentials clientCreds = client.getCredentials(); + Credentials serverCreds = server.getCredentials(); + + int myPid = getCurrentPid(); + + assertEquals("Current PID should match client credentials", + myPid, clientCreds.getPid()); + assertEquals("Current PID should match server credentials", + myPid, serverCreds.getPid()); + + assertEquals("Client/server running in same process, UID should be the same", + clientCreds.getUid(), serverCreds.getUid()); + + //don't have an easy way of getting effective GID, but they should be the same + assertEquals("Client/server running in same process, GID should be the same", + clientCreds.getGid(), serverCreds.getGid()); + } + + public int getCurrentPid() { + String[] nameParts = ManagementFactory.getRuntimeMXBean().getName().split("@", 2); + assertEquals("Cannot determine PID", 2, nameParts.length); + return Integer.valueOf(nameParts[0]); + } + + /* + * A Linux-only utility method. + */ + public int getLoginUid() throws IOException { + FileReader fr = null; + StringBuilder uidText = new StringBuilder(); + try { + fr = new FileReader("/proc/self/loginuid"); + char[] buf = new char[16]; + int read = -1; + while ((read = fr.read(buf)) > -1) { + uidText.append(buf, 0, read); + } + } catch (IOException ioe) { + fail("Unable to determine login uid: " + ioe.getMessage()); + } finally { + fr.close(); + } + + return Integer.valueOf(uidText.toString()); + } +} diff -Nru jnr-unixsocket-0.3/src/test/java/jnr/unixsocket/example/UnixClient.java jnr-unixsocket-0.8/src/test/java/jnr/unixsocket/example/UnixClient.java --- jnr-unixsocket-0.3/src/test/java/jnr/unixsocket/example/UnixClient.java 1970-01-01 00:00:00.000000000 +0000 +++ jnr-unixsocket-0.8/src/test/java/jnr/unixsocket/example/UnixClient.java 2015-05-04 19:05:51.000000000 +0000 @@ -0,0 +1,34 @@ + +package jnr.unixsocket.example; + +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.nio.CharBuffer; +import java.nio.channels.Channels; +import jnr.unixsocket.UnixSocketAddress; +import jnr.unixsocket.UnixSocketChannel; + +public class UnixClient { + public static void main(String[] args) throws IOException { + java.io.File path = new java.io.File("/tmp/fubar.sock"); + String data = "blah blah"; + UnixSocketAddress address = new UnixSocketAddress(path); + UnixSocketChannel channel = UnixSocketChannel.open(address); + System.out.println("connected to " + channel.getRemoteSocketAddress()); + PrintWriter w = new PrintWriter(Channels.newOutputStream(channel)); + w.print(data); + w.flush(); + + InputStreamReader r = new InputStreamReader(Channels.newInputStream(channel)); + CharBuffer result = CharBuffer.allocate(1024); + r.read(result); + result.flip(); + System.out.println("read from server: " + result.toString()); + if (!result.toString().equals(data)) { + System.out.println("ERROR: data mismatch"); + } else { + System.out.println("SUCCESS"); + } + } +} diff -Nru jnr-unixsocket-0.3/src/test/java/jnr/unixsocket/example/UnixServer.java jnr-unixsocket-0.8/src/test/java/jnr/unixsocket/example/UnixServer.java --- jnr-unixsocket-0.3/src/test/java/jnr/unixsocket/example/UnixServer.java 1970-01-01 00:00:00.000000000 +0000 +++ jnr-unixsocket-0.8/src/test/java/jnr/unixsocket/example/UnixServer.java 2015-05-04 19:05:51.000000000 +0000 @@ -0,0 +1,98 @@ + +package jnr.unixsocket.example; + +import jnr.enxio.channels.NativeSelectorProvider; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; +import jnr.unixsocket.UnixServerSocket; +import jnr.unixsocket.UnixServerSocketChannel; +import jnr.unixsocket.UnixSocketAddress; +import jnr.unixsocket.UnixSocketChannel; + +public class UnixServer { + + public static void main(String[] args) throws IOException { + java.io.File path = new java.io.File("/tmp/fubar.sock"); + path.deleteOnExit(); + UnixSocketAddress address = new UnixSocketAddress(path); + UnixServerSocketChannel channel = UnixServerSocketChannel.open(); + + try { + Selector sel = NativeSelectorProvider.getInstance().openSelector(); + channel.configureBlocking(false); + channel.socket().bind(address); + channel.register(sel, SelectionKey.OP_ACCEPT, new ServerActor(channel, sel)); + + while (sel.select() > 0) { + Set keys = sel.selectedKeys(); + for (SelectionKey k : keys) { + Actor a = (Actor) k.attachment(); + if (!a.rxready()) { + k.cancel(); + } + } + } + } catch (IOException ex) { + Logger.getLogger(UnixServerSocket.class.getName()).log(Level.SEVERE, null, ex); + } + + } + + static interface Actor { + public boolean rxready(); + } + + static final class ServerActor implements Actor { + private final UnixServerSocketChannel channel; + private final Selector selector; + + public ServerActor(UnixServerSocketChannel channel, Selector selector) { + this.channel = channel; + this.selector = selector; + } + public final boolean rxready() { + try { + UnixSocketChannel client = channel.accept(); + client.configureBlocking(false); + client.register(selector, SelectionKey.OP_READ, new ClientActor(client)); + return true; + } catch (IOException ex) { + return false; + } + } + } + static final class ClientActor implements Actor { + private final UnixSocketChannel channel; + + public ClientActor(UnixSocketChannel channel) { + this.channel = channel; + } + + public final boolean rxready() { + try { + ByteBuffer buf = ByteBuffer.allocate(1024); + int n = channel.read(buf); + UnixSocketAddress remote = channel.getRemoteSocketAddress(); + System.out.printf("Read in %d bytes from %s\n", n, remote); + + if (n > 0) { + buf.flip(); + channel.write(buf); + return true; + } else if (n < 0) { + return false; + } + + } catch (IOException ex) { + ex.printStackTrace(); + return false; + } + return true; + } + } +} diff -Nru jnr-unixsocket-0.3/.travis.yml jnr-unixsocket-0.8/.travis.yml --- jnr-unixsocket-0.3/.travis.yml 2013-04-03 00:45:01.000000000 +0000 +++ jnr-unixsocket-0.8/.travis.yml 2015-05-04 19:05:51.000000000 +0000 @@ -2,3 +2,11 @@ jdk: - oraclejdk7 - openjdk6 +notifications: + irc: + channels: + - "irc.freenode.org#jnr" + on_success: change + on_failure: always + template: + - "%{repository} (%{branch}:%{commit} by %{author}): %{message} (%{build_url})"