package com.limegroup.gnutella;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Properties;
import junit.framework.Test;
import com.limegroup.gnutella.handshaking.HandshakeResponder;
import com.limegroup.gnutella.handshaking.HandshakeResponse;
import com.limegroup.gnutella.handshaking.HeaderNames;
import com.limegroup.gnutella.handshaking.StubHandshakeResponder;
import com.limegroup.gnutella.handshaking.UltrapeerHandshakeResponder;
import com.limegroup.gnutella.handshaking.UltrapeerHeaders;
import com.limegroup.gnutella.io.AcceptObserver;
import com.limegroup.gnutella.io.NIOServerSocket;
import com.limegroup.gnutella.messages.Message;
import com.limegroup.gnutella.messages.PingReply;
import com.limegroup.gnutella.messages.PingRequest;
import com.limegroup.gnutella.messages.QueryRequest;
import com.limegroup.gnutella.settings.ConnectionSettings;
import com.limegroup.gnutella.settings.FilterSettings;
import com.limegroup.gnutella.stubs.ActivityCallbackStub;
import com.limegroup.gnutella.util.IOUtils;
import com.limegroup.gnutella.util.ThreadFactory;
/**
* Tests basic connection properties. All tests are done once with compression
* and once without.
*/
public class ManagedConnectionTest extends ServerSideTestCase {
private static final int LISTEN_PORT = 12350;
public ManagedConnectionTest(String name) {
super(name);
}
public static Test suite() {
return buildTestSuite(ManagedConnectionTest.class);
}
public static void main(String argv[]) {
junit.textui.TestRunner.run(suite());
}
public static Integer numUPs() {
return new Integer(0);
}
public static Integer numLeaves() {
return new Integer(0);
}
public static ActivityCallback getActivityCallback() {
return new ActivityCallbackStub();
}
public static void setUpQRPTables() {}
/**
* Tests the method for checking whether or not a connection is stable.
*/
public void testIsStable() throws Exception {
Connection conn = createLeafConnection();
assertTrue("should not yet be considered stable", !conn.isStable());
Thread.sleep(6000);
assertTrue("connection should be considered stable", conn.isStable());
conn.close();
// Keep in mind that Connection is a loopback
// connection! That means Acceptor creates a
// second ManagedConnection instance for the
// incoming connection. Give that instance a
// bit time to die or the next test will fail
// frequently.
Thread.sleep(500);
}
public void testConnectionStatsRecorded() throws Exception {
ConnectionManager cm = RouterService.getConnectionManager();
assertEquals(0, cm.getNumConnections());
Connection in = createLeafConnection();
drain(in);
assertEquals(1, cm.getNumConnections());
ManagedConnection out = (ManagedConnection)cm.getConnections().get(0);
PingRequest pr=null;
long start=0;
long elapsed=0;
// Record initial msgs.
int initialNumSent = out.getNumMessagesSent();
long initialBytesSent = out.getUncompressedBytesSent();
long initialBytesRecv = in.getUncompressedBytesReceived();
pr=new PingRequest((byte)3);
out.send(pr);
start=System.currentTimeMillis();
pr=(PingRequest)in.receive();
elapsed=System.currentTimeMillis()-start;
assertEquals("unexpected number of sent messages", initialNumSent + 1, out.getNumMessagesSent());
assertEquals( initialBytesRecv + pr.getTotalLength(), in.getUncompressedBytesReceived() );
// due to delay in updating, this stat is off always.
//assertEquals( initialBytesSent + pr.getTotalLength(), out.getUncompressedBytesSent() );
assertLessThan("Unreasonably long send time", 500, elapsed);
assertEquals("hopped something other than 0", 0, pr.getHops());
assertEquals("unexpected ttl", 3, pr.getTTL());
out.close();
in.close();
}
public void testForwardsGGEP() throws Exception {
ConnectionManager cm = RouterService.getConnectionManager();
assertEquals(0, cm.getNumConnections());
Connection conn = createLeafConnection();
drain(conn);
assertEquals(1, cm.getNumConnections());
Connection out = (Connection)cm.getConnections().get(0);
assertTrue("connection should support GGEP", out.supportsGGEP());
out.send(PingReply.create(GUID.makeGuid(), (byte)1));
Message m = getFirstInstanceOfMessageType(conn, PingReply.class);
assertNotNull(m);
assertInstanceof("should be a pong", PingReply.class, m);
PingReply pr = (PingReply)m;
assertTrue("pong should have GGEP", pr.hasGGEPExtension());
assertTrue("should not support unicast", !pr.supportsUnicast());
assertTrue("incorrect daily uptime!", pr.getDailyUptime() > 0);
assertEquals("unexpected vendor", "LIME", pr.getVendor());
assertTrue("pong should have GGEP", pr.hasGGEPExtension());
out.close();
conn.close();
}
/**
* Tests the method for checking whether or not the connection is a high-
* degree connection that maintains high numbers of intra-Ultrapeer
* connections.
*/
public void testIsHighDegreeConnection() throws Exception {
Connection conn = createLeafConnection();
assertTrue("connection should be high degree", conn.isHighDegreeConnection());
conn.close();
}
public void testStripsGGEP() throws Exception {
ConnectionManager cm = RouterService.getConnectionManager();
assertEquals(0, cm.getNumConnections());
Connection conn = createConnection(new NoGGEPProperties());
drain(conn);
assertEquals(1, cm.getNumConnections());
Connection out = (Connection)cm.getConnections().get(0);
assertFalse("connection should supportn't GGEP", out.supportsGGEP());
out.send(PingReply.create(GUID.makeGuid(), (byte)1));
Message m = getFirstInstanceOfMessageType(conn, PingReply.class);
assertNotNull(m);
assertInstanceof("should be a pong", PingReply.class, m);
PingReply pr = (PingReply)m;
assertTrue("pong should not have GGEP", !pr.hasGGEPExtension());
assertTrue("should not have ggep block", !pr.supportsUnicast());
assertEquals("incorrect daily uptime!", -1, pr.getDailyUptime());
out.close();
conn.close();
}
// Tests to make sure that connections are closed correctly from the
// client side.
public void testClientSideClose() throws Exception {
ConnectionManager cm = RouterService.getConnectionManager();
assertEquals(0, cm.getNumConnections());
Connection out = createLeafConnection();
drain(out);
assertEquals(1, cm.getNumConnections());
Connection in = (Connection)cm.getConnections().get(0);
//in=acceptor.accept();
assertTrue("connection should be open", out.isOpen());
out.close();
Thread.sleep(100);
assertTrue("connection should not be open", !out.isOpen());
Thread.sleep(100);
assertTrue(!in.isOpen());
}
// Tests to make sure that connections are closed correctly from the
// server side.
public void testServerSideClose() throws Exception {
ConnectionManager cm = RouterService.getConnectionManager();
assertEquals(0, cm.getNumConnections());
Connection out = createLeafConnection();
drain(out);
assertEquals(1, cm.getNumConnections());
Connection in = (Connection)cm.getConnections().get(0);
assertTrue("connection should be open", out.isOpen());
out.close();
Message m = new PingRequest((byte)4);
m.hop();
in.send(m);
Thread.sleep(500);
in.send(new PingRequest((byte)4));
Thread.sleep(500);
in.send(new PingRequest((byte)4));
Thread.sleep(500);
assertTrue("connection should not be open", !in.isOpen());
Thread.sleep(2000);
}
public void testHashFiltering() throws Exception {
URN sha1 = URN.createSHA1Urn("urn:sha1:PLSTHIPQGSSZTS5FJUPAKUZWUGYQYPFB");
QueryRequest urnFile = QueryRequest.createQuery(sha1,"java");
ManagedConnection mc = new ManagedConnection("", 1);
// default should be no filtering
assertFalse(mc.isSpam(urnFile));
// now turn filtering on and rebuild filters
FilterSettings.FILTER_HASH_QUERIES.setValue(true);
mc = new ManagedConnection("", 1);
assertTrue(mc.isSpam(urnFile));
FilterSettings.FILTER_HASH_QUERIES.setValue(false);
}
public void testNonBlockingHandshakeSucceeds() throws Exception {
ManagedConnection mc = new ManagedConnection("127.0.0.1", LISTEN_PORT);
ConnectionAcceptor acceptor = new ConnectionAcceptor();
StubGnetConnectObserver observer = new StubGnetConnectObserver();
acceptor.start();
ConnectionSettings.PREFERENCING_ACTIVE.setValue(false);
try {
mc.initialize(observer);
observer.waitForResponse(5000);
assertTrue(observer.isConnect());
assertFalse(observer.isBadHandshake());
assertFalse(observer.isNoGOK());
assertFalse(observer.isShutdown());
assertEquals("NIODispatcher", observer.getFinishedThread().getName());
mc.close();
} finally {
acceptor.shutdown();
}
}
public void testNonBlockingBadHandshake() throws Exception {
ManagedConnection mc = new ManagedConnection("127.0.0.1", LISTEN_PORT);
ConnectionAcceptor acceptor = new ConnectionAcceptor();
StubGnetConnectObserver observer = new StubGnetConnectObserver();
acceptor.start();
ConnectionSettings.PREFERENCING_ACTIVE.setValue(false);
try {
acceptor.getObserver().setBadHandshake(true);
mc.initialize(observer);
observer.waitForResponse(5000);
assertFalse(observer.isConnect());
assertTrue(observer.isBadHandshake());
assertFalse(observer.isNoGOK());
assertFalse(observer.isShutdown());
assertEquals("NIODispatcher", observer.getFinishedThread().getName());
mc.close();
} finally {
acceptor.shutdown();
}
}
public void testNonBlockingNGOK() throws Exception {
ManagedConnection mc = new ManagedConnection("127.0.0.1", LISTEN_PORT);
ConnectionAcceptor acceptor = new ConnectionAcceptor();
StubGnetConnectObserver observer = new StubGnetConnectObserver();
acceptor.start();
ConnectionSettings.PREFERENCING_ACTIVE.setValue(false);
try {
acceptor.getObserver().setNoGOK(true);
mc.initialize(observer);
observer.waitForResponse(5000);
assertFalse(observer.isConnect());
assertFalse(observer.isBadHandshake());
assertTrue(observer.isNoGOK());
assertEquals(401, observer.getCode());
assertFalse(observer.isShutdown());
assertEquals("NIODispatcher", observer.getFinishedThread().getName());
mc.close();
} finally {
acceptor.shutdown();
}
}
public void testNonBlockingHandshakeTimeout() throws Exception {
ManagedConnection mc = new ManagedConnection("127.0.0.1", LISTEN_PORT);
ConnectionAcceptor acceptor = new ConnectionAcceptor();
StubGnetConnectObserver observer = new StubGnetConnectObserver();
acceptor.start();
ConnectionSettings.PREFERENCING_ACTIVE.setValue(false);
try {
acceptor.getObserver().setTimeout(true);
mc.initialize(observer);
observer.waitForResponse(10000);
assertFalse(observer.isConnect());
assertFalse(observer.isBadHandshake());
assertFalse(observer.isNoGOK());
assertTrue(observer.isShutdown());
assertEquals("NIODispatcher", observer.getFinishedThread().getName());
mc.close();
} finally {
acceptor.shutdown();
}
}
class EmptyResponder implements HandshakeResponder {
public HandshakeResponse respond(HandshakeResponse response,
boolean outgoing) {
Properties props = new Properties();
return HandshakeResponse.createResponse(props);
}
public void setLocalePreferencing(boolean b) {}
}
/**
* Handshake properties indicating no support for GGEP.
*/
private static class NoGGEPProperties extends UltrapeerHeaders {
public NoGGEPProperties() {
super("localhost");
remove(HeaderNames.GGEP);
}
}
private static class ConnectionAcceptor {
private ServerSocket socket;
private SimpleAcceptObserver observer;
public void start() throws Exception {
observer = new SimpleAcceptObserver();
socket = new NIOServerSocket(LISTEN_PORT, observer);
socket.setReuseAddress(true);
}
public void shutdown() throws Exception {
socket.close();
}
public SimpleAcceptObserver getObserver() {
return observer;
}
}
private static class SimpleAcceptObserver implements AcceptObserver {
private boolean noGOK = false;
private boolean timeout = false;
private boolean badHandshake = false;
public void handleIOException(IOException iox) {
}
public void handleAccept(final Socket socket) throws IOException {
ThreadFactory.startThread(new Runnable() {
public void run() {
try {
if (badHandshake) {
socket.close();
return;
}
if(timeout) {
socket.setSoTimeout(60000);
socket.getInputStream().read(new byte[2048]);
return;
}
socket.setSoTimeout(3000);
InputStream in = socket.getInputStream();
String word = IOUtils.readWord(in, 9);
if (!word.equals("GNUTELLA"))
throw new IOException("Bad word: " + word);
if (noGOK) {
socket.getOutputStream().write("GNUTELLA/0.6 401 Failed\r\n\r\n".getBytes());
socket.getOutputStream().flush();
return;
}
final Connection con = new Connection(socket);
con.initialize(null, new StubHandshakeResponder());
} catch (Exception e) {
ErrorService.error(e);
}
}
}, "conninit");
}
public void shutdown() {
}
public void setBadHandshake(boolean badHandshake) {
this.badHandshake = badHandshake;
}
public void setNoGOK(boolean noGOK) {
this.noGOK = noGOK;
}
public void setTimeout(boolean timeout) {
this.timeout = timeout;
}
public void clear() {
this.badHandshake = false;
this.noGOK = false;
this.timeout = false;
}
}
}