/* This code is part of Freenet. It is distributed under the GNU General
* Public License, version 2 (or at your option any later version). See
* http://www.gnu.org/ for further details of the GPL. */
package freenet.node.simulator;
import static java.util.concurrent.TimeUnit.DAYS;
import static java.util.concurrent.TimeUnit.MINUTES;
import static java.util.concurrent.TimeUnit.SECONDS;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import freenet.crypt.RandomSource;
import freenet.io.comm.NotConnectedException;
import freenet.io.comm.PeerParseException;
import freenet.io.comm.ReferenceSignatureVerificationException;
import freenet.node.Announcer;
import freenet.node.FSParseException;
import freenet.node.Node;
import freenet.node.NodeInitException;
import freenet.node.NodeStarter;
import freenet.node.OpennetDisabledException;
import freenet.node.SeedServerPeerNode;
import freenet.node.SeedServerTestPeerNode;
import freenet.node.SeedServerTestPeerNode.FATE;
import freenet.support.Executor;
import freenet.support.Logger;
import freenet.support.PooledExecutor;
import freenet.support.SimpleFieldSet;
import freenet.support.TimeUtil;
import freenet.support.Logger.LogLevel;
import freenet.support.LoggerHook.InvalidThresholdException;
/**
* @author Florent Daignière <nextgens@freenetproject.org>
*/
public class SeednodePingTest extends RealNodeTest {
static File STATUS_DIR = new File("/var/www/freenet/tests/seednodes/status/");
static final long COUNT_SUCCESSES_PERIOD = DAYS.toMillis(7);
static final int DARKNET_PORT = RealNodeULPRTest.DARKNET_PORT_END;
static final int OPENNET_PORT = DARKNET_PORT+1;
public static void main(String[] args) throws FSParseException, IOException, OpennetDisabledException, PeerParseException, InterruptedException, ReferenceSignatureVerificationException, NodeInitException, InvalidThresholdException {
Node node = null;
try {
if(args.length == 1)
STATUS_DIR = new File(args[0]);
RandomSource random = NodeStarter.globalTestInit("seednode-pingtest", false, LogLevel.ERROR, "", false);
// Create one node
Executor executor = new PooledExecutor();
node = NodeStarter.createTestNode(DARKNET_PORT, OPENNET_PORT, "seednode-pingtest", false, Node.DEFAULT_MAX_HTL, 0, random, executor, 1000, 5*1024*1024, true, false, false, false, false, false, false, 0, false, false, false, false, null);
// Connect & ping
List<SeedServerTestPeerNode> seedNodes = new ArrayList<SeedServerTestPeerNode>();
List<SimpleFieldSet> seedNodesAsSFS = Announcer.readSeednodes(new File("/tmp/", Announcer.SEEDNODES_FILENAME));
int numberOfNodesInTheFile = 0;
for(SimpleFieldSet sfs : seedNodesAsSFS) {
numberOfNodesInTheFile++;
SeedServerTestPeerNode seednode = node.createNewSeedServerTestPeerNode(sfs);
try {
node.connectToSeednode(seednode);
seedNodes.add(seednode);
} catch (Exception fse) {
System.err.println("ERROR adding "+seednode.toString()+ " "+fse.getMessage());
}
}
// Start it
node.start(true);
//Logger.setupStdoutLogging(LogLevel.MINOR, "freenet:NORMAL,freenet.node.NodeDispatcher:MINOR,freenet.node.FNPPacketMangler:MINOR");
Logger.getChain().setThreshold(LogLevel.ERROR); // kill logging
Thread.sleep(SECONDS.toMillis(2));
if(seedNodes.size() != numberOfNodesInTheFile)
System.out.println("ERROR ADDING SOME OF THE SEEDNODES!!");
System.out.println("Let some time for the "+ seedNodes.size() +" nodes to connect...");
Thread.sleep(SECONDS.toMillis(8));
int pingID = 0;
long deadline = System.currentTimeMillis() + MINUTES.toMillis(2);
while(System.currentTimeMillis() < deadline) {
int countConnectedSeednodes = 0;
for(SeedServerPeerNode seednode : node.peers.getConnectedSeedServerPeersVector(null)) {
try {
double pingTime = seednode.averagePingTime();
int uptime = seednode.getUptime();
long timeDelta = seednode.getClockDelta();
if(seednode.isRealConnection())
continue;
countConnectedSeednodes++;
boolean ping = seednode.ping(pingID++);
if(ping)
System.out.println(seednode.getIdentityString()+
" uptime="+uptime+
" ping="+ping+
" pingTime="+pingTime+
" uptime="+seednode.getUptime()+
" timeDelta="+TimeUtil.formatTime(timeDelta));
// sanity check
if(seednode.isRoutable())
System.out.println(seednode + " is routable!");
} catch (NotConnectedException e) {
System.out.println(seednode.getIdentityString() + " is not connected "+seednode.getHandshakeCount());
}
}
Map<FATE, Integer> totals = new EnumMap<FATE, Integer>(SeedServerTestPeerNode.FATE.class);
for(SeedServerTestPeerNode seednode : seedNodes) {
FATE fate = seednode.getFate();
Integer x = totals.get(fate);
if(x == null)
totals.put(fate, 1);
else
totals.put(fate, x+1);
System.out.println(seednode.getIdentityString() + " : "+fate+ " : "+seednode.getPeerNodeStatusString());
}
System.out.println("TOTALS:");
for (Entry<FATE, Integer> fateEntry : totals.entrySet()) {
System.out.println(fateEntry.getKey() + " : " + fateEntry.getValue());
}
System.out.println("################## ("+node.peers.countConnectedPeers()+") "+countConnectedSeednodes+'/'+node.peers.countSeednodes());
Thread.sleep(SECONDS.toMillis(5));
}
Map<FATE, Integer> totals = new EnumMap<FATE, Integer>(SeedServerTestPeerNode.FATE.class);
for(SeedServerTestPeerNode seednode : seedNodes) {
FATE fate = seednode.getFate();
Integer x = totals.get(fate);
if(x == null)
totals.put(fate, 1);
else
totals.put(fate, x+1);
System.out.println(seednode.getIdentityString() + " : "+fate+ " : "+seednode.getPeerNodeStatusString());
}
System.out.println("RESULT:TOTALS:");
for(FATE fate : totals.keySet()) {
System.out.println("RESULT:"+fate + " : "+totals.get(fate));
}
System.out.println("Completed seednodes scan.");
// Record statuses.
System.out.println("FINAL STATUS:");
long writeTime = System.currentTimeMillis();
for(SeedServerTestPeerNode peer : seedNodes) {
String status = writeTime+" : "+peer.getIdentityString()+" : "+peer.getFate();
System.out.println(status);
File logFile = new File(STATUS_DIR, peer.getIdentityString());
FileOutputStream fos = new FileOutputStream(logFile, true);
OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8");
osw.write(status+"\n");
osw.close();
FileInputStream fis = new FileInputStream(logFile);
InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
BufferedReader br = new BufferedReader(isr);
String line;
int successes = 0;
int failures = 0;
long lastSuccess = 0;
long firstSample = 0;
long countSince = writeTime - COUNT_SUCCESSES_PERIOD;
do {
line = br.readLine();
if(line == null) break;
String[] results = line.split(" : ");
if(results.length != 3) {
System.err.println("Unable to parse line in "+logFile+" : wrong number of fields : "+results.length+" : "+line);
continue;
}
long time = Long.parseLong(results[0]);
FATE fate = FATE.valueOf(results[2]);
if(firstSample == 0) firstSample = time;
if(fate == FATE.CONNECTED_SUCCESS) {
if(time >= countSince)
successes++;
lastSuccess = time;
} else {
if(time >= countSince)
failures++;
}
} while(line != null);
br.close();
if(firstSample < countSince && successes == 0)
System.err.println("RESULT:"+peer.getIdentityString()+" NOT CONNECTED IN LAST WEEK! LAST CONNECTED: "+(lastSuccess > 0 ? TimeUtil.formatTime(writeTime - lastSuccess) : "NEVER"));
System.out.println(peer.getIdentityString()+" : last success "+(lastSuccess > 0 ? TimeUtil.formatTime(writeTime - lastSuccess) : "NEVER")+" failures in last week: "+failures+" successes in last week: "+successes);
}
node.park();
System.exit(0);
} catch (Throwable t) {
System.err.println("CAUGHT: "+t);
t.printStackTrace();
try {
if(node != null)
node.park();
} catch (Throwable t1) {}
System.exit(1);
}
}
}