package com.limegroup.gnutella;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import com.limegroup.gnutella.handshaking.HandshakeResponder;
import com.limegroup.gnutella.handshaking.UltrapeerHandshakeResponder;
/**
* A handy class for creating incoming connections for in-process tests.
* Typical use:
*
* <pre>
* MiniAcceptor acceptor=new MiniAcceptor(inProperties, 6346);
* Connection out=new Connection("localhost", 6346);
* out.initialize();
* Connection in=acceptor.accept();
*
* out.send(..);
* in.receive();
* in.send(..);
* out.receive(..);
* </pre>
*/
public class MiniAcceptor implements Runnable {
private Object lock=new Object();
private Connection c=null;
private boolean done=false;
private int port;
private IOException error=null;
private HandshakeResponder properties;
/** Starts the listen socket on port 6346 without blocking. */
public MiniAcceptor(HandshakeResponder properties) {
this(properties, 6346);
}
/** Starts the listen socket without blocking. */
public MiniAcceptor(HandshakeResponder properties, int port) {
//ConnectionSettings.NUM_CONNECTIONS.setValue(3);
this.properties=properties;
this.port=port;
Thread runner=new Thread(this);
runner.start();
Thread.yield(); //hack to make sure runner creates socket
}
/** Starts the listen socket without blocking. */
public MiniAcceptor(int port) {
this(new UltrapeerHandshakeResponder("localhost"), port);
}
/** Blocks until a connection is available, and returns it.
* Returns null if something went awry. In this case, you
* can get the exception via getError. Bad design, but
* exists for backwards compatibility. */
public Connection accept() {
synchronized (lock) {
while (! done) {
try {
lock.wait();
} catch (InterruptedException e) {
return null;
}
}
return c;
}
}
public IOException getError() {
return error;
}
/** Don't call. For internal use only. */
public void run() {
ServerSocket ss=null;
try {
ss=new ServerSocket(port);
ss.setReuseAddress(true);
Socket s=ss.accept();
//Technically "GNUTELLA " should be read from s. Turns out that
//out implementation doesn't care;
Connection c=new Connection(s);
c.initialize(null, properties);
ss.close();
synchronized (lock) {
this.c=c;
done=true;
lock.notify();
}
} catch (IOException e) {
if (ss==null) {
ErrorService.error(e);
}
error=e; //Record for later.
synchronized (lock) {
done=true;
lock.notify();
}
}
}
}