blob: 4665f71feb052f2fd61e9dc977f2fc9dd7d374e3 [file] [log] [blame]
//
// ========================================================================
// Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.io;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.FileChannel;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;
import java.nio.file.StandardOpenOption;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.toolchain.test.OS;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.IO;
import org.junit.Assert;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
public class IOTest
{
@Test
public void testIO() throws Exception
{
// Only a little test
ByteArrayInputStream in = new ByteArrayInputStream("The quick brown fox jumped over the lazy dog".getBytes());
ByteArrayOutputStream out = new ByteArrayOutputStream();
IO.copy(in, out);
assertEquals("copyThread", out.toString(), "The quick brown fox jumped over the lazy dog");
}
@Test
public void testHalfClose() throws Exception
{
ServerSocket connector = new ServerSocket(0);
Socket client = new Socket("localhost", connector.getLocalPort());
Socket server = connector.accept();
// we can write both ways
client.getOutputStream().write(1);
assertEquals(1, server.getInputStream().read());
server.getOutputStream().write(1);
assertEquals(1, client.getInputStream().read());
// shutdown output results in read -1
client.shutdownOutput();
assertEquals(-1, server.getInputStream().read());
// Even though EOF has been read, the server input is not seen as shutdown
assertFalse(server.isInputShutdown());
// and we can read -1 again
assertEquals(-1, server.getInputStream().read());
// but cannot write
try
{
client.getOutputStream().write(1);
fail("exception expected");
}
catch (SocketException e)
{
}
// but can still write in opposite direction.
server.getOutputStream().write(1);
assertEquals(1, client.getInputStream().read());
// server can shutdown input to match the shutdown out of client
server.shutdownInput();
// now we EOF instead of reading -1
try
{
server.getInputStream().read();
fail("exception expected");
}
catch (SocketException e)
{
}
// but can still write in opposite direction.
server.getOutputStream().write(1);
assertEquals(1, client.getInputStream().read());
// client can shutdown input
client.shutdownInput();
// now we EOF instead of reading -1
try
{
client.getInputStream().read();
fail("exception expected");
}
catch (SocketException e)
{
}
// But we can still write at the server (data which will never be read)
server.getOutputStream().write(1);
// and the server output is not shutdown
assertFalse(server.isOutputShutdown());
// until we explictly shut it down
server.shutdownOutput();
// and now we can't write
try
{
server.getOutputStream().write(1);
fail("exception expected");
}
catch (SocketException e)
{
}
// but the sockets are still open
assertFalse(client.isClosed());
assertFalse(server.isClosed());
// but if we close one end
client.close();
// it is seen as closed.
assertTrue(client.isClosed());
// but not the other end
assertFalse(server.isClosed());
// which has to be closed explictly
server.close();
assertTrue(server.isClosed());
}
@Test
public void testHalfCloseClientServer() throws Exception
{
ServerSocketChannel connector = ServerSocketChannel.open();
connector.socket().bind(null);
Socket client = SocketChannel.open(connector.socket().getLocalSocketAddress()).socket();
client.setSoTimeout(1000);
client.setSoLinger(false, -1);
Socket server = connector.accept().socket();
server.setSoTimeout(1000);
server.setSoLinger(false, -1);
// Write from client to server
client.getOutputStream().write(1);
// Server reads
assertEquals(1, server.getInputStream().read());
// Write from server to client with oshut
server.getOutputStream().write(1);
// System.err.println("OSHUT "+server);
server.shutdownOutput();
// Client reads response
assertEquals(1, client.getInputStream().read());
try
{
// Client reads -1 and does ishut
assertEquals(-1, client.getInputStream().read());
assertFalse(client.isInputShutdown());
//System.err.println("ISHUT "+client);
client.shutdownInput();
// Client ???
//System.err.println("OSHUT "+client);
client.shutdownOutput();
//System.err.println("CLOSE "+client);
client.close();
// Server reads -1, does ishut and then close
assertEquals(-1, server.getInputStream().read());
assertFalse(server.isInputShutdown());
//System.err.println("ISHUT "+server);
try
{
server.shutdownInput();
}
catch (SocketException e)
{
// System.err.println(e);
}
//System.err.println("CLOSE "+server);
server.close();
}
catch (Exception e)
{
System.err.println(e);
assertTrue(OS.IS_OSX);
}
}
@Test
public void testHalfCloseBadClient() throws Exception
{
ServerSocketChannel connector = ServerSocketChannel.open();
connector.socket().bind(null);
Socket client = SocketChannel.open(connector.socket().getLocalSocketAddress()).socket();
client.setSoTimeout(1000);
client.setSoLinger(false, -1);
Socket server = connector.accept().socket();
server.setSoTimeout(1000);
server.setSoLinger(false, -1);
// Write from client to server
client.getOutputStream().write(1);
// Server reads
assertEquals(1, server.getInputStream().read());
// Write from server to client with oshut
server.getOutputStream().write(1);
//System.err.println("OSHUT "+server);
server.shutdownOutput();
try
{
// Client reads response
assertEquals(1, client.getInputStream().read());
// Client reads -1
assertEquals(-1, client.getInputStream().read());
assertFalse(client.isInputShutdown());
// Client can still write as we are half closed
client.getOutputStream().write(1);
// Server can still read
assertEquals(1, server.getInputStream().read());
// Server now closes
server.close();
// Client still reads -1 (not broken pipe !!)
assertEquals(-1, client.getInputStream().read());
assertFalse(client.isInputShutdown());
Thread.sleep(100);
// Client still reads -1 (not broken pipe !!)
assertEquals(-1, client.getInputStream().read());
assertFalse(client.isInputShutdown());
// Client can still write data even though server is closed???
client.getOutputStream().write(1);
// Client eventually sees Broken Pipe
int i = 0;
try
{
for (i = 0; i < 100000; i++)
client.getOutputStream().write(1);
Assert.fail();
}
catch (IOException e)
{
}
client.close();
}
catch (Exception e)
{
System.err.println("PLEASE INVESTIGATE:");
e.printStackTrace();
}
}
@Test
public void testServerChannelInterrupt() throws Exception
{
final ServerSocketChannel connector = ServerSocketChannel.open();
connector.configureBlocking(true);
connector.socket().bind(null);
Socket client = SocketChannel.open(connector.socket().getLocalSocketAddress()).socket();
client.setSoTimeout(2000);
client.setSoLinger(false, -1);
Socket server = connector.accept().socket();
server.setSoTimeout(2000);
server.setSoLinger(false, -1);
// Write from client to server
client.getOutputStream().write(1);
// Server reads
assertEquals(1, server.getInputStream().read());
// Write from server to client
server.getOutputStream().write(1);
// Client reads
assertEquals(1, client.getInputStream().read());
// block a thread in accept
final CountDownLatch alatch=new CountDownLatch(2);
Thread acceptor = new Thread()
{
@Override
public void run()
{
try
{
alatch.countDown();
connector.accept();
}
catch (Throwable e)
{
}
finally
{
alatch.countDown();
}
}
};
acceptor.start();
while (alatch.getCount()==2)
Thread.sleep(10);
// interrupt the acceptor
acceptor.interrupt();
// wait for acceptor to exit
assertTrue(alatch.await(10,TimeUnit.SECONDS));
// connector is closed
assertFalse(connector.isOpen());
// but connection is still open
assertFalse(client.isClosed());
assertFalse(server.isClosed());
// Write from client to server
client.getOutputStream().write(42);
// Server reads
assertEquals(42, server.getInputStream().read());
// Write from server to client
server.getOutputStream().write(43);
// Client reads
assertEquals(43, client.getInputStream().read());
client.close();
}
@Test
public void testReset() throws Exception
{
try (ServerSocket connector = new ServerSocket(0);
Socket client = new Socket("127.0.0.1", connector.getLocalPort());
Socket server = connector.accept();)
{
client.setTcpNoDelay(true);
client.setSoLinger(true, 0);
server.setTcpNoDelay(true);
server.setSoLinger(true, 0);
client.getOutputStream().write(1);
assertEquals(1, server.getInputStream().read());
server.getOutputStream().write(1);
assertEquals(1, client.getInputStream().read());
// Server generator shutdowns output after non persistent sending response.
server.shutdownOutput();
// client endpoint reads EOF and shutdown input as result
assertEquals(-1, client.getInputStream().read());
client.shutdownInput();
// client connection see's EOF and shutsdown output as no more requests to be sent.
client.shutdownOutput();
// Since input already shutdown, client also closes socket.
client.close();
// Server reads the EOF from client oshut and shut's down it's input
assertEquals(-1, server.getInputStream().read());
server.shutdownInput();
// Since output was already shutdown, server closes
server.close();
}
}
@Test
public void testAsyncSocketChannel() throws Exception
{
AsynchronousServerSocketChannel connector = AsynchronousServerSocketChannel.open();
connector.bind(null);
InetSocketAddress addr=(InetSocketAddress)connector.getLocalAddress();
Future<AsynchronousSocketChannel> acceptor = connector.accept();
AsynchronousSocketChannel client = AsynchronousSocketChannel.open();
client.connect(new InetSocketAddress("127.0.0.1",addr.getPort())).get(5, TimeUnit.SECONDS);
AsynchronousSocketChannel server = acceptor.get(5, TimeUnit.SECONDS);
ByteBuffer read = ByteBuffer.allocate(1024);
Future<Integer> reading = server.read(read);
byte[] data = "Testing 1 2 3".getBytes(StandardCharsets.UTF_8);
ByteBuffer write = BufferUtil.toBuffer(data);
Future<Integer> writing = client.write(write);
writing.get(5, TimeUnit.SECONDS);
reading.get(5, TimeUnit.SECONDS);
read.flip();
Assert.assertEquals(ByteBuffer.wrap(data), read);
}
@Test
public void testGatherWrite() throws Exception
{
File dir = MavenTestingUtils.getTargetTestingDir();
if (!dir.exists())
dir.mkdir();
File file = File.createTempFile("test",".txt",dir);
file.deleteOnExit();
FileChannel out = FileChannel.open(file.toPath(),
StandardOpenOption.CREATE,
StandardOpenOption.READ,
StandardOpenOption.WRITE,
StandardOpenOption.DELETE_ON_CLOSE);
ByteBuffer[] buffers = new ByteBuffer[4096];
long expected=0;
for (int i=0;i<buffers.length;i++)
{
buffers[i]=BufferUtil.toBuffer(i);
expected+=buffers[i].remaining();
}
long wrote = IO.write(out,buffers,0,buffers.length);
assertEquals(expected,wrote);
for (int i=0;i<buffers.length;i++)
assertEquals(0,buffers[i].remaining());
}
}