package com.limegroup.gnutella.handshaking; import java.io.IOException; import java.net.InetAddress; import java.net.Socket; import java.nio.ByteBuffer; import java.util.Map; import java.util.Properties; import junit.framework.Test; import com.limegroup.gnutella.connection.ReadBufferChannel; import com.limegroup.gnutella.connection.WriteBufferChannel; import com.limegroup.gnutella.io.ChannelReadObserver; import com.limegroup.gnutella.io.ChannelWriter; import com.limegroup.gnutella.io.InterestReadChannel; import com.limegroup.gnutella.io.InterestWriteChannel; import com.limegroup.gnutella.io.NIOMultiplexor; import com.limegroup.gnutella.io.ReadObserver; import com.limegroup.gnutella.io.WriteObserver; import com.limegroup.gnutella.util.BaseTestCase; public class AsyncIncomingHandshakerTest extends BaseTestCase { public AsyncIncomingHandshakerTest(String name) { super(name); } public static Test suite() { return buildTestSuite(AsyncIncomingHandshakerTest.class); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public void testSimpleSuccess() throws Exception { ReadBufferChannel reader = new ReadBufferChannel( ("GNUTELLA CONNECT/0.6\r\n" + "RequestHeader: RequestValue\r\n" + "\r\n" + "GNUTELLA/0.6 200 OK DOKIE\r\n" + "ResponseHeader: ResponseValue\r\n" + "\r\n").getBytes()); WriteBufferChannel writer = new WriteBufferChannel(2048); MultiplexingSocket socket = new MultiplexingSocket(reader, writer); Properties outProps = new Properties(); outProps.put("OutHeader", "OutValue"); StubHandshakeResponder responder = new StubHandshakeResponder(new StubHandshakeResponse(200, "OK!", outProps)); StubHandshakeObserver observer = new StubHandshakeObserver(); Handshaker shaker = new AsyncIncomingHandshaker(responder, socket, observer); shaker.shake(); socket.exchange(); // do the transfer! -- simulates NIODispatcher notifying assertFalse(observer.isNoGOK()); assertFalse(observer.isBadHandshake()); assertTrue(observer.isHandshakeFinished()); assertEquals(shaker, observer.getShaker()); Map respondedTo = responder.getRespondedToProps(); assertEquals(respondedTo.toString(), 1, respondedTo.size()); assertEquals("RequestValue", respondedTo.get("RequestHeader")); assertFalse(responder.isOutgoing()); HandshakeResponse read = shaker.getReadHeaders(); assertEquals(2, read.props().size()); assertEquals("RequestValue", read.props().get("RequestHeader")); assertEquals("ResponseValue", read.props().get("ResponseHeader")); HandshakeResponse written = shaker.getWrittenHeaders(); assertEquals(1, written.props().size()); assertEquals("OutValue", written.props().get("OutHeader")); ByteBuffer out = writer.getBuffer(); assertEquals("GNUTELLA/0.6 200 OK!\r\nOutHeader: OutValue\r\n\r\n", new String(out.array(), 0, out.limit())); } public void testBelowPointSixFails() throws Exception { ReadBufferChannel reader = new ReadBufferChannel( ("GNUTELLA CONNECT/0.5\r\n").getBytes()); WriteBufferChannel writer = new WriteBufferChannel(2048); MultiplexingSocket socket = new MultiplexingSocket(reader, writer); StubHandshakeObserver observer = new StubHandshakeObserver(); Handshaker shaker = new AsyncIncomingHandshaker(new StubHandshakeResponder(), socket, observer); shaker.shake(); socket.exchange(); // do the transfer! -- simulates NIODispatcher notifying assertFalse(observer.isNoGOK()); assertTrue(observer.isBadHandshake()); assertFalse(observer.isHandshakeFinished()); assertNull(observer.getShaker()); } public void testAbovePointSixSucceeds() throws Exception { ReadBufferChannel reader = new ReadBufferChannel( ("GNUTELLA CONNECT/0.7\r\n" + "RequestHeader: RequestValue\r\n" + "\r\n" + "GNUTELLA/0.6 200 OK DOKIE\r\n" + "ResponseHeader: ResponseValue\r\n" + "\r\n").getBytes()); WriteBufferChannel writer = new WriteBufferChannel(2048); MultiplexingSocket socket = new MultiplexingSocket(reader, writer); Properties outProps = new Properties(); outProps.put("OutHeader", "OutValue"); StubHandshakeResponder responder = new StubHandshakeResponder(new StubHandshakeResponse(200, "OK!", outProps)); StubHandshakeObserver observer = new StubHandshakeObserver(); Handshaker shaker = new AsyncIncomingHandshaker(responder, socket, observer); shaker.shake(); socket.exchange(); // do the transfer! -- simulates NIODispatcher notifying assertFalse(observer.isNoGOK()); assertFalse(observer.isBadHandshake()); assertTrue(observer.isHandshakeFinished()); assertEquals(shaker, observer.getShaker()); Map respondedTo = responder.getRespondedToProps(); assertEquals(respondedTo.toString(), 1, respondedTo.size()); assertEquals("RequestValue", respondedTo.get("RequestHeader")); assertFalse(responder.isOutgoing()); HandshakeResponse read = shaker.getReadHeaders(); assertEquals(2, read.props().size()); assertEquals("RequestValue", read.props().get("RequestHeader")); assertEquals("ResponseValue", read.props().get("ResponseHeader")); HandshakeResponse written = shaker.getWrittenHeaders(); assertEquals(1, written.props().size()); assertEquals("OutValue", written.props().get("OutHeader")); ByteBuffer out = writer.getBuffer(); assertEquals("GNUTELLA/0.6 200 OK!\r\nOutHeader: OutValue\r\n\r\n", new String(out.array(), 0, out.limit())); } public void testCrawlerDiscosEarly() throws Exception { ReadBufferChannel reader = new ReadBufferChannel( ("GNUTELLA CONNECT/0.6\r\n" + "Crawler: 0.1\r\n" + "\r\n" + // pretend it would have sent a good response, // just to make sure we'll close it anyway. "GNUTELLA/0.6 200 OK DOKIE\r\n" + "ResponseHeader: ResponseValue\r\n" + "\r\n").getBytes()); WriteBufferChannel writer = new WriteBufferChannel(2048); MultiplexingSocket socket = new MultiplexingSocket(reader, writer); StubHandshakeObserver observer = new StubHandshakeObserver(); // make sure that even 'cause of the bad response, we close due to BadHandshake, // not No GOK -- otherwise we can't be sure the response got sent all the way. HandshakeResponse response = new StubHandshakeResponse(HandshakeResponse.CRAWLER_CODE, "Failed", new Properties()); Handshaker shaker = new AsyncIncomingHandshaker(new StubHandshakeResponder(response), socket, observer); shaker.shake(); socket.exchange(); // do the transfer! -- simulates NIODispatcher notifying assertFalse(observer.isNoGOK()); // Not a NGOK assertTrue(observer.isBadHandshake()); // Instead a BadHandshake assertFalse(observer.isHandshakeFinished()); assertNull(observer.getShaker()); } public void testDiscoOnBadResponder() throws Exception { ReadBufferChannel reader = new ReadBufferChannel( ("GNUTELLA CONNECT/0.6\r\n" + "RequestHeader: RequestValue\r\n" + "\r\n").getBytes()); WriteBufferChannel writer = new WriteBufferChannel(2048); MultiplexingSocket socket = new MultiplexingSocket(reader, writer); Properties outProps = new Properties(); outProps.put("OutHeader", "OutValue"); StubHandshakeResponder responder = new StubHandshakeResponder(new StubHandshakeResponse(599, "NOPE", outProps)); StubHandshakeObserver observer = new StubHandshakeObserver(); Handshaker shaker = new AsyncIncomingHandshaker(responder, socket, observer); shaker.shake(); socket.exchange(); // do the transfer! -- simulates NIODispatcher notifying assertTrue(observer.isNoGOK()); assertEquals(599, observer.getCode()); assertFalse(observer.isBadHandshake()); assertFalse(observer.isHandshakeFinished()); assertNull(observer.getShaker()); assertEquals(1, shaker.getReadHeaders().props().size()); assertEquals("RequestValue", shaker.getReadHeaders().props().get("RequestHeader")); assertEquals(1, shaker.getWrittenHeaders().props().size()); assertEquals("OutValue", shaker.getWrittenHeaders().props().get("OutHeader")); } public void testDiscoOnBadResponse() throws Exception { ReadBufferChannel reader = new ReadBufferChannel( ("GNUTELLA CONNECT/0.6\r\n" + "RequestHeader: RequestValue\r\n" + "\r\n" + "GNUTELLA/0.6 333 SUX\r\n" + "ResponseHeader: ResponseValue\r\n" + "\r\n").getBytes()); WriteBufferChannel writer = new WriteBufferChannel(2048); MultiplexingSocket socket = new MultiplexingSocket(reader, writer); Properties outProps = new Properties(); outProps.put("OutHeader", "OutValue"); StubHandshakeResponder responder = new StubHandshakeResponder(new StubHandshakeResponse(200, "OK!", outProps)); StubHandshakeObserver observer = new StubHandshakeObserver(); Handshaker shaker = new AsyncIncomingHandshaker(responder, socket, observer); shaker.shake(); socket.exchange(); // do the transfer! -- simulates NIODispatcher notifying assertTrue(observer.isNoGOK()); assertEquals(333, observer.getCode()); assertFalse(observer.isBadHandshake()); assertFalse(observer.isHandshakeFinished()); assertNull(observer.getShaker()); Map respondedTo = responder.getRespondedToProps(); assertEquals(respondedTo.toString(), 1, respondedTo.size()); assertEquals("RequestValue", respondedTo.get("RequestHeader")); assertFalse(responder.isOutgoing()); HandshakeResponse read = shaker.getReadHeaders(); assertEquals(2, read.props().size()); assertEquals("RequestValue", read.props().get("RequestHeader")); assertEquals("ResponseValue", read.props().get("ResponseHeader")); HandshakeResponse written = shaker.getWrittenHeaders(); assertEquals(1, written.props().size()); assertEquals("OutValue", written.props().get("OutHeader")); ByteBuffer out = writer.getBuffer(); assertEquals("GNUTELLA/0.6 200 OK!\r\nOutHeader: OutValue\r\n\r\n", new String(out.array(), 0, out.limit())); } public void testDiscoOnBadResponseConnectLine() throws Exception { ReadBufferChannel reader = new ReadBufferChannel( ("GNUTELLA CONNECT/0.6\r\n" + "RequestHeader: RequestValue\r\n" + "\r\n" + "HTTP/1.1 543 WHAT ARE YOU DOING?\r\n" + "ResponseHeader: ResponseValue\r\n" + "\r\n").getBytes()); WriteBufferChannel writer = new WriteBufferChannel(2048); MultiplexingSocket socket = new MultiplexingSocket(reader, writer); Properties outProps = new Properties(); outProps.put("OutHeader", "OutValue"); StubHandshakeResponder responder = new StubHandshakeResponder(new StubHandshakeResponse(200, "OK!", outProps)); StubHandshakeObserver observer = new StubHandshakeObserver(); Handshaker shaker = new AsyncIncomingHandshaker(responder, socket, observer); shaker.shake(); socket.exchange(); // do the transfer! -- simulates NIODispatcher notifying assertFalse(observer.isNoGOK()); assertTrue(observer.isBadHandshake()); assertFalse(observer.isHandshakeFinished()); assertNull(observer.getShaker()); Map respondedTo = responder.getRespondedToProps(); assertEquals(respondedTo.toString(), 1, respondedTo.size()); assertEquals("RequestValue", respondedTo.get("RequestHeader")); assertFalse(responder.isOutgoing()); HandshakeResponse read = shaker.getReadHeaders(); assertEquals(1, read.props().size()); assertEquals("RequestValue", read.props().get("RequestHeader")); HandshakeResponse written = shaker.getWrittenHeaders(); assertEquals(1, written.props().size()); assertEquals("OutValue", written.props().get("OutHeader")); ByteBuffer out = writer.getBuffer(); assertEquals("GNUTELLA/0.6 200 OK!\r\nOutHeader: OutValue\r\n\r\n", new String(out.array(), 0, out.limit())); } private static class MultiplexingSocket extends Socket implements NIOMultiplexor { private InterestReadChannel baseReader; private InterestWriteChannel baseWriter; private ReadObserver reader; private WriteObserver writer; MultiplexingSocket(InterestReadChannel baseReader, InterestWriteChannel baseWriter) { this.baseReader = baseReader; this.baseWriter = baseWriter; } public InetAddress getInetAddress() { try { return InetAddress.getByName("127.0.0.1"); } catch(IOException iox) { return null; } } public void setReadObserver(ChannelReadObserver reader) { reader.setReadChannel(baseReader); this.reader = reader; } public void setWriteObserver(ChannelWriter writer) { writer.setWriteChannel(baseWriter); this.writer = writer; } public void exchange() throws IOException { reader.handleRead(); writer.handleWrite(); reader.handleRead(); } } }