package com.limegroup.gnutella;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.Vector;
import com.limegroup.gnutella.guess.GUESSStatistics;
import com.limegroup.gnutella.messages.PingReply;
import com.limegroup.gnutella.stubs.ActivityCallbackStub;
import com.limegroup.gnutella.util.BaseTestCase;
import com.limegroup.gnutella.util.Buffer;
import com.limegroup.gnutella.util.NetworkUtils;
/** Starts a BackEnd (which should have a .props file configured to be an
* Ultrapeer) and any time it gets a pong from a GUESS Ultrapeer, it sends
* it a query and take statistics on how many acks it recieves.
* It seems like you need to start this guy from a directory which has a com
* underneath it.
* If you run main, this will stop when you enter anything and press RETURN.
*/
public class GUESSMonitor extends BaseTestCase {
public final static String INSTRUCTIONS =
"? - Help; verbose - switch verbose on/off; connect - start the " +
"backend; disconnect - stop the backend; stats - show stats";
private RouterService _backend;
private MyMessageRouter _messageRouter;
public GUESSMonitor() {
super("GUESS MONITOR");
setStandardSettings();
// make my own MessageRouter....
ActivityCallback stub = new ActivityCallbackStub();
_messageRouter = new MyMessageRouter();
_backend = new RouterService(stub, _messageRouter);
//_backend = Backend.createLongLivedBackend(stub, _messageRouter);
_backend.start();
//RouterService.forceKeepAlive(8);
//_backend.getRouterService().forceKeepAlive(5);
}
public void shutdown() {
_messageRouter.shutdown();
_messageRouter.join();
RouterService.shutdown();
}
public void connect() {
//_backend.getRouterService().connect();
//_backend.getRouterService().forceKeepAlive(5);
RouterService.connect();
//RouterService.forceKeepAlive(5);
}
public void disconnect() {
//_backend.getRouterService().disconnect();
RouterService.disconnect();
}
public static void main(String argv[]) throws Exception {
System.out.println("Type 'quit' to Exit....");
GUESSMonitor guessMon = new GUESSMonitor();
// open up standard input
String input = "";
BufferedReader br =
new BufferedReader(new InputStreamReader(System.in));
System.out.println("Ready - Type '?' for Help.");
while (!input.equals("quit")) {
System.out.print("% ");
try {
input = br.readLine(); // just wait for input...
if (input.equals("?"))
System.out.println(INSTRUCTIONS);
else if (input.equals("verbose"))
guessMon.switchDebug();
else if (input.equals("connect"))
guessMon.connect();
else if (input.equals("disconnect"))
guessMon.disconnect();
else if (input.equals("stats"))
guessMon.showOverallStats();
else if (input.equals(""))
;
else
System.out.println("Unknown Command, type '?' for Help.");
}
catch (IOException ioe) {
}
}
guessMon.shutdown();
}
private class MyMessageRouter extends StandardMessageRouter {
private List _guessPongs = new Vector();
private Set _uniqueHosts = Collections.synchronizedSet(new HashSet());
private Set _badHosts = Collections.synchronizedSet(new HashSet());
private Buffer _lastFiveHosts = new Buffer(5);
private boolean _shouldRun = true;
public void shutdown() {
_shouldRun = false;
_pongLoop.interrupt();
}
private Thread _pongLoop = null;
public void join() {
try {
_pongLoop.join();
}
catch (Exception ignored) {}
}
public MyMessageRouter() {
super();
_pongLoop = new Thread() {
public void run() {
guessPongLoop();
}
};
_pongLoop.start();
}
protected void handlePingReply(PingReply reply,
ReplyHandler handler) {
super.handlePingReply(reply, handler);
if (!NetworkUtils.isPrivateAddress(reply.getIPBytes()) &&
notMe(reply.getInetAddress(), reply.getPort()) &&
reply.supportsUnicast()) {
synchronized (_guessPongs) {
_guessPongs.add(reply);
_guessPongs.notify();
}
}
}
private void guessPongLoop() {
debug("guessPongLoop(): starting.");
while (_shouldRun) {
synchronized (_guessPongs) {
while (_shouldRun && _guessPongs.size() == 0) {
try {
_guessPongs.wait();
}
catch (InterruptedException ignored) {}
}
}
if (_shouldRun && (_guessPongs.size() > 0)) {
PingReply currPong = (PingReply) _guessPongs.remove(0);
if (_badHosts.contains(currPong.getInetAddress()))
continue;
{
// don't hit the same guys too often.....
if (_lastFiveHosts.contains(currPong.getInetAddress()))
continue;
_lastFiveHosts.addFirst(currPong.getInetAddress());
}
debug("guessPongLoop(): consuming Pong = " + currPong);
Object[] retObjs =
GUESSStatistics.getAckStatistics(currPong.getAddress(),
currPong.getPort());
float numSent = ((Float)retObjs[1]).floatValue();
float numGot = ((Float)retObjs[0]).floatValue();
float averageTime = ((Float)retObjs[2]).floatValue();
float successRate = (numGot/numSent)*100;
tallyStats(numGot, averageTime, successRate);
// also keep track of unique tests done....
if (!_uniqueHosts.contains(currPong.getInetAddress())) {
_uniqueHosts.add(currPong.getInetAddress());
if (numGot == 0)
_badHosts.add(currPong.getInetAddress());
else
goodGUESSers++;
}
debug("Sent Queries to " + currPong.getInetAddress() + ":" +
currPong.getPort() + " . " + "Success Rate = " +
successRate + " at an average of " +
averageTime + " ms per Query.");
try {
Thread.sleep(500); // wait a little, don't kill guys....
}
catch (InterruptedException ignored) {}
}
}
debug("guessPongLoop(): returning.");
}
}
/* Numbers for maintaining stats...
*/
private float numTestsDone = 0;
private float numSuccessTests = 0;
private float overallSuccessRate = 0;
private float overallLatency = 0;
private float goodGUESSers = 0;
private synchronized void tallyStats(float numGot,
float averageTime, float successRate) {
if (numGot > 0) {
numSuccessTests++;
overallSuccessRate =
((overallSuccessRate*numTestsDone) + successRate) /
(numTestsDone+1);
overallLatency =
((overallLatency*numTestsDone) + averageTime) /
(numTestsDone+1);
}
numTestsDone++;
}
public synchronized void showOverallStats() {
System.out.println("---- STATS -----");
System.out.println("Current Time: " +
Calendar.getInstance().getTime());
System.out.println("Number of Tests : " + numTestsDone);
if (numSuccessTests > 0) {
float uniqueHostsSize = _messageRouter._uniqueHosts.size();
System.out.println("Overall Throughput Rate : " +
overallSuccessRate +
"%");
System.out.println("Overall Latency : " + overallLatency +
"ms");
System.out.println("Number of Unique GUESS-enabled IPs : " +
uniqueHostsSize);
System.out.println("Percentage of GUESS IPs that work : " +
(goodGUESSers/uniqueHostsSize)*100 +
"%");
}
System.out.println("----------------");
}
/**
* Returns whether or not the Endpoint refers to me! True if it doesn't,
* false if it does (NOT not me == me).
*/
private boolean notMe(InetAddress address, int port) {
boolean retVal = true;
if ((port == RouterService.getPort()) &&
Arrays.equals(address.getAddress(),
RouterService.getAddress())) {
retVal = false;
}
return retVal;
}
private boolean debugOn = false;
private void debug(String out) {
if (debugOn) {
System.out.println(out);
}
}
public void switchDebug() {
debugOn = !debugOn;
}
}