From 432ee0d8593d9f9ee96158d66b50a5494070216d Mon Sep 17 00:00:00 2001 From: Fritz Elfert Date: Fri, 4 Nov 2016 11:52:00 +0100 Subject: [PATCH] Added more tests --- src/main/java/jnr/unixsocket/Common.java | 16 +- .../jnr/unixsocket/UnixDatagramChannel.java | 9 +- .../BasicDatagramFunctionalityTest.java | 33 ++-- .../jnr/unixsocket/ChannelOptionsTest.java | 143 ++++++++++++++++++ 4 files changed, 175 insertions(+), 26 deletions(-) create mode 100644 src/test/java/jnr/unixsocket/ChannelOptionsTest.java diff --git a/src/main/java/jnr/unixsocket/Common.java b/src/main/java/jnr/unixsocket/Common.java index 8d8b8c0..4e73713 100644 --- a/src/main/java/jnr/unixsocket/Common.java +++ b/src/main/java/jnr/unixsocket/Common.java @@ -112,9 +112,15 @@ static void setSocketOption(int fd, SocketOption name, if (null == value) { throw new IllegalArgumentException("Invalid option value"); } + + jnr.constants.platform.SocketOption optname = wMap.get(name); + if (null == optname) { + throw new AssertionError("Option not found or not writable"); + } + Class type = name.type(); if (type != Integer.class && type != Boolean.class) { - throw new AssertionError("Should not reach here"); + throw new AssertionError("Unsupported option type"); } int optvalue; @@ -131,9 +137,11 @@ static void setSocketOption(int fd, SocketOption name, } } - jnr.constants.platform.SocketOption optname = wMap.get(name); - if (null == optname) { - throw new AssertionError("Option not found"); + if (name == UnixSocketOptions.SO_RCVTIMEO || name == UnixSocketOptions.SO_SNDTIMEO) { + int i = ((Integer)value).intValue(); + if (i < 0) { + throw new IllegalArgumentException("Invalid send/receive timeout"); + } } if (0 != Native.setsockopt(fd, SocketLevel.SOL_SOCKET, optname, optvalue)) { diff --git a/src/main/java/jnr/unixsocket/UnixDatagramChannel.java b/src/main/java/jnr/unixsocket/UnixDatagramChannel.java index 92ec9fb..9c6f604 100644 --- a/src/main/java/jnr/unixsocket/UnixDatagramChannel.java +++ b/src/main/java/jnr/unixsocket/UnixDatagramChannel.java @@ -64,8 +64,8 @@ public static final UnixDatagramChannel[] pair() throws IOException { int[] sockets = { -1, -1 }; Native.socketpair(ProtocolFamily.PF_UNIX, Sock.SOCK_DGRAM, 0, sockets); return new UnixDatagramChannel[] { - new UnixDatagramChannel(sockets[0], State.CONNECTED), - new UnixDatagramChannel(sockets[1], State.CONNECTED) + new UnixDatagramChannel(sockets[0], State.CONNECTED, true), + new UnixDatagramChannel(sockets[1], State.CONNECTED, true) }; } @@ -74,13 +74,14 @@ private UnixDatagramChannel() throws IOException { } UnixDatagramChannel(int fd) { - this(fd, State.IDLE); + this(fd, State.IDLE, false); } - UnixDatagramChannel(int fd, State initialState) { + UnixDatagramChannel(int fd, State initialState, boolean initialBoundState) { super(fd); stateLock.writeLock().lock(); state = initialState; + bound.set(initialBoundState); stateLock.writeLock().unlock(); } diff --git a/src/test/java/jnr/unixsocket/BasicDatagramFunctionalityTest.java b/src/test/java/jnr/unixsocket/BasicDatagramFunctionalityTest.java index 85b30f3..1131b26 100644 --- a/src/test/java/jnr/unixsocket/BasicDatagramFunctionalityTest.java +++ b/src/test/java/jnr/unixsocket/BasicDatagramFunctionalityTest.java @@ -123,26 +123,23 @@ public void doubleBindTest() throws Exception { try { ch.bind(null); fail("Should have thrown AlreadyBoundException"); - } catch (AlreadyBoundException ex) { - } - try { - ch.socket().bind(null); - fail("Should have thrown SocketException"); - } catch (SocketException ex) { - assertEquals("exception message", ex.getMessage(), "already bound"); + } catch (AlreadyBoundException abx) { + try { + ch.socket().bind(null); + fail("Should have thrown SocketException"); + } catch (SocketException sx) { + assertEquals("exception message", sx.getMessage(), "already bound"); + } } } - // Ignore for now @Test - public void socketBufferTest() throws Exception { - UnixDatagramChannel ch = UnixDatagramChannel.open(); - int rxs = ch.getOption(UnixSocketOptions.SO_RCVBUF); - int txs = ch.getOption(UnixSocketOptions.SO_SNDBUF); - System.out.println(String.format("rxbuf=%d, txbuf=%d", rxs, txs)); - ch.setOption(UnixSocketOptions.SO_RCVBUF, rxs - 100); - ch.setOption(UnixSocketOptions.SO_SNDBUF, txs - 100); - rxs = ch.getOption(UnixSocketOptions.SO_RCVBUF); - txs = ch.getOption(UnixSocketOptions.SO_SNDBUF); - System.out.println(String.format("rxbuf=%d, txbuf=%d", rxs, txs)); + @Test + public void pairTest() throws Exception { + UnixDatagramChannel[] sp = UnixDatagramChannel.pair(); + for (final UnixDatagramChannel ch : sp) { + assertTrue("Channel is connected", ch.isConnected()); + assertTrue("Channel is bound", ch.isBound()); + assertFalse("Channel's socket is not closed", ch.socket().isClosed()); + } } } diff --git a/src/test/java/jnr/unixsocket/ChannelOptionsTest.java b/src/test/java/jnr/unixsocket/ChannelOptionsTest.java new file mode 100644 index 0000000..b4ad2e3 --- /dev/null +++ b/src/test/java/jnr/unixsocket/ChannelOptionsTest.java @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2016 Fritz Elfert + * + * (ported from https://github.com/softprops/unisockets/blob/master/unisockets-core/src/main/scala/Socket.scala) + * + * 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 java.io.File; +import java.io.IOException; +import java.net.SocketAddress; +import java.net.SocketException; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.file.Files; +import java.nio.channels.AlreadyBoundException; +import java.nio.channels.DatagramChannel; +import java.nio.charset.StandardCharsets; + +import java.util.Set; + +import org.junit.Assume; +import org.junit.Ignore; +import org.junit.Test; + +import jnr.ffi.Platform; +import jnr.ffi.Platform.OS; + +import static junit.framework.Assert.*; + +public class ChannelOptionsTest { + + @Test + public void readonlyDatagramChannelOptionTest() throws Exception { + UnixDatagramChannel[] sp = UnixDatagramChannel.pair(); + UnixDatagramChannel ch = sp[0]; + Credentials c = ch.socket().getCredentials(); + try { + // SO_PEERCRED is readonly + ch.setOption(UnixSocketOptions.SO_PEERCRED, c); + fail("Should have thrown AssertionError"); + } catch (AssertionError ae) { + assertEquals("exception message", ae.getMessage(), "Option not found or not writable"); + } + } + + @Test + public void readonlySocketChannelOptionTest() throws Exception { + UnixSocketChannel[] sp = UnixSocketChannel.pair(); + UnixSocketChannel ch = sp[0]; + Credentials c = ch.socket().getCredentials(); + try { + // SO_PEERCRED is readonly + ch.setOption(UnixSocketOptions.SO_PEERCRED, c); + fail("Should have thrown AssertionError"); + } catch (AssertionError ae) { + assertEquals("exception message", ae.getMessage(), "Option not found or not writable"); + } + } + + @Test + public void unsupportedChannelOptionTest() throws Exception { + UnixDatagramChannel ch = UnixDatagramChannel.open(); + try { + // SO_KEEPALIVE is suitable only for SOCK_STREAM sockets + ch.getOption(UnixSocketOptions.SO_KEEPALIVE); + fail("Should have thrown UnsupportedOperationException"); + } catch (UnsupportedOperationException uoe) { + assertEquals("exception message", uoe.getMessage(), "'SO_KEEPALIVE' not supported"); + } + } + + @Test + public void keepaliveOptionTest() throws Exception { + UnixSocketChannel ch = UnixSocketChannel.open(); + boolean origValue = ch.getOption(UnixSocketOptions.SO_KEEPALIVE).booleanValue(); + assertEquals("Initial value of SO_KEEPALIVE", origValue, false); + ch.setOption(UnixSocketOptions.SO_KEEPALIVE, Boolean.TRUE); + boolean changedValue = ch.getOption(UnixSocketOptions.SO_KEEPALIVE).booleanValue(); + assertEquals("Changed value of SO_KEEPALIVE", changedValue, true); + ch.setOption(UnixSocketOptions.SO_KEEPALIVE, Boolean.FALSE); + changedValue = ch.getOption(UnixSocketOptions.SO_KEEPALIVE).booleanValue(); + assertEquals("Changed value of SO_KEEPALIVE", changedValue, origValue); + } + + @Test + public void invalidOptionValueTest() throws Exception { + UnixSocketChannel ch = UnixSocketChannel.open(); + try { + ch.setOption(UnixSocketOptions.SO_RCVTIMEO, Integer.valueOf(-1)); + fail("Should have thrown IllegalArgumentException"); + } catch (IllegalArgumentException iae) { + assertEquals("exception message", iae.getMessage(), "Invalid send/receive timeout"); + } + try { + ch.setOption(UnixSocketOptions.SO_SNDTIMEO, Integer.valueOf(-1)); + fail("Should have thrown IllegalArgumentException"); + } catch (IllegalArgumentException iae) { + assertEquals("exception message", iae.getMessage(), "Invalid send/receive timeout"); + } + try { + ch.setOption(UnixSocketOptions.SO_RCVBUF, Integer.valueOf(-1)); + fail("Should have thrown IllegalArgumentException"); + } catch (IllegalArgumentException iae) { + assertEquals("exception message", iae.getMessage(), "Invalid send/receive buffer size"); + } + try { + ch.setOption(UnixSocketOptions.SO_SNDBUF, Integer.valueOf(-1)); + fail("Should have thrown IllegalArgumentException"); + } catch (IllegalArgumentException iae) { + assertEquals("exception message", iae.getMessage(), "Invalid send/receive buffer size"); + } + } + + @Test + @Ignore + // Linux doubles the values when setting. Check what other platforms do. + public void socketBufferTest() throws Exception { + UnixDatagramChannel ch = UnixDatagramChannel.open(); + int rxs = ch.getOption(UnixSocketOptions.SO_RCVBUF); + int txs = ch.getOption(UnixSocketOptions.SO_SNDBUF); + System.out.println(String.format("rxbuf=%d, txbuf=%d", rxs, txs)); + ch.setOption(UnixSocketOptions.SO_RCVBUF, rxs - 100); + ch.setOption(UnixSocketOptions.SO_SNDBUF, txs - 100); + rxs = ch.getOption(UnixSocketOptions.SO_RCVBUF); + txs = ch.getOption(UnixSocketOptions.SO_SNDBUF); + System.out.println(String.format("rxbuf=%d, txbuf=%d", rxs, txs)); + } +}