propagate from branch 'i2p.i2p.zzz.test3' (head e19da9b978ed2ec03adb0e326fff6870746cc4fc)

to branch 'i2p.i2p' (head 179b9a7974d64853c0c91924a5ad86e8b04ee7ba)
This commit is contained in:
zzz
2009-08-24 00:08:30 +00:00
17 changed files with 157 additions and 63 deletions

View File

@@ -843,6 +843,8 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
String type; String type;
if (filename.endsWith(".css")) if (filename.endsWith(".css"))
type = "text/css"; type = "text/css";
else if (filename.endsWith(".ico"))
type = "image/x-icon";
else if (filename.endsWith(".png")) else if (filename.endsWith(".png"))
type = "image/png"; type = "image/png";
else if (filename.endsWith(".jpg")) else if (filename.endsWith(".jpg"))

View File

@@ -1,3 +1,4 @@
<%@page pageEncoding="UTF-8"%>
<%@page contentType="text/html" import="net.i2p.i2ptunnel.web.EditBean" %><% <%@page contentType="text/html" import="net.i2p.i2ptunnel.web.EditBean" %><%
String tun = request.getParameter("tunnel"); String tun = request.getParameter("tunnel");
if (tun != null) { if (tun != null) {

View File

@@ -1,3 +1,9 @@
<%
// http://www.crazysquirrel.com/computing/general/form-encoding.jspx
if (request.getCharacterEncoding() == null)
request.setCharacterEncoding("UTF-8");
%>
<%@page pageEncoding="UTF-8"%>
<%@page contentType="text/html" import="net.i2p.i2ptunnel.web.IndexBean"%><?xml version="1.0" encoding="UTF-8"?> <%@page contentType="text/html" import="net.i2p.i2ptunnel.web.IndexBean"%><?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<jsp:useBean class="net.i2p.i2ptunnel.web.IndexBean" id="indexBean" scope="request" /> <jsp:useBean class="net.i2p.i2ptunnel.web.IndexBean" id="indexBean" scope="request" />
@@ -6,13 +12,12 @@
<head> <head>
<title>I2P Tunnel Manager - List</title> <title>I2P Tunnel Manager - List</title>
<meta htt <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
p-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" /> <meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
<link href="/themes/console/images/favicon.ico" type="image/x-icon" rel="shortcut icon" />
<% if (indexBean.allowCSS()) { <% if (indexBean.allowCSS()) {
%><link href="/themes/console/images/favicon.ico" type="image/x-icon" rel="shortcut icon" /> %><link href="<%=indexBean.getTheme()%>default.css" rel="stylesheet" type="text/css" />
<link href="<%=indexBean.getTheme()%>default.css" rel="stylesheet" type="text/css" />
<link href="<%=indexBean.getTheme()%>i2ptunnel.css" rel="stylesheet" type="text/css" /> <link href="<%=indexBean.getTheme()%>i2ptunnel.css" rel="stylesheet" type="text/css" />
<% } <% }
%> %>

View File

@@ -23,7 +23,8 @@
<target name="compile" depends="depend"> <target name="compile" depends="depend">
<mkdir dir="./build" /> <mkdir dir="./build" />
<mkdir dir="./build/obj" /> <mkdir dir="./build/obj" />
<javac srcdir="./src" debug="true" deprecation="on" source="1.5" target="1.5" destdir="./build/obj" classpath="../../../core/java/build/i2p.jar" > <!-- half of this is deprecated classes so turn deprecation off -->
<javac srcdir="./src" debug="true" deprecation="off" source="1.5" target="1.5" destdir="./build/obj" classpath="../../../core/java/build/i2p.jar" >
<compilerarg line="${javac.compilerargs}" /> <compilerarg line="${javac.compilerargs}" />
</javac> </javac>
</target> </target>

View File

@@ -154,28 +154,35 @@ buf.append("<tr><th></th><th><img src=\"/themes/console/images/inbound.png\" alt
buf.append("</tr>\n"); buf.append("</tr>\n");
// custom options // custom options
buf.append("<tr><td align=\"right\" class=\"mediumtags\">Inbound options:</td>\n"); // There is no facility to set these, either in ConfigTunnelsHandler or
buf.append("<td colspan=\"2\" align=\"center\"><input name=\"").append(index); // TunnelPoolOptions, so make the boxes readonly.
buf.append(".inboundOptions\" type=\"text\" size=\"32\" "); // And let's not display them at all unless they have contents, which should be rare.
buf.append("value=\"");
Properties props = in.getUnknownOptions(); Properties props = in.getUnknownOptions();
for (Iterator iter = props.keySet().iterator(); iter.hasNext(); ) { if (props.size() > 0) {
String prop = (String)iter.next(); buf.append("<tr><td align=\"right\" class=\"mediumtags\">Inbound options:</td>\n" +
String val = (String)props.getProperty(prop); "<td colspan=\"2\" align=\"center\"><input name=\"").append(index);
buf.append(prop).append("=").append(val).append(" "); buf.append(".inboundOptions\" type=\"text\" size=\"32\" disabled=\"true\" " +
"value=\"");
for (Iterator iter = props.keySet().iterator(); iter.hasNext(); ) {
String prop = (String)iter.next();
String val = (String)props.getProperty(prop);
buf.append(prop).append('=').append(val).append(' ');
}
buf.append("\"></td></tr>\n");
} }
buf.append("\"/></td></tr>\n"); props = out.getUnknownOptions();
buf.append("<tr><td align=\"right\" class=\"mediumtags\">Outbound options:</td>\n"); if (props.size() > 0) {
buf.append("<td colspan=\"2\" align=\"center\"><input name=\"").append(index); buf.append("<tr><td align=\"right\" class=\"mediumtags\">Outbound options:</td>\n" +
buf.append(".outboundOptions\" type=\"text\" size=\"32\" "); "<td colspan=\"2\" align=\"center\"><input name=\"").append(index);
buf.append("value=\""); buf.append(".outboundOptions\" type=\"text\" size=\"32\" disabled=\"true\" " +
props = in.getUnknownOptions(); "value=\"");
for (Iterator iter = props.keySet().iterator(); iter.hasNext(); ) { for (Iterator iter = props.keySet().iterator(); iter.hasNext(); ) {
String prop = (String)iter.next(); String prop = (String)iter.next();
String val = (String)props.getProperty(prop); String val = (String)props.getProperty(prop);
buf.append(prop).append("=").append(val).append(" "); buf.append(prop).append('=').append(val).append(' ');
}
buf.append("\"></td></tr>\n");
} }
buf.append("\"/></td></tr>\n");
// buf.append("<tr><td colspan=\"3\"><br></td></tr>\n"); // buf.append("<tr><td colspan=\"3\"><br></td></tr>\n");
} }

View File

@@ -2,8 +2,14 @@
/* /*
* This should be included inside <head>...</head>, * This should be included inside <head>...</head>,
* as it sets the stylesheet. * as it sets the stylesheet.
*
* This is included almost 30 times, so keep whitespace etc. to a minimum.
*/ */
// http://www.crazysquirrel.com/computing/general/form-encoding.jspx
if (request.getCharacterEncoding() == null)
request.setCharacterEncoding("UTF-8");
response.setHeader("Pragma", "no-cache"); response.setHeader("Pragma", "no-cache");
response.setHeader("Cache-Control","no-cache"); response.setHeader("Cache-Control","no-cache");
response.setDateHeader("Expires", 0); response.setDateHeader("Expires", 0);
@@ -15,7 +21,9 @@
session.setAttribute("i2p.contextId", request.getParameter("i2p.contextId")); session.setAttribute("i2p.contextId", request.getParameter("i2p.contextId"));
} }
%> %>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="shortcut icon" href="favicon.ico">
<jsp:useBean class="net.i2p.router.web.CSSHelper" id="cssHelper" scope="request" /> <jsp:useBean class="net.i2p.router.web.CSSHelper" id="cssHelper" scope="request" />
<jsp:setProperty name="cssHelper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" /> <jsp:setProperty name="cssHelper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
<link href="<%=cssHelper.getTheme(request.getHeader("User-Agent"))%>console.css" rel="stylesheet" type="text/css"> <link href="<%=cssHelper.getTheme(request.getHeader("User-Agent"))%>console.css" rel="stylesheet" type="text/css">
<!--[if IE]><link href="/themes/console/classic/ieshim.css" rel="stylesheet" type="text/css" /><![endif]--> <!--[if IE]><link href="/themes/console/classic/ieshim.css" rel="stylesheet" type="text/css" /><![endif]-->

View File

@@ -13,7 +13,6 @@
// If it can't find the iframe or viewtheme.jsp I wonder if the whole thing blows up... // If it can't find the iframe or viewtheme.jsp I wonder if the whole thing blows up...
%> %>
<html><head><title>I2P Router Console - Page Not Found</title> <html><head><title>I2P Router Console - Page Not Found</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<%@include file="css.jsp" %> <%@include file="css.jsp" %>
<link rel="shortcut icon" href="favicon.ico" /></head><body> <link rel="shortcut icon" href="favicon.ico" /></head><body>
<% <%

View File

@@ -25,6 +25,12 @@ if (c != null && c.length() > 0) {
if (rendered) if (rendered)
cout.close(); cout.close();
} }
/*
* Send a 403 instead of a 404, because the server sends error.jsp
* for 404 errors, complete with the summary bar, which would be
* a huge load for a page full of flags if the user didn't have the
* flags directory for some reason.
*/
if (!rendered) if (!rendered)
response.sendError(404, "Not found"); response.sendError(403, "Flag not found");
%> %>

View File

@@ -5,8 +5,6 @@
<html><head> <html><head>
<%@include file="css.jsp" %> <%@include file="css.jsp" %>
<title>I2P Router Console - home</title> <title>I2P Router Console - home</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="shortcut icon" href="/themes/console/images/favicon.ico" />
</head><body> </head><body>
<% <%
if (System.getProperty("router.consoleNonce") == null) { if (System.getProperty("router.consoleNonce") == null) {

View File

@@ -10,7 +10,6 @@
<html><head> <html><head>
<%@include file="css.jsp" %> <%@include file="css.jsp" %>
<title>Summary Bar</title> <title>Summary Bar</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<% <%
// try hard to avoid an error page in the iframe after shutdown // try hard to avoid an error page in the iframe after shutdown
String action = request.getParameter("action"); String action = request.getParameter("action");

View File

@@ -63,7 +63,12 @@ if ( !rendered && ((rs != null) || fakeBw) ) {
} }
} catch (NumberFormatException nfe) {} } catch (NumberFormatException nfe) {}
} }
/*
* Send a 403 instead of a 404, because the server sends error.jsp
* for 404 errors, complete with the summary bar, which would be
* a huge load for a page full of graphs if there's a problem
*/
if (!rendered) { if (!rendered) {
response.sendError(404, "That stat is not available"); response.sendError(403, "That stat is not available");
} }
%> %>

View File

@@ -105,6 +105,19 @@ public class DataHelper {
*/ */
public static void writeProperties(OutputStream rawStream, Properties props) public static void writeProperties(OutputStream rawStream, Properties props)
throws DataFormatException, IOException { throws DataFormatException, IOException {
writeProperties(rawStream, props, false);
}
/**
* jrandom disabled UTF-8 in mid-2004, for performance reasons,
* i.e. slow foo.getBytes("UTF-8")
* Re-enable it so we can pass UTF-8 tunnel names through the I2CP SessionConfig.
*
* Use utf8 = false for RouterAddress (fast, non UTF-8)
* Use utf8 = true for SessionConfig (slow, UTF-8)
*/
public static void writeProperties(OutputStream rawStream, Properties props, boolean utf8)
throws DataFormatException, IOException {
if (props != null) { if (props != null) {
OrderedProperties p = new OrderedProperties(); OrderedProperties p = new OrderedProperties();
p.putAll(props); p.putAll(props);
@@ -112,12 +125,15 @@ public class DataHelper {
for (Iterator iter = p.keySet().iterator(); iter.hasNext();) { for (Iterator iter = p.keySet().iterator(); iter.hasNext();) {
String key = (String) iter.next(); String key = (String) iter.next();
String val = p.getProperty(key); String val = p.getProperty(key);
// now make sure they're in UTF-8 if (utf8)
//key = new String(key.getBytes(), "UTF-8"); writeStringUTF8(baos, key);
//val = new String(val.getBytes(), "UTF-8"); else
writeString(baos, key); writeString(baos, key);
baos.write(_equalBytes); baos.write(_equalBytes);
writeString(baos, val); if (utf8)
writeStringUTF8(baos, val);
else
writeString(baos, val);
baos.write(_semicolonBytes); baos.write(_semicolonBytes);
} }
baos.close(); baos.close();
@@ -486,6 +502,7 @@ public class DataHelper {
/** Read in a string from the stream as specified by the I2P data structure spec. /** Read in a string from the stream as specified by the I2P data structure spec.
* A string is 1 or more bytes where the first byte is the number of bytes (not characters!) * A string is 1 or more bytes where the first byte is the number of bytes (not characters!)
* in the string and the remaining 0-255 bytes are the non-null terminated UTF-8 encoded character array. * in the string and the remaining 0-255 bytes are the non-null terminated UTF-8 encoded character array.
*
* @param in stream to read from * @param in stream to read from
* @throws DataFormatException if the stream doesn't contain a validly formatted string * @throws DataFormatException if the stream doesn't contain a validly formatted string
* @throws IOException if there is an IO error reading the string * @throws IOException if there is an IO error reading the string
@@ -496,12 +513,17 @@ public class DataHelper {
byte raw[] = new byte[size]; byte raw[] = new byte[size];
int read = read(in, raw); int read = read(in, raw);
if (read != size) throw new DataFormatException("Not enough bytes to read the string"); if (read != size) throw new DataFormatException("Not enough bytes to read the string");
return new String(raw); // the following constructor throws an UnsupportedEncodingException which is an IOException,
// but that's only if UTF-8 is not supported. Other encoding errors are not thrown.
return new String(raw, "UTF-8");
} }
/** Write out a string to the stream as specified by the I2P data structure spec. Note that the max /** Write out a string to the stream as specified by the I2P data structure spec. Note that the max
* size for a string allowed by the spec is 255 bytes. * size for a string allowed by the spec is 255 bytes.
* *
* WARNING - this method destroys the encoding, and therefore violates
* the data structure spec.
*
* @param out stream to write string * @param out stream to write string
* @param string string to write out: null strings are perfectly valid, but strings of excess length will * @param string string to write out: null strings are perfectly valid, but strings of excess length will
* cause a DataFormatException to be thrown * cause a DataFormatException to be thrown
@@ -516,13 +538,41 @@ public class DataHelper {
int len = string.length(); int len = string.length();
if (len > 255) if (len > 255)
throw new DataFormatException("The I2P data spec limits strings to 255 bytes or less, but this is " throw new DataFormatException("The I2P data spec limits strings to 255 bytes or less, but this is "
+ string.length() + " [" + string + "]"); + len + " [" + string + "]");
writeLong(out, 1, len); writeLong(out, 1, len);
for (int i = 0; i < len; i++) for (int i = 0; i < len; i++)
out.write((byte)(string.charAt(i) & 0xFF)); out.write((byte)(string.charAt(i) & 0xFF));
} }
} }
/** Write out a string to the stream as specified by the I2P data structure spec. Note that the max
* size for a string allowed by the spec is 255 bytes.
*
* This method correctly uses UTF-8
*
* @param out stream to write string
* @param string UTF-8 string to write out: null strings are perfectly valid, but strings of excess length will
* cause a DataFormatException to be thrown
* @throws DataFormatException if the string is not valid
* @throws IOException if there is an IO error writing the string
*/
private static void writeStringUTF8(OutputStream out, String string)
throws DataFormatException, IOException {
if (string == null) {
writeLong(out, 1, 0);
} else {
// the following method throws an UnsupportedEncodingException which is an IOException,
// but that's only if UTF-8 is not supported. Other encoding errors are not thrown.
byte[] raw = string.getBytes("UTF-8");
int len = raw.length;
if (len > 255)
throw new DataFormatException("The I2P data spec limits strings to 255 bytes or less, but this is "
+ len + " [" + string + "]");
writeLong(out, 1, len);
out.write(raw);
}
}
/** Read in a boolean as specified by the I2P data structure spec. /** Read in a boolean as specified by the I2P data structure spec.
* A boolean is 1 byte that is either 0 (false), 1 (true), or 2 (null) * A boolean is 1 byte that is either 0 (false), 1 (true), or 2 (null)
* @param in stream to read from * @param in stream to read from

View File

@@ -173,7 +173,7 @@ public class SessionConfig extends DataStructureImpl {
_log.debug("PubKey size for destination: " + _destination.getPublicKey().getData().length); _log.debug("PubKey size for destination: " + _destination.getPublicKey().getData().length);
_log.debug("SigningKey size for destination: " + _destination.getSigningPublicKey().getData().length); _log.debug("SigningKey size for destination: " + _destination.getSigningPublicKey().getData().length);
_destination.writeBytes(out); _destination.writeBytes(out);
DataHelper.writeProperties(out, _options); DataHelper.writeProperties(out, _options, true); // UTF-8
DataHelper.writeDate(out, _creationDate); DataHelper.writeDate(out, _creationDate);
} catch (IOException ioe) { } catch (IOException ioe) {
_log.error("IOError signing", ioe); _log.error("IOError signing", ioe);
@@ -198,7 +198,7 @@ public class SessionConfig extends DataStructureImpl {
if ((_destination == null) || (_options == null) || (_signature == null) || (_creationDate == null)) if ((_destination == null) || (_options == null) || (_signature == null) || (_creationDate == null))
throw new DataFormatException("Not enough data to create the session config"); throw new DataFormatException("Not enough data to create the session config");
_destination.writeBytes(out); _destination.writeBytes(out);
DataHelper.writeProperties(out, _options); DataHelper.writeProperties(out, _options, true); // UTF-8
DataHelper.writeDate(out, _creationDate); DataHelper.writeDate(out, _creationDate);
_signature.writeBytes(out); _signature.writeBytes(out);
} }
@@ -232,4 +232,4 @@ public class SessionConfig extends DataStructureImpl {
buf.append("]"); buf.append("]");
return buf.toString(); return buf.toString();
} }
} }

View File

@@ -117,8 +117,12 @@ wrapper.logfile=$SYSTEM_java_io_tmpdir/wrapper.log
# no need for a wrapper.java.additional line too. # no need for a wrapper.java.additional line too.
#wrapper.logfile=$INSTALL_PATH/wrapper.log #wrapper.logfile=$INSTALL_PATH/wrapper.log
# Format of output for the log file. (See docs for formats) # Format of output for the log file.
wrapper.logfile.format=LPTM # The format consists of the tokens 'L' for log level, 'P' for prefix, 'D' for thread,
# 'T' for time, 'Z' for millisecond time, and 'M' for message
# Unfortunately the log timezone cannot be changed, see
# http://www.nabble.com/Log-message-timezone-td23651317.html
wrapper.logfile.format=TM
# Log Level for log file output. (See docs for log levels) # Log Level for log file output. (See docs for log levels)
wrapper.logfile.loglevel=INFO wrapper.logfile.loglevel=INFO

View File

@@ -1109,7 +1109,11 @@ public class Router {
return; return;
} }
System.out.println("INFO: Update file exists [" + UPDATE_FILE + "] - installing"); System.out.println("INFO: Update file exists [" + UPDATE_FILE + "] - installing");
boolean ok = FileUtil.extractZip(updateFile, _context.getBaseDir()); // verify the whole thing first
// we could remember this fails, and not bother restarting, but who cares...
boolean ok = FileUtil.verifyZip(updateFile);
if (ok)
ok = FileUtil.extractZip(updateFile, _context.getBaseDir());
if (ok) if (ok)
System.out.println("INFO: Update installed"); System.out.println("INFO: Update installed");
else else
@@ -1132,6 +1136,7 @@ public class Router {
updateFile.deleteOnExit(); updateFile.deleteOnExit();
} }
} }
// exit whether ok or not
if (System.getProperty("wrapper.version") != null) if (System.getProperty("wrapper.version") != null)
System.out.println("INFO: Restarting after update"); System.out.println("INFO: Restarting after update");
else else

View File

@@ -111,10 +111,11 @@ class ProfileOrganizerRenderer {
if (isIntegrated) buf.append(", Integrated"); if (isIntegrated) buf.append(", Integrated");
RouterInfo info = _context.netDb().lookupRouterInfoLocally(peer); RouterInfo info = _context.netDb().lookupRouterInfoLocally(peer);
if (info != null) { if (info != null) {
buf.append(" (").append(info.getCapabilities()); // prevent HTML injection in the caps and version
buf.append(" (").append(DataHelper.stripHTML(info.getCapabilities()));
String v = info.getOption("router.version"); String v = info.getOption("router.version");
if (v != null) if (v != null)
buf.append(' ').append(v); buf.append(' ').append(DataHelper.stripHTML(v));
buf.append(')'); buf.append(')');
} }
@@ -153,6 +154,9 @@ class ProfileOrganizerRenderer {
buf.append("<td nowrap align=\"center\"><a target=\"_blank\" href=\"dumpprofile.jsp?peer=").append(peer.toBase64().substring(0,6)).append("\">profile</a>"); buf.append("<td nowrap align=\"center\"><a target=\"_blank\" href=\"dumpprofile.jsp?peer=").append(peer.toBase64().substring(0,6)).append("\">profile</a>");
buf.append("&nbsp;<a href=\"configpeer.jsp?peer=").append(peer.toBase64()).append("\">+-</a></td>\n"); buf.append("&nbsp;<a href=\"configpeer.jsp?peer=").append(peer.toBase64()).append("\">+-</a></td>\n");
buf.append("</tr>"); buf.append("</tr>");
// let's not build the whole page in memory (~500 bytes per peer)
out.write(buf.toString());
buf.setLength(0);
} }
buf.append("</table>"); buf.append("</table>");
@@ -189,7 +193,7 @@ class ProfileOrganizerRenderer {
buf.append("</td>"); buf.append("</td>");
RouterInfo info = _context.netDb().lookupRouterInfoLocally(peer); RouterInfo info = _context.netDb().lookupRouterInfoLocally(peer);
if (info != null) if (info != null)
buf.append("<td align=\"center\">" + info.getCapabilities() + "</td>"); buf.append("<td align=\"center\">").append(DataHelper.stripHTML(info.getCapabilities())).append("</td>");
else else
buf.append("<td>&nbsp;</td>"); buf.append("<td>&nbsp;</td>");
buf.append("</code></td>"); buf.append("</code></td>");

View File

@@ -645,20 +645,20 @@ public class NTCPTransport extends TransportImpl {
buf.append("<p><b id=\"ntcpcon\"><h3>NTCP connections: ").append(peers.size()); buf.append("<p><b id=\"ntcpcon\"><h3>NTCP connections: ").append(peers.size());
buf.append(". Limit: ").append(getMaxConnections()); buf.append(". Limit: ").append(getMaxConnections());
buf.append(". Timeout: ").append(DataHelper.formatDuration(_pumper.getIdleTimeout())); buf.append(". Timeout: ").append(DataHelper.formatDuration(_pumper.getIdleTimeout()));
buf.append(".</b></h3>\n"); buf.append(".</b></h3>\n" +
buf.append("<div class=\"wideload\"><table>\n"); "<div class=\"wideload\"><table>\n" +
buf.append("<tr><th><a href=\"#def.peer\">Peer</a></th>"); "<tr><th><a href=\"#def.peer\">Peer</a></th>" +
buf.append("<th>Dir</th>"); "<th>Dir</th>" +
buf.append("<th align=\"right\"><a href=\"#def.idle\">Idle</a></th>"); "<th align=\"right\"><a href=\"#def.idle\">Idle</a></th>" +
buf.append("<th align=\"right\"><a href=\"#def.rate\">In/Out</a></th>"); "<th align=\"right\"><a href=\"#def.rate\">In/Out</a></th>" +
buf.append("<th align=\"right\"><a href=\"#def.up\">Up</a></th>"); "<th align=\"right\"><a href=\"#def.up\">Up</a></th>" +
buf.append("<th align=\"right\"><a href=\"#def.skew\">Skew</a></th>"); "<th align=\"right\"><a href=\"#def.skew\">Skew</a></th>" +
buf.append("<th align=\"right\"><a href=\"#def.send\">TX</a></th>"); "<th align=\"right\"><a href=\"#def.send\">TX</a></th>" +
buf.append("<th align=\"right\"><a href=\"#def.recv\">RX</a></th>"); "<th align=\"right\"><a href=\"#def.recv\">RX</a></th>" +
buf.append("<th>Out queue</th>"); "<th>Out queue</th>" +
buf.append("<th>Backlogged?</th>"); "<th>Backlogged?</th>" +
buf.append("<th>Reading?</th>"); "<th>Reading?</th>" +
buf.append(" </tr>\n"); " </tr>\n");
out.write(buf.toString()); out.write(buf.toString());
buf.setLength(0); buf.setLength(0);
for (Iterator iter = peers.iterator(); iter.hasNext(); ) { for (Iterator iter = peers.iterator(); iter.hasNext(); ) {
@@ -726,8 +726,8 @@ public class NTCPTransport extends TransportImpl {
buf.append("</td> <td align=\"center\"><b>").append(DataHelper.formatDuration(totalUptime/peers.size())); buf.append("</td> <td align=\"center\"><b>").append(DataHelper.formatDuration(totalUptime/peers.size()));
buf.append("</b></td> <td align=\"center\"><b>").append(peers.size() > 0 ? DataHelper.formatDuration(offsetTotal*1000/peers.size()) : "0ms"); buf.append("</b></td> <td align=\"center\"><b>").append(peers.size() > 0 ? DataHelper.formatDuration(offsetTotal*1000/peers.size()) : "0ms");
buf.append("</b></td> <td align=\"center\"><b>").append(totalSend).append("</b></td> <td align=\"center\"><b>").append(totalRecv); buf.append("</b></td> <td align=\"center\"><b>").append(totalSend).append("</b></td> <td align=\"center\"><b>").append(totalRecv);
buf.append("</b></td> <td>&nbsp;</td> <td>&nbsp;</td> <td>&nbsp;"); buf.append("</b></td> <td>&nbsp;</td> <td>&nbsp;</td> <td>&nbsp;" +
buf.append("</td></tr>\n"); "</td></tr>\n");
} }
buf.append("</table></div></p>\n"); buf.append("</table></div></p>\n");