/* Copyright 2007 Freenet Project Inc.
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package freenet.clients.http;
import java.io.IOException;
import java.net.URI;
import freenet.client.HighLevelSimpleClient;
import freenet.io.AddressTracker;
import freenet.io.AddressTrackerItem;
import freenet.io.InetAddressAddressTrackerItem;
import freenet.io.PeerAddressTrackerItem;
import freenet.io.AddressTrackerItem.Gap;
import freenet.io.comm.UdpSocketHandler;
import freenet.l10n.NodeL10n;
import freenet.node.FSParseException;
import freenet.node.Node;
import freenet.support.HTMLNode;
import freenet.support.SimpleFieldSet;
import freenet.support.TimeUtil;
import freenet.support.api.HTTPRequest;
/**
* Toadlet displaying information on the node's connectivity status.
* Eventually this will include all information gathered by the node on its
* connectivity from plugins, local IP detection, packet monitoring etc.
* For the moment it's just a dump of the AddressTracker.
* @author toad
*/
public class ConnectivityToadlet extends Toadlet {
private final Node node;
protected ConnectivityToadlet(HighLevelSimpleClient client, Node node) {
super(client);
this.node = node;
}
public void handleMethodGET(URI uri, final HTTPRequest request, ToadletContext ctx) throws ToadletContextClosedException, IOException {
PageMaker pageMaker = ctx.getPageMaker();
PageNode page = pageMaker.getPageNode(NodeL10n.getBase().getString("ConnectivityToadlet.title"), ctx);
HTMLNode pageNode = page.outer;
HTMLNode contentNode = page.content;
/* add alert summary box */
if(ctx.isAllowedFullAccess())
contentNode.addChild(ctx.getAlertManager().createSummary());
// our ports
HTMLNode portInfobox = contentNode.addChild("div", "class", "infobox infobox-normal");
portInfobox.addChild("div", "class", "infobox-header", l10nConn("nodePortsTitle"));
HTMLNode portInfoboxContent = portInfobox.addChild("div", "class", "infobox-content");
HTMLNode portInfoList = portInfoboxContent.addChild("ul");
SimpleFieldSet fproxyConfig = node.config.get("fproxy").exportFieldSet(true);
SimpleFieldSet fcpConfig = node.config.get("fcp").exportFieldSet(true);
SimpleFieldSet tmciConfig = node.config.get("console").exportFieldSet(true);
portInfoList.addChild("li", NodeL10n.getBase().getString("DarknetConnectionsToadlet.darknetFnpPort", new String[] { "port" }, new String[] { Integer.toString(node.getFNPPort()) }));
int opennetPort = node.getOpennetFNPPort();
if(opennetPort > 0)
portInfoList.addChild("li", NodeL10n.getBase().getString("DarknetConnectionsToadlet.opennetFnpPort", new String[] { "port" }, new String[] { Integer.toString(opennetPort) }));
try {
if(fproxyConfig.getBoolean("enabled", false)) {
portInfoList.addChild("li", NodeL10n.getBase().getString("DarknetConnectionsToadlet.fproxyPort", new String[] { "port" }, new String[] { Integer.toString(fproxyConfig.getInt("port")) }));
} else {
portInfoList.addChild("li", l10nConn("fproxyDisabled"));
}
if(fcpConfig.getBoolean("enabled", false)) {
portInfoList.addChild("li", NodeL10n.getBase().getString("DarknetConnectionsToadlet.fcpPort", new String[] { "port" }, new String[] { Integer.toString(fcpConfig.getInt("port")) }));
} else {
portInfoList.addChild("li", l10nConn("fcpDisabled"));
}
if(tmciConfig.getBoolean("enabled", false)) {
portInfoList.addChild("li", NodeL10n.getBase().getString("DarknetConnectionsToadlet.tmciPort", new String[] { "port" }, new String[] { Integer.toString(tmciConfig.getInt("port")) }));
} else {
portInfoList.addChild("li", l10nConn("tmciDisabled"));
}
} catch (FSParseException e) {
// ignore
}
// Add connection type box.
node.ipDetector.addConnectionTypeBox(contentNode);
UdpSocketHandler[] handlers = node.getPacketSocketHandlers();
HTMLNode summaryContent = pageMaker.getInfobox("#", NodeL10n.getBase().getString("ConnectivityToadlet.summaryTitle"), contentNode, "connectivity-summary", true);
HTMLNode table = summaryContent.addChild("table", "border", "0");
for(UdpSocketHandler handler: handlers) {
AddressTracker tracker = handler.getAddressTracker();
HTMLNode row = table.addChild("tr");
row.addChild("td", handler.getTitle());
row.addChild("td", AddressTracker.statusString(tracker.getPortForwardStatus()));
}
if(ctx.isAdvancedModeEnabled()) {
// One box per port
String noreply = l10n("noreply");
String local = l10n("local");
String remote = l10n("remote");
long now = System.currentTimeMillis();
for(UdpSocketHandler handler: handlers) {
// Peers
AddressTracker tracker = handler.getAddressTracker();
HTMLNode portsContent = pageMaker.getInfobox("#", NodeL10n.getBase().getString("ConnectivityToadlet.byPortTitle", new String[] { "port", "status", "tunnelLength" }, new String[] { handler.getTitle(), AddressTracker.statusString(tracker.getPortForwardStatus()), TimeUtil.formatTime(tracker.getLongestSendReceiveGap()) }), contentNode, "connectivity-port", false);
PeerAddressTrackerItem[] items = tracker.getPeerAddressTrackerItems();
table = portsContent.addChild("table");
HTMLNode row = table.addChild("tr");
row.addChild("th", l10n("addressTitle"));
row.addChild("th", l10n("sentReceivedTitle"));
row.addChild("th", l10n("localRemoteTitle"));
row.addChild("th", l10n("firstSendLeadTime"));
row.addChild("th", l10n("firstReceiveLeadTime"));
for(int j=0;j<AddressTrackerItem.TRACK_GAPS;j++) {
row.addChild("th", " "); // FIXME is <th/> valid??
}
for(PeerAddressTrackerItem item: items) {
row = table.addChild("tr");
// Address
row.addChild("td", item.peer.toString());
// Sent/received packets
row.addChild("td", item.packetsSent() + "/ " + item.packetsReceived());
// Initiator: local/remote FIXME something more graphical e.g. colored cells
row.addChild("td", item.packetsReceived() == 0 ? noreply :
(item.weSentFirst() ? local : remote));
// Lead in time to first packet sent
row.addChild("td", TimeUtil.formatTime(item.timeFromStartupToFirstSentPacket()));
// Lead in time to first packet received
row.addChild("td", TimeUtil.formatTime(item.timeFromStartupToFirstReceivedPacket()));
Gap[] gaps = item.getGaps();
for(int k=0;k<AddressTrackerItem.TRACK_GAPS;k++) {
row.addChild("td", gaps[k].receivedPacketAt == 0 ? "" :
(TimeUtil.formatTime(gaps[k].gapLength)+" @ "+TimeUtil.formatTime(now - gaps[k].receivedPacketAt)+" ago" /* fixme l10n */));
}
}
// IPs
portsContent = pageMaker.getInfobox("#", NodeL10n.getBase().getString("ConnectivityToadlet.byIPTitle", new String[] { "ip", "status", "tunnelLength" }, new String[] { handler.getTitle(), AddressTracker.statusString(tracker.getPortForwardStatus()), TimeUtil.formatTime(tracker.getLongestSendReceiveGap()) }), contentNode, "connectivity-ip", false);
InetAddressAddressTrackerItem[] ipItems = tracker.getInetAddressTrackerItems();
table = portsContent.addChild("table");
row = table.addChild("tr");
row.addChild("th", l10n("addressTitle"));
row.addChild("th", l10n("sentReceivedTitle"));
row.addChild("th", l10n("localRemoteTitle"));
row.addChild("th", l10n("firstSendLeadTime"));
row.addChild("th", l10n("firstReceiveLeadTime"));
for(int j=0;j<AddressTrackerItem.TRACK_GAPS;j++) {
row.addChild("th", " "); // FIXME is <th/> valid??
}
for(InetAddressAddressTrackerItem item: ipItems) {
row = table.addChild("tr");
// Address
row.addChild("td", item.addr.toString());
// Sent/received packets
row.addChild("td", item.packetsSent() + "/ " + item.packetsReceived());
// Initiator: local/remote FIXME something more graphical e.g. colored cells
row.addChild("td", item.packetsReceived() == 0 ? noreply :
(item.weSentFirst() ? local : remote));
// Lead in time to first packet sent
row.addChild("td", TimeUtil.formatTime(item.timeFromStartupToFirstSentPacket()));
// Lead in time to first packet received
row.addChild("td", TimeUtil.formatTime(item.timeFromStartupToFirstReceivedPacket()));
Gap[] gaps = item.getGaps();
for(int k=0;k<AddressTrackerItem.TRACK_GAPS;k++) {
row.addChild("td", gaps[k].receivedPacketAt == 0 ? "" :
(TimeUtil.formatTime(gaps[k].gapLength)+" @ "+TimeUtil.formatTime(now - gaps[k].receivedPacketAt)+" ago" /* fixme l10n */));
}
}
}
}
writeHTMLReply(ctx, 200, "OK", pageNode.generate());
}
private String l10nConn(String string) {
return NodeL10n.getBase().getString("DarknetConnectionsToadlet."+string);
}
private String l10n(String key) {
return NodeL10n.getBase().getString("ConnectivityToadlet."+key);
}
public static final String PATH = "/connectivity/";
@Override
public String path() {
return PATH;
}
}