package com.limegroup.gnutella.guess;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.UnknownHostException;
import junit.framework.Test;
import com.limegroup.gnutella.messages.BadPacketException;
import com.limegroup.gnutella.messages.Message;
import com.limegroup.gnutella.messages.PingReply;
import com.limegroup.gnutella.messages.PingRequest;
import com.limegroup.gnutella.messages.QueryReply;
import com.limegroup.gnutella.messages.QueryRequest;
/** Provides primitives for contacting GUESS nodes on the network.
* THIS TEST SHOULD NOT BE INCLUDED IN ALL TESTS! It is very specifically
* tuned and will now work in general.
*/
public class GUESSTester extends com.limegroup.gnutella.util.BaseTestCase {
/**
* Constant for the size of UDP messages to accept -- dependent upon
* IP-layer fragmentation.
*/
private final int BUFFER_SIZE = 8192;
private final int WAIT_TIME = 500; // 1/2 a second...
private DatagramSocket _socket = null;
private QueryReply _qr = null;
private final Object _qrLock = new Object();
private PingReply _pong = null;
private final Object _pongLock = new Object();
/**
* Constructs a new <tt>GUESSTester</tt> instance.
*/
public GUESSTester(String name) {
super(name);
initUDPPort();
}
private void initUDPPort() {
try {
_socket = new DatagramSocket();
_socket.setSoTimeout(1000);
Thread listener = new Thread() {
public void run() {
listenLoop();
}
};
listener.start();
}
catch (Exception ignored) {
System.out.println("Could not get a UDP Socket!!");
}
}
private void listenLoop() {
byte[] datagramBytes = new byte[BUFFER_SIZE];
DatagramPacket datagram = new DatagramPacket(datagramBytes,
BUFFER_SIZE);
while (true) {
try {
_socket.receive(datagram);
byte[] data = datagram.getData();
int length = datagram.getLength();
try {
// construct a message out of it...
InputStream in = new ByteArrayInputStream(data);
Message message = Message.read(in);
if (message == null) continue;
if (message instanceof QueryReply) {
synchronized (_qrLock) {
_qr = (QueryReply) message;
_qrLock.notify();
}
}
else if (message instanceof PingReply) {
synchronized (_pongLock) {
_pong = (PingReply) message;
_pongLock.notify();
}
}
}
catch(BadPacketException e) {
continue;
}
}
catch (InterruptedIOException e) {
continue;
}
catch (IOException e) {
continue;
}
}
}
/**
* Run this suite of tests.
*/
public static Test suite() {
return buildTestSuite(GUESSTester.class);
}
public void testSmall() {
try {
assertTrue(testAck("10.254.0.19", 6346) > 0);
assertNotNull(testQuery("10.254.0.19", 6346,
QueryRequest.createQuery("morrissey", (byte)1)));
}
catch (Exception whatever) {
assertTrue(false);
}
}
/** This method blocks for possibly several seconds.
* @return a non-negative value if the ack was recieved. else 0...
*/
public synchronized long testAck(String host, int port)
throws UnknownHostException, IOException {
synchronized (_pongLock) {
_pong = null;
}
QueryRequest qr = QueryRequest.createQuery("susheel", (byte)1);
InetAddress addr = InetAddress.getByName(host);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
qr.write(baos);
DatagramPacket toSend = new DatagramPacket(baos.toByteArray(),
baos.toByteArray().length,
addr, port);
long startTime = 0, endTime = 0;
synchronized (_pongLock) {
startTime = System.currentTimeMillis();
_socket.send(toSend);
try {
// wait up to 2.5 seconds for an ack....
_pongLock.wait(WAIT_TIME);
}
catch (InterruptedException ignored) {}
endTime = System.currentTimeMillis();
}
if (_pong == null)
return 0;
else return (endTime - startTime);
}
/** This method blocks for possibly several seconds.
* @return a non-negative value if the ack was recieved. else 0...
*/
public synchronized long testPing(String host, int port)
throws UnknownHostException, IOException {
synchronized (_pongLock) {
_pong = null;
}
PingRequest pr = new PingRequest((byte)1);
InetAddress addr = InetAddress.getByName(host);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
pr.write(baos);
DatagramPacket toSend = new DatagramPacket(baos.toByteArray(),
baos.toByteArray().length,
addr, port);
long startTime = 0, endTime = 0;
synchronized (_pongLock) {
startTime = System.currentTimeMillis();
_socket.send(toSend);
try {
// wait up to WAIT_TIME seconds for an ack....
_pongLock.wait(WAIT_TIME);
}
catch (InterruptedException ignored) {}
endTime = System.currentTimeMillis();
}
if (_pong == null)
return 0;
else return (endTime - startTime);
}
/** This method blocks for possibly several seconds.
* @return A QueryReply to your input Query. May be null.
*/
public synchronized QueryReply testQuery(String host, int port,
QueryRequest qr)
throws UnknownHostException, IOException {
synchronized (_qrLock) {
_qr = null;
}
synchronized (_pongLock) {
_pong = null;
}
InetAddress addr = InetAddress.getByName(host);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
qr.write(baos);
DatagramPacket toSend = new DatagramPacket(baos.toByteArray(),
baos.toByteArray().length,
addr, port);
synchronized (_qrLock) {
_socket.send(toSend);
try {
// wait up to 2.5 seconds for an ack....
_qrLock.wait(WAIT_TIME);
}
catch (InterruptedException ignored) {}
}
return _qr;
}
public static final boolean debugOn = true;
public static final void debug(String out) {
if (debugOn)
System.out.println(out);
}
}