/* * Copyright 2002-2016 the original author or authors. * * 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.springframework.integration.ip.tcp.connection; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import java.io.IOException; import java.io.InputStream; import java.net.Socket; import java.net.SocketException; import javax.net.SocketFactory; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.integration.ip.util.TestingUtilities; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; /** * @author Gary Russell * @since 2.0.2 * */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration @DirtiesContext public class SOLingerTests { @Autowired private AbstractServerConnectionFactory inCFNet; @Autowired private AbstractServerConnectionFactory inCFNio; @Autowired private AbstractServerConnectionFactory inCFNetRst; @Autowired private AbstractServerConnectionFactory inCFNioRst; @Autowired private AbstractServerConnectionFactory inCFNetLinger; @Autowired private AbstractServerConnectionFactory inCFNioLinger; @Test public void configOk() { } @Test public void finReceivedNet() { finReceived(inCFNet, false); } @Test public void finReceivedNio() { finReceived(inCFNio, false); } @Test public void rstReceivedNet() { rstReceived(inCFNetRst); } @Test public void rstReceivedNio() { rstReceived(inCFNioRst); } @Test public void finReceivedNetLinger() { finReceived(inCFNetLinger, true); } @Test public void finReceivedNioLinger() { finReceived(inCFNioLinger, true); } private void finReceived(AbstractServerConnectionFactory inCF, boolean hasLinger) { /* * Default (no linger) means the OS may still deliver everything before the * FIN, but it's not guaranteed. */ TestingUtilities.waitListening(inCF, null); int port = inCF.getPort(); try { Socket socket = SocketFactory.getDefault().createSocket("localhost", port); socket.setSoTimeout(10000); String test = "Test\r\n"; socket.getOutputStream().write(test.getBytes()); byte[] buff = new byte[test.length() + 5]; try { readFully(socket.getInputStream(), buff); assertEquals("echo:" + test, new String(buff)); } catch (SocketException se) { if (hasLinger) { fail("SocketException not expected with SO_LINGER"); } else { return; } } int n = socket.getInputStream().read(); // we expect an orderly close assertEquals(-1, n); } catch (Exception e) { e.printStackTrace(); fail("Unexpected Exception " + e.getMessage()); } } private void rstReceived(AbstractServerConnectionFactory inCF) { TestingUtilities.waitListening(inCF, null); int port = inCF.getPort(); try { Socket socket = SocketFactory.getDefault().createSocket("localhost", port); socket.setSoTimeout(10000); String test = "Test\r\n"; socket.getOutputStream().write(test.getBytes()); byte[] buff = new byte[test.length() + 5]; try { // with SO_LINGER=0 we may, or may not, get the data // if we do, verify it is as expected, if not, the RST // arrived before the final data. readFully(socket.getInputStream(), buff); assertEquals("echo:" + test, new String(buff)); socket.getInputStream().read(); fail("Expected SocketException"); } catch (SocketException se) { } } catch (Exception e) { e.printStackTrace(); fail("Unexpected Exception " + e.getMessage()); } } private void readFully(InputStream is, byte[] buff) throws IOException { for (int i = 0; i < buff.length; i++) { buff[i] = (byte) is.read(); } } }