forked from I2P_Developers/i2p.i2p
Compare commits
7 Commits
i2p_0_6_1_
...
i2p_0_6_1_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
12900ca709 | ||
|
|
f5b829a124 | ||
|
|
f62a6d3ce6 | ||
|
|
3d18bf870b | ||
|
|
d8071296eb | ||
|
|
c66e3256aa | ||
|
|
686742a67b |
@@ -490,17 +490,20 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
_log.warn("Unable to resolve " + destination + " (proxy? " + usingWWWProxy + ", request: " + targetRequest);
|
||||
String str;
|
||||
byte[] header;
|
||||
boolean showAddrHelper = false;
|
||||
if (usingWWWProxy)
|
||||
str = FileUtil.readTextFile("docs/dnfp-header.ht", 100, true);
|
||||
else if(ahelper != 0)
|
||||
str = FileUtil.readTextFile("docs/dnfb-header.ht", 100, true);
|
||||
else
|
||||
else {
|
||||
str = FileUtil.readTextFile("docs/dnfh-header.ht", 100, true);
|
||||
showAddrHelper = true;
|
||||
}
|
||||
if (str != null)
|
||||
header = str.getBytes();
|
||||
else
|
||||
header = ERR_DESTINATION_UNKNOWN;
|
||||
writeErrorMessage(header, out, targetRequest, usingWWWProxy, destination);
|
||||
writeErrorMessage(header, out, targetRequest, usingWWWProxy, destination, showAddrHelper);
|
||||
s.close();
|
||||
return;
|
||||
}
|
||||
@@ -569,7 +572,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
}
|
||||
|
||||
private static void writeErrorMessage(byte[] errMessage, OutputStream out, String targetRequest,
|
||||
boolean usingWWWProxy, String wwwProxy) throws IOException {
|
||||
boolean usingWWWProxy, String wwwProxy, boolean showAddrHelper) throws IOException {
|
||||
if (out != null) {
|
||||
out.write(errMessage);
|
||||
if (targetRequest != null) {
|
||||
@@ -581,6 +584,13 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
out.write(uri.getBytes());
|
||||
out.write("</a>".getBytes());
|
||||
if (usingWWWProxy) out.write(("<br>WWW proxy: " + wwwProxy).getBytes());
|
||||
if (showAddrHelper) {
|
||||
out.write("<br><br>Click below to try an address helper link:<br><br><a href=\"http://orion.i2p/jump/".getBytes());
|
||||
out.write(uri.getBytes());
|
||||
out.write("\">http://orion.i2p/jump/".getBytes());
|
||||
out.write(uri.getBytes());
|
||||
out.write("</a>".getBytes());
|
||||
}
|
||||
}
|
||||
out.write("</div><p><i>I2P HTTP Proxy Server<br>Generated on: ".getBytes());
|
||||
out.write(new Date().toString().getBytes());
|
||||
@@ -606,7 +616,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
header = str.getBytes();
|
||||
else
|
||||
header = ERR_DESTINATION_UNKNOWN;
|
||||
writeErrorMessage(header, out, targetRequest, usingWWWProxy, wwwProxy);
|
||||
writeErrorMessage(header, out, targetRequest, usingWWWProxy, wwwProxy, false);
|
||||
} catch (IOException ioe) {
|
||||
_log.warn(getPrefix(requestId) + "Error writing out the 'destination was unknown' " + "message", ioe);
|
||||
}
|
||||
|
||||
@@ -3,30 +3,29 @@
|
||||
|
||||
<target name="all" depends="build" />
|
||||
<target name="fetchJettylib" >
|
||||
<available property="jetty.available" file="jetty-5.1.2.zip" />
|
||||
<available property="jetty.available" file="jetty-5.1.6.zip" />
|
||||
<ant target="doFetchJettylib" />
|
||||
</target>
|
||||
<target name="doFetchJettylib" unless="jetty.available" >
|
||||
<echo message="The libraries contained within the fetched file are from Jetty's 5.1.2" />
|
||||
<echo message="The libraries contained within the fetched file are from Jetty's 5.1.6" />
|
||||
<echo message="distribution (http://jetty.mortbay.org/). These are not " />
|
||||
<echo message="necessary for using I2P, but are used by some applications on top of I2P," />
|
||||
<echo message="such as the routerconsole." />
|
||||
<get src="http://mesh.dl.sourceforge.net/sourceforge/jetty/jetty-5.1.2.zip" verbose="true" dest="jetty-5.1.2.zip" />
|
||||
<get src="http://mesh.dl.sourceforge.net/sourceforge/jetty/jetty-5.1.6.zip" verbose="true" dest="jetty-5.1.6.zip" />
|
||||
<ant target="doExtract" />
|
||||
</target>
|
||||
<target name="doExtract">
|
||||
<unzip src="jetty-5.1.2.zip" dest="." />
|
||||
<unzip src="jetty-5.1.6.zip" dest="." />
|
||||
<mkdir dir="jettylib" />
|
||||
<copy todir="jettylib">
|
||||
<fileset dir="jetty-5.1.2/lib">
|
||||
<fileset dir="jetty-5.1.6/lib">
|
||||
<include name="*.jar" />
|
||||
</fileset>
|
||||
</copy>
|
||||
<copy todir="jettylib">
|
||||
<fileset dir="jetty-5.1.2/ext">
|
||||
<fileset dir="jetty-5.1.6/ext">
|
||||
<include name="ant.jar" />
|
||||
<include name="commons-el.jar" />
|
||||
<include name="commons-logging.jar" />
|
||||
<include name="jasper-compiler.jar" />
|
||||
<include name="jasper-runtime.jar" />
|
||||
<include name="javax.servlet.jar" />
|
||||
@@ -34,7 +33,9 @@
|
||||
<include name="xercesImpl.jar" />
|
||||
</fileset>
|
||||
</copy>
|
||||
<delete dir="jetty-5.1.2" />
|
||||
<!-- note the rename, to keep compat with old rev, since we only used the API anyway -->
|
||||
<copy file="jetty-5.1.6/ext/commons-logging-api.jar" tofile="jettylib/commons-logging.jar" />
|
||||
<delete dir="jetty-5.1.6" />
|
||||
</target>
|
||||
<target name="build" depends="fetchJettylib" />
|
||||
<target name="builddep" />
|
||||
|
||||
@@ -63,6 +63,8 @@ public class ConfigStatsHandler extends FormHandler {
|
||||
|
||||
if (_explicitFilter) {
|
||||
_stats.clear();
|
||||
if (_explicitFilterValue == null)
|
||||
_explicitFilterValue = "";
|
||||
|
||||
if (_explicitFilterValue.indexOf(',') != -1) {
|
||||
StringTokenizer tok = new StringTokenizer(_explicitFilterValue, ",");
|
||||
|
||||
@@ -236,14 +236,14 @@ public class PacketHandler {
|
||||
}
|
||||
packet.releasePayload();
|
||||
} else {
|
||||
if (_log.shouldLog(Log.DEBUG) && !packet.isFlagSet(Packet.FLAG_SYNCHRONIZE))
|
||||
_log.debug("Packet received on an unknown stream (and not an ECHO or SYN): " + packet);
|
||||
//if (_log.shouldLog(Log.DEBUG) && !packet.isFlagSet(Packet.FLAG_SYNCHRONIZE))
|
||||
// _log.debug("Packet received on an unknown stream (and not an ECHO or SYN): " + packet);
|
||||
if (sendId <= 0) {
|
||||
Connection con = _manager.getConnectionByOutboundId(packet.getReceiveStreamId());
|
||||
if (con != null) {
|
||||
if ( (con.getHighestAckedThrough() <= 5) && (packet.getSequenceNum() <= 5) ) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Received additional packets before the syn on " + con + ": " + packet);
|
||||
//if (_log.shouldLog(Log.DEBUG))
|
||||
// _log.debug("Received additional packets before the syn on " + con + ": " + packet);
|
||||
receiveKnownCon(con, packet);
|
||||
return;
|
||||
} else {
|
||||
|
||||
@@ -14,6 +14,7 @@ import net.i2p.data.*;
|
||||
import net.i2p.syndie.*;
|
||||
import net.i2p.syndie.data.*;
|
||||
import net.i2p.syndie.sml.*;
|
||||
import net.i2p.util.FileUtil;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
@@ -75,7 +76,7 @@ public abstract class BaseServlet extends HttpServlet {
|
||||
public void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
req.setCharacterEncoding("UTF-8");
|
||||
resp.setCharacterEncoding("UTF-8");
|
||||
resp.setContentType("text/html");
|
||||
resp.setContentType("text/html;charset=UTF-8");
|
||||
|
||||
User user = (User)req.getSession().getAttribute("user");
|
||||
String login = req.getParameter("login");
|
||||
@@ -488,7 +489,27 @@ public abstract class BaseServlet extends HttpServlet {
|
||||
}
|
||||
|
||||
protected void renderBegin(User user, HttpServletRequest req, PrintWriter out, ThreadIndex index) throws IOException {
|
||||
out.write("<html>\n<head><title>" + getTitle() + "</title>\n" + BEGIN_HTML);
|
||||
out.write("<html>\n<head><title>" + getTitle() + "</title>\n");
|
||||
out.write("<style>");
|
||||
out.write(STYLE_HTML);
|
||||
Reader css = null;
|
||||
try {
|
||||
InputStream in = req.getSession().getServletContext().getResourceAsStream("/syndie.css");
|
||||
if (in != null) {
|
||||
css = new InputStreamReader(in, "UTF-8");
|
||||
char buf[] = new char[1024];
|
||||
int read = 0;
|
||||
while ( (read = css.read(buf)) != -1)
|
||||
out.write(buf, 0, read);
|
||||
}
|
||||
} finally {
|
||||
if (css != null)
|
||||
css.close();
|
||||
}
|
||||
String content = FileUtil.readTextFile("./docs/syndie_standard.css", -1, true);
|
||||
if (content != null) out.write(content);
|
||||
out.write("</style>");
|
||||
out.write(BEGIN_HTML);
|
||||
}
|
||||
protected void renderNavBar(User user, HttpServletRequest req, PrintWriter out, ThreadIndex index) throws IOException {
|
||||
//out.write("<tr class=\"topNav\"><td class=\"topNav_user\" colspan=\"2\" nowrap=\"true\">\n");
|
||||
@@ -899,8 +920,13 @@ public abstract class BaseServlet extends HttpServlet {
|
||||
}
|
||||
}
|
||||
|
||||
private static final String BEGIN_HTML = "<style>\n" +
|
||||
".overallTable {\n" +
|
||||
private static final String BEGIN_HTML = "<link href=\"rss.jsp\" rel=\"alternate\" type=\"application/rss+xml\" >\n" +
|
||||
"</head>\n" +
|
||||
"<body>\n" +
|
||||
"<span style=\"display: none\"><a href=\"#bodySubject\">Jump to the beginning of the first post rendered, if any</a>\n" +
|
||||
"<a href=\"#threads\">Jump to the thread navigation</a>\n</span>\n" +
|
||||
"<table border=\"0\" width=\"100%\" class=\"overallTable\">\n";
|
||||
private static final String STYLE_HTML = ".overallTable {\n" +
|
||||
" border-spacing: 0px;\n" +
|
||||
" border-width: 0px;\n" +
|
||||
" border: 0px;\n" +
|
||||
@@ -982,15 +1008,8 @@ public abstract class BaseServlet extends HttpServlet {
|
||||
"}\n" +
|
||||
".postReplyOptions {\n" +
|
||||
" background-color: #BBBBFF;\n" +
|
||||
"}\n" +
|
||||
"</style>\n" +
|
||||
"<link href=\"style.jsp\" rel=\"stylesheet\" type=\"text/css\" >\n" +
|
||||
"<link href=\"rss.jsp\" rel=\"alternate\" type=\"application/rss+xml\" >\n" +
|
||||
"</head>\n" +
|
||||
"<body>\n" +
|
||||
"<span style=\"display: none\"><a href=\"#bodySubject\">Jump to the beginning of the first post rendered, if any</a>\n" +
|
||||
"<a href=\"#threads\">Jump to the thread navigation</a>\n</span>\n" +
|
||||
"<table border=\"0\" width=\"100%\" class=\"overallTable\">\n";
|
||||
"}\n";
|
||||
|
||||
|
||||
private static final String END_HTML = "</table>\n" +
|
||||
"</body>\n";
|
||||
|
||||
424
apps/syndie/java/src/net/i2p/syndie/web/MultiPartRequest.java
Normal file
424
apps/syndie/java/src/net/i2p/syndie/web/MultiPartRequest.java
Normal file
@@ -0,0 +1,424 @@
|
||||
// see below for license info
|
||||
package net.i2p.syndie.web;
|
||||
|
||||
import org.mortbay.servlet.*;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.Hashtable;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.mortbay.http.HttpFields;
|
||||
import org.mortbay.util.LineInput;
|
||||
import org.mortbay.util.MultiMap;
|
||||
import org.mortbay.util.StringUtil;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Hacked version of Jetty's MultiPartRequest handler, applying a tiny patch for
|
||||
* charset handling [1]. These changes are public domain, and will hopefully
|
||||
* be integrated into Jetty so we can drop this file altogether. Of course,
|
||||
* until then, this file is APL2 licensed.
|
||||
*
|
||||
* Original code is up at [2]
|
||||
*
|
||||
* [1] http://article.gmane.org/gmane.comp.java.jetty.general/6031
|
||||
* [2] http://cvs.sourceforge.net/viewcvs.py/jetty/Jetty/src/org/mortbay/servlet/
|
||||
* (rev 1.15)
|
||||
*
|
||||
*/
|
||||
public class MultiPartRequest
|
||||
{
|
||||
/* ------------------------------------------------------------ */
|
||||
HttpServletRequest _request;
|
||||
LineInput _in;
|
||||
String _boundary;
|
||||
String _encoding;
|
||||
byte[] _byteBoundary;
|
||||
MultiMap _partMap = new MultiMap(10);
|
||||
int _char=-2;
|
||||
boolean _lastPart=false;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Constructor.
|
||||
* @param request The request containing a multipart/form-data
|
||||
* request
|
||||
* @exception IOException IOException
|
||||
*/
|
||||
public MultiPartRequest(HttpServletRequest request)
|
||||
throws IOException
|
||||
{
|
||||
_request=request;
|
||||
String content_type = request.getHeader(HttpFields.__ContentType);
|
||||
if (!content_type.startsWith("multipart/form-data"))
|
||||
throw new IOException("Not multipart/form-data request");
|
||||
|
||||
//if(log.isDebugEnabled())log.debug("Multipart content type = "+content_type);
|
||||
|
||||
_encoding = request.getCharacterEncoding();
|
||||
if (_encoding != null)
|
||||
_in = new LineInput(request.getInputStream(), 2048, _encoding);
|
||||
else
|
||||
_in = new LineInput(request.getInputStream());
|
||||
|
||||
// Extract boundary string
|
||||
_boundary="--"+
|
||||
value(content_type.substring(content_type.indexOf("boundary=")));
|
||||
|
||||
//if(log.isDebugEnabled())log.debug("Boundary="+_boundary);
|
||||
_byteBoundary= (_boundary+"--").getBytes(StringUtil.__ISO_8859_1);
|
||||
|
||||
loadAllParts();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Get the part names.
|
||||
* @return an array of part names
|
||||
*/
|
||||
public String[] getPartNames()
|
||||
{
|
||||
Set s = _partMap.keySet();
|
||||
return (String[]) s.toArray(new String[s.size()]);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Check if a named part is present
|
||||
* @param name The part
|
||||
* @return true if it was included
|
||||
*/
|
||||
public boolean contains(String name)
|
||||
{
|
||||
Part part = (Part)_partMap.get(name);
|
||||
return (part!=null);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Get the data of a part as a string.
|
||||
* @param name The part name
|
||||
* @return The part data
|
||||
*/
|
||||
public String getString(String name)
|
||||
{
|
||||
List part = (List)_partMap.getValues(name);
|
||||
if (part==null)
|
||||
return null;
|
||||
if (_encoding != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
return new String(((Part)part.get(0))._data, _encoding);
|
||||
}
|
||||
catch (UnsupportedEncodingException uee)
|
||||
{
|
||||
//if (log.isDebugEnabled()) log.debug("Invalid character set: " + uee);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return new String(((Part)part.get(0))._data);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param name The part name
|
||||
* @return The parts data
|
||||
*/
|
||||
public String[] getStrings(String name)
|
||||
{
|
||||
List parts = (List)_partMap.getValues(name);
|
||||
if (parts==null)
|
||||
return null;
|
||||
String[] strings = new String[parts.size()];
|
||||
if (_encoding == null) {
|
||||
for (int i=0; i<strings.length; i++) {
|
||||
strings[i] = new String(((Part)parts.get(i))._data);
|
||||
}
|
||||
} else {
|
||||
try
|
||||
{
|
||||
for (int i=0; i<strings.length; i++)
|
||||
strings[i] = new String(((Part)parts.get(i))._data, _encoding);
|
||||
}
|
||||
catch (UnsupportedEncodingException uee)
|
||||
{
|
||||
//if (log.isDebugEnabled()) log.debug("Invalid character set: " + uee);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return strings;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Get the data of a part as a stream.
|
||||
* @param name The part name
|
||||
* @return Stream providing the part data
|
||||
*/
|
||||
public InputStream getInputStream(String name)
|
||||
{
|
||||
List part = (List)_partMap.getValues(name);
|
||||
if (part==null)
|
||||
return null;
|
||||
return new ByteArrayInputStream(((Part)part.get(0))._data);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public InputStream[] getInputStreams(String name)
|
||||
{
|
||||
List parts = (List)_partMap.getValues(name);
|
||||
if (parts==null)
|
||||
return null;
|
||||
InputStream[] streams = new InputStream[parts.size()];
|
||||
for (int i=0; i<streams.length; i++) {
|
||||
streams[i] = new ByteArrayInputStream(((Part)parts.get(i))._data);
|
||||
}
|
||||
return streams;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Get the MIME parameters associated with a part.
|
||||
* @param name The part name
|
||||
* @return Hashtable of parameters
|
||||
*/
|
||||
public Hashtable getParams(String name)
|
||||
{
|
||||
List part = (List)_partMap.getValues(name);
|
||||
if (part==null)
|
||||
return null;
|
||||
return ((Part)part.get(0))._headers;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public Hashtable[] getMultipleParams(String name)
|
||||
{
|
||||
List parts = (List)_partMap.getValues(name);
|
||||
if (parts==null)
|
||||
return null;
|
||||
Hashtable[] params = new Hashtable[parts.size()];
|
||||
for (int i=0; i<params.length; i++) {
|
||||
params[i] = ((Part)parts.get(i))._headers;
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Get any file name associated with a part.
|
||||
* @param name The part name
|
||||
* @return The filename
|
||||
*/
|
||||
public String getFilename(String name)
|
||||
{
|
||||
List part = (List)_partMap.getValues(name);
|
||||
if (part==null)
|
||||
return null;
|
||||
return ((Part)part.get(0))._filename;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public String[] getFilenames(String name)
|
||||
{
|
||||
List parts = (List)_partMap.getValues(name);
|
||||
if (parts==null)
|
||||
return null;
|
||||
String[] filenames = new String[parts.size()];
|
||||
for (int i=0; i<filenames.length; i++) {
|
||||
filenames[i] = ((Part)parts.get(i))._filename;
|
||||
}
|
||||
return filenames;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private void loadAllParts()
|
||||
throws IOException
|
||||
{
|
||||
// Get first boundary
|
||||
String line = _in.readLine();
|
||||
if (!line.equals(_boundary))
|
||||
{
|
||||
//log.warn(line);
|
||||
throw new IOException("Missing initial multi part boundary");
|
||||
}
|
||||
|
||||
// Read each part
|
||||
while (!_lastPart)
|
||||
{
|
||||
// Read Part headers
|
||||
Part part = new Part();
|
||||
|
||||
String content_disposition=null;
|
||||
while ((line=_in.readLine())!=null)
|
||||
{
|
||||
// If blank line, end of part headers
|
||||
if (line.length()==0)
|
||||
break;
|
||||
|
||||
//if(log.isDebugEnabled())log.debug("LINE="+line);
|
||||
|
||||
// place part header key and value in map
|
||||
int c = line.indexOf(':',0);
|
||||
if (c>0)
|
||||
{
|
||||
String key = line.substring(0,c).trim().toLowerCase();
|
||||
String value = line.substring(c+1,line.length()).trim();
|
||||
String ev = (String) part._headers.get(key);
|
||||
part._headers.put(key,(ev!=null)?(ev+';'+value):value);
|
||||
//if(log.isDebugEnabled())log.debug(key+": "+value);
|
||||
if (key.equals("content-disposition"))
|
||||
content_disposition=value;
|
||||
}
|
||||
}
|
||||
|
||||
// Extract content-disposition
|
||||
boolean form_data=false;
|
||||
if (content_disposition==null)
|
||||
{
|
||||
throw new IOException("Missing content-disposition");
|
||||
}
|
||||
|
||||
StringTokenizer tok =
|
||||
new StringTokenizer(content_disposition,";");
|
||||
while (tok.hasMoreTokens())
|
||||
{
|
||||
String t = tok.nextToken().trim();
|
||||
String tl = t.toLowerCase();
|
||||
if (t.startsWith("form-data"))
|
||||
form_data=true;
|
||||
else if (tl.startsWith("name="))
|
||||
part._name=value(t);
|
||||
else if (tl.startsWith("filename="))
|
||||
part._filename=value(t);
|
||||
}
|
||||
|
||||
// Check disposition
|
||||
if (!form_data)
|
||||
{
|
||||
//log.warn("Non form-data part in multipart/form-data");
|
||||
continue;
|
||||
}
|
||||
if (part._name==null || part._name.length()==0)
|
||||
{
|
||||
//log.warn("Part with no name in multipart/form-data");
|
||||
continue;
|
||||
}
|
||||
//if(log.isDebugEnabled())log.debug("name="+part._name);
|
||||
//if(log.isDebugEnabled())log.debug("filename="+part._filename);
|
||||
_partMap.add(part._name,part);
|
||||
part._data=readBytes();
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private byte[] readBytes()
|
||||
throws IOException
|
||||
{
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
|
||||
int c;
|
||||
boolean cr=false;
|
||||
boolean lf=false;
|
||||
|
||||
// loop for all lines`
|
||||
while (true)
|
||||
{
|
||||
int b=0;
|
||||
while ((c=(_char!=-2)?_char:_in.read())!=-1)
|
||||
{
|
||||
_char=-2;
|
||||
|
||||
// look for CR and/or LF
|
||||
if (c==13 || c==10)
|
||||
{
|
||||
if (c==13) _char=_in.read();
|
||||
break;
|
||||
}
|
||||
|
||||
// look for boundary
|
||||
if (b>=0 && b<_byteBoundary.length && c==_byteBoundary[b])
|
||||
b++;
|
||||
else
|
||||
{
|
||||
// this is not a boundary
|
||||
if (cr) baos.write(13);
|
||||
if (lf) baos.write(10);
|
||||
cr=lf=false;
|
||||
|
||||
if (b>0)
|
||||
baos.write(_byteBoundary,0,b);
|
||||
b=-1;
|
||||
|
||||
baos.write(c);
|
||||
}
|
||||
}
|
||||
|
||||
// check partial boundary
|
||||
if ((b>0 && b<_byteBoundary.length-2) ||
|
||||
(b==_byteBoundary.length-1))
|
||||
{
|
||||
if (cr) baos.write(13);
|
||||
if (lf) baos.write(10);
|
||||
cr=lf=false;
|
||||
baos.write(_byteBoundary,0,b);
|
||||
b=-1;
|
||||
}
|
||||
|
||||
// boundary match
|
||||
if (b>0 || c==-1)
|
||||
{
|
||||
if (b==_byteBoundary.length)
|
||||
_lastPart=true;
|
||||
if (_char==10) _char=-2;
|
||||
break;
|
||||
}
|
||||
|
||||
// handle CR LF
|
||||
if (cr) baos.write(13);
|
||||
if (lf) baos.write(10);
|
||||
cr=(c==13);
|
||||
lf=(c==10 || _char==10);
|
||||
if (_char==10) _char=-2;
|
||||
}
|
||||
//if(log.isTraceEnabled())log.trace(baos.toString());
|
||||
return baos.toByteArray();
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private String value(String nameEqualsValue)
|
||||
{
|
||||
String value =
|
||||
nameEqualsValue.substring(nameEqualsValue.indexOf('=')+1).trim();
|
||||
|
||||
int i=value.indexOf(';');
|
||||
if (i>0)
|
||||
value=value.substring(0,i);
|
||||
if (value.startsWith("\""))
|
||||
{
|
||||
value=value.substring(1,value.indexOf('"',1));
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
i=value.indexOf(' ');
|
||||
if (i>0)
|
||||
value=value.substring(0,i);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private class Part
|
||||
{
|
||||
String _name=null;
|
||||
String _filename=null;
|
||||
Hashtable _headers= new Hashtable(10);
|
||||
byte[] _data=null;
|
||||
}
|
||||
};
|
||||
@@ -172,6 +172,7 @@ public class PostBean {
|
||||
private static final int MAX_SIZE = 256*1024;
|
||||
|
||||
private void cacheAttachments() throws IOException {
|
||||
if (_user == null) throw new IOException("User not specified");
|
||||
File postCacheDir = new File(BlogManager.instance().getTempDir(), _user.getBlog().toBase64());
|
||||
if (!postCacheDir.exists())
|
||||
postCacheDir.mkdirs();
|
||||
|
||||
@@ -8,7 +8,8 @@ import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
import org.mortbay.servlet.MultiPartRequest;
|
||||
// temporarily, we use our overwride, until jetty applies our patches
|
||||
//import org.mortbay.servlet.MultiPartRequest;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.client.naming.*;
|
||||
@@ -48,6 +49,8 @@ public class PostServlet extends BaseServlet {
|
||||
String action = req.getParameter(PARAM_ACTION);
|
||||
if (!empty(action) && ACTION_CONFIRM.equals(action)) {
|
||||
postEntry(user, req, archive, post, out);
|
||||
post.reinitialize();
|
||||
post.setUser(user);
|
||||
} else {
|
||||
String contentType = req.getContentType();
|
||||
if (!empty(contentType) && (contentType.indexOf("boundary=") != -1)) {
|
||||
@@ -72,8 +75,8 @@ public class PostServlet extends BaseServlet {
|
||||
|
||||
out.write("<tr><td colspan=\"3\">");
|
||||
|
||||
post.reinitialize();
|
||||
post.setUser(user);
|
||||
//post.reinitialize();
|
||||
//post.setUser(user);
|
||||
|
||||
boolean inNewThread = getInNewThread(req.getString(PARAM_IN_NEW_THREAD));
|
||||
boolean refuseReplies = getRefuseReplies(req.getString(PARAM_REFUSE_REPLIES));
|
||||
@@ -342,6 +345,7 @@ public class PostServlet extends BaseServlet {
|
||||
bean = new PostBean();
|
||||
req.getSession().setAttribute(ATTR_POST_BEAN, bean);
|
||||
}
|
||||
bean.setUser(user);
|
||||
return bean;
|
||||
}
|
||||
|
||||
|
||||
@@ -247,12 +247,34 @@ public class ViewThreadedServlet extends BaseServlet {
|
||||
}
|
||||
}
|
||||
|
||||
out.write(" @ ");
|
||||
out.write(": ");
|
||||
out.write("<a href=\"");
|
||||
out.write(getViewPostLink(req, node, user, false));
|
||||
out.write("\" title=\"View post\">");
|
||||
EntryContainer entry = archive.getEntry(node.getEntry());
|
||||
if (entry == null) throw new RuntimeException("Unable to fetch the entry " + node.getEntry());
|
||||
|
||||
HeaderReceiver rec = new HeaderReceiver();
|
||||
parser.parse(entry.getEntry().getText(), rec);
|
||||
String subject = rec.getHeader(HTMLRenderer.HEADER_SUBJECT);
|
||||
if (subject == null)
|
||||
subject = "(no subject)";
|
||||
out.write(trim(subject, 40));
|
||||
//out.write("</a>\n</td><td class=\"threadRight\">\n");
|
||||
out.write("</a>");
|
||||
|
||||
out.write(" (<a href=\"");
|
||||
out.write(getViewThreadLink(req, node, user));
|
||||
out.write("\" title=\"View all posts in the thread\">full thread</a>)\n");
|
||||
|
||||
out.write("</span><span class=\"threadInfoRight\">");
|
||||
|
||||
out.write(" <a href=\"");
|
||||
out.write(getViewPostLink(req, new BlogURI(node.getMostRecentPostAuthor(), node.getMostRecentPostDate()), user));
|
||||
out.write("\" title=\"View the most recent post\">latest - ");
|
||||
|
||||
long dayBegin = BlogManager.instance().getDayBegin();
|
||||
long postId = node.getEntry().getEntryId();
|
||||
long postId = node.getMostRecentPostDate();
|
||||
if (postId >= dayBegin) {
|
||||
out.write("<b>today</b>");
|
||||
} else if (postId >= dayBegin - 24*60*60*1000) {
|
||||
@@ -261,39 +283,13 @@ public class ViewThreadedServlet extends BaseServlet {
|
||||
int daysAgo = (int)((dayBegin - postId + 24*60*60*1000-1)/(24*60*60*1000));
|
||||
out.write(daysAgo + " days ago");
|
||||
}
|
||||
|
||||
out.write(": ");
|
||||
EntryContainer entry = archive.getEntry(node.getEntry());
|
||||
if (entry == null) throw new RuntimeException("Unable to fetch the entry " + node.getEntry());
|
||||
|
||||
HeaderReceiver rec = new HeaderReceiver();
|
||||
parser.parse(entry.getEntry().getText(), rec);
|
||||
String subject = rec.getHeader(HTMLRenderer.HEADER_SUBJECT);
|
||||
if (subject == null)
|
||||
subject = "";
|
||||
out.write(trim(subject, 40));
|
||||
//out.write("</a>\n</td><td class=\"threadRight\">\n");
|
||||
out.write("</a></span><span class=\"threadInfoRight\">");
|
||||
if (childCount > 0) {
|
||||
out.write(" <a href=\"");
|
||||
out.write(getViewPostLink(req, new BlogURI(node.getMostRecentPostAuthor(), node.getMostRecentPostDate()), user));
|
||||
out.write("\" title=\"View the most recent post\">latest - ");
|
||||
|
||||
postId = node.getMostRecentPostDate();
|
||||
if (postId >= dayBegin) {
|
||||
out.write("<b>today</b>");
|
||||
} else if (postId >= dayBegin - 24*60*60*1000) {
|
||||
out.write("<b>yesterday</b>");
|
||||
} else {
|
||||
int daysAgo = (int)((dayBegin - postId + 24*60*60*1000-1)/(24*60*60*1000));
|
||||
out.write(daysAgo + " days ago");
|
||||
}
|
||||
|
||||
out.write("</a>\n");
|
||||
}
|
||||
out.write("</a>\n");
|
||||
/*
|
||||
out.write(" <a href=\"");
|
||||
out.write(getViewThreadLink(req, node, user));
|
||||
out.write("\" title=\"View all posts in the thread\">full thread</a>\n");
|
||||
*/
|
||||
out.write("</span>");
|
||||
out.write("</td></tr>\n");
|
||||
|
||||
|
||||
20
build.xml
20
build.xml
@@ -233,8 +233,6 @@
|
||||
<copy file="build/routerconsole.jar" todir="pkg-temp/lib/" />
|
||||
<copy file="build/sam.jar" todir="pkg-temp/lib/" />
|
||||
<copy file="build/systray.jar" todir="pkg-temp/lib" />
|
||||
<copy file="build/jdom.jar" todir="pkg-temp/lib" />
|
||||
<copy file="build/rome-0.7.jar" todir="pkg-temp/lib" />
|
||||
<copy file="build/sucker.jar" todir="pkg-temp/lib" />
|
||||
<copy file="build/i2psnark.jar" todir="pkg-temp/lib/" />
|
||||
<copy file="i2p.exe" todir="pkg-temp/" failonerror="false" />
|
||||
@@ -341,30 +339,14 @@
|
||||
<copy file="build/sam.jar" todir="pkg-temp/lib/" />
|
||||
<copy file="build/router.jar" todir="pkg-temp/lib/" />
|
||||
<copy file="build/routerconsole.jar" todir="pkg-temp/lib/" />
|
||||
<!-- for the 0.6.1.3 release, push JDOM and ROME. it can be
|
||||
removed later updates (once people on earlier builds upgrade -->
|
||||
<copy file="build/jdom.jar" todir="pkg-temp/lib" />
|
||||
<copy file="build/rome-0.7.jar" todir="pkg-temp/lib" />
|
||||
<copy file="build/sucker.jar" todir="pkg-temp/lib" />
|
||||
<copy file="build/i2psnark.jar" todir="pkg-temp/lib" />
|
||||
|
||||
<copy file="i2p.exe" todir="pkg-temp/" failonerror="false" />
|
||||
<copy file="installer/resources/runplain.sh" todir="pkg-temp/" />
|
||||
|
||||
<!-- for the i2p 0.5 release, push jetty 5.2.1 -->
|
||||
<!--
|
||||
<copy file="build/jasper-compiler.jar" todir="pkg-temp/lib/" />
|
||||
<copy file="build/jasper-runtime.jar" todir="pkg-temp/lib/" />
|
||||
<!-- for 0.6.1.7, push jetty 5.1.6 -->
|
||||
<copy file="build/commons-logging.jar" todir="pkg-temp/lib/" />
|
||||
<copy file="build/commons-el.jar" todir="pkg-temp/lib/" />
|
||||
<copy file="build/org.mortbay.jetty.jar" todir="pkg-temp/lib/" />
|
||||
<copy file="build/javax.servlet.jar" todir="pkg-temp/lib/" />
|
||||
-->
|
||||
<!-- requires commons-* to be added to the classpath (boo, hiss) -->
|
||||
<!--
|
||||
<copy file="installer/resources/wrapper.config" todir="pkg-temp/" />
|
||||
<touch file="pkg-temp/wrapper.config.updated" />
|
||||
-->
|
||||
|
||||
<copy file="build/i2ptunnel.war" todir="pkg-temp/webapps/" />
|
||||
<copy file="build/routerconsole.war" todir="pkg-temp/webapps/" />
|
||||
|
||||
@@ -14,8 +14,8 @@ package net.i2p;
|
||||
*
|
||||
*/
|
||||
public class CoreVersion {
|
||||
public final static String ID = "$Revision: 1.48 $ $Date: 2005/11/15 22:20:21 $";
|
||||
public final static String VERSION = "0.6.1.6";
|
||||
public final static String ID = "$Revision: 1.49 $ $Date: 2005/11/26 13:26:22 $";
|
||||
public final static String VERSION = "0.6.1.7";
|
||||
|
||||
public static void main(String args[]) {
|
||||
System.out.println("I2P Core version: " + VERSION);
|
||||
|
||||
@@ -818,7 +818,7 @@ public class DataHelper {
|
||||
return ms + "ms";
|
||||
} else if (ms < 5 * 60 * 1000) {
|
||||
return (ms / 1000) + "s";
|
||||
} else if (ms < 90 * 60 * 1000) {
|
||||
} else if (ms < 120 * 60 * 1000) {
|
||||
return (ms / (60 * 1000)) + "m";
|
||||
} else if (ms < 3 * 24 * 60 * 60 * 1000) {
|
||||
return (ms / (60 * 60 * 1000)) + "h";
|
||||
|
||||
@@ -631,7 +631,8 @@ public class EepGet {
|
||||
buf.append(_alreadyTransferred);
|
||||
buf.append("-\r\n");
|
||||
}
|
||||
buf.append("Accept-Encoding: identity;q=1, *;q=0\r\n");
|
||||
buf.append("Accept-Encoding: \r\n");
|
||||
buf.append("X-Accept-Encoding: x-i2p-gzip;q=1.0, identity;q=0.5, deflate;q=0, gzip;q=0, *;q=0\r\n");
|
||||
if (!_allowCaching) {
|
||||
buf.append("Cache-control: no-cache\r\n");
|
||||
buf.append("Pragma: no-cache\r\n");
|
||||
|
||||
61
history.txt
61
history.txt
@@ -1,4 +1,63 @@
|
||||
$Id: history.txt,v 1.333 2005/11/26 11:51:20 jrandom Exp $
|
||||
$Id: history.txt,v 1.340 2005/11/30 20:13:45 jrandom Exp $
|
||||
|
||||
* 2005-12-01 0.6.1.7 released
|
||||
|
||||
2005-12-01 jrandom
|
||||
* Add a new criteria to the tunnel join throttle, backing off people if we
|
||||
are failing to talk to our peers more than usual.
|
||||
|
||||
2005-11-30 jrandom
|
||||
* Cleaned up the build process to deal with Jetty 5.1.6 and rename the
|
||||
new commons-logging-api.jar to commons-logging.jar, which it replaces.
|
||||
Jetty 5.1.6 is pushed with all updates. Also, no need to push a
|
||||
separate jdom or rome, as they're inside syndie.war.
|
||||
|
||||
2005-11-30 jrandom
|
||||
* Don't let the TCP transport alone shitlist a peer, since other
|
||||
transports may be working. Also display whether TCP connections are
|
||||
inbound or outbound on the peers page.
|
||||
* Fixed some substantial bugs in the SSU introducers where we wouldn't
|
||||
talk to anyone who didn't expose an IP (even if they had introducers),
|
||||
among other goofy things.
|
||||
* When dealing with SSU introducers, send them all a packet at 3s/6s/9s,
|
||||
rather than sending one a packet at 3s, then another a packet at 6s,
|
||||
and a third a packet at 9s.
|
||||
* Fixed Syndie attachments (oops)
|
||||
|
||||
2005-11-29 zzz
|
||||
* Added a link to orion's jump page on the 'key not found' error page.
|
||||
|
||||
2005-11-29 jrandom
|
||||
* Further Syndie UI cleanup
|
||||
* Bundled our patched MultiPartRequest code from jetty (APL2 licensed),
|
||||
since it hasn't been applied to the jetty CVS yet [1]. Its packaged
|
||||
into syndie.jar and renamed to net.i2p.syndie.web.MultiPartRequest, but
|
||||
will be removed as soon as its integrated into Jetty. This patch allows
|
||||
posting content in various character sets.
|
||||
[1] http://article.gmane.org/gmane.comp.java.jetty.general/6031
|
||||
* Upgraded new installs to the latest stable jetty (5.1.6), though this
|
||||
isn't pushed as part of the update yet, as there aren't any critical
|
||||
bugs.
|
||||
|
||||
2005-11-29 jrandom
|
||||
* Added back in the OSX jbigi, which was accidentally removed a few revs
|
||||
back (thanks for the bug report stoerte!) New installs will get the
|
||||
full jbigi, or you can pull the jbigi.jar from CVS by going to
|
||||
http://dev.i2p.net/cgi-bin/cvsweb.cgi/i2p/installer/lib/jbigi/jbigi.jar
|
||||
and clicking on the first "download" link, saving that jbigi.jar to
|
||||
lib/jbigi.jar in your I2P installation directory. After restarting your
|
||||
router, it should load up fine.
|
||||
|
||||
2005-11-27 jrandom
|
||||
* Inlined the Syndie CSS to reduce the number of HTTP requests (and
|
||||
because firefox [and others?] delay rendering until they fetch the css).
|
||||
* Make sure we fire the shutdown tasks when regenerating a new identity
|
||||
(thanks picsou!)
|
||||
* Cleaned up some of the things I b0rked in the 'dynamic keys' mode
|
||||
* Don't drop SSU sessions if they're still transmitting data successfully,
|
||||
even if there are transmission failures
|
||||
* Adjusted the time summarization to display hours after 119m, not 90m
|
||||
* Further EepGet cleanup (grr)
|
||||
|
||||
* 2005-11-26 0.6.1.6 released
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<i2p.news date="$Date: 2005/11/15 22:20:22 $">
|
||||
<i2p.release version="0.6.1.6" date="2005/11/26" minVersion="0.6"
|
||||
<i2p.news date="$Date: 2005/11/26 13:26:24 $">
|
||||
<i2p.release version="0.6.1.7" date="2005/12/01" minVersion="0.6"
|
||||
anonurl="http://i2p/NF2RLVUxVulR3IqK0sGJR0dHQcGXAzwa6rEO4WAWYXOHw-DoZhKnlbf1nzHXwMEJoex5nFTyiNMqxJMWlY54cvU~UenZdkyQQeUSBZXyuSweflUXFqKN-y8xIoK2w9Ylq1k8IcrAFDsITyOzjUKoOPfVq34rKNDo7fYyis4kT5bAHy~2N1EVMs34pi2RFabATIOBk38Qhab57Umpa6yEoE~rbyR~suDRvD7gjBvBiIKFqhFueXsR2uSrPB-yzwAGofTXuklofK3DdKspciclTVzqbDjsk5UXfu2nTrC1agkhLyqlOfjhyqC~t1IXm-Vs2o7911k7KKLGjB4lmH508YJ7G9fLAUyjuB-wwwhejoWqvg7oWvqo4oIok8LG6ECR71C3dzCvIjY2QcrhoaazA9G4zcGMm6NKND-H4XY6tUWhpB~5GefB3YczOqMbHq4wi0O9MzBFrOJEOs3X4hwboKWANf7DT5PZKJZ5KorQPsYRSq0E3wSOsFCSsdVCKUGsAAAA/i2p/i2pupdate.sud"
|
||||
publicurl="http://dev.i2p.net/i2p/i2pupdate.sud"
|
||||
anonannouncement="http://i2p/NF2RLVUxVulR3IqK0sGJR0dHQcGXAzwa6rEO4WAWYXOHw-DoZhKnlbf1nzHXwMEJoex5nFTyiNMqxJMWlY54cvU~UenZdkyQQeUSBZXyuSweflUXFqKN-y8xIoK2w9Ylq1k8IcrAFDsITyOzjUKoOPfVq34rKNDo7fYyis4kT5bAHy~2N1EVMs34pi2RFabATIOBk38Qhab57Umpa6yEoE~rbyR~suDRvD7gjBvBiIKFqhFueXsR2uSrPB-yzwAGofTXuklofK3DdKspciclTVzqbDjsk5UXfu2nTrC1agkhLyqlOfjhyqC~t1IXm-Vs2o7911k7KKLGjB4lmH508YJ7G9fLAUyjuB-wwwhejoWqvg7oWvqo4oIok8LG6ECR71C3dzCvIjY2QcrhoaazA9G4zcGMm6NKND-H4XY6tUWhpB~5GefB3YczOqMbHq4wi0O9MzBFrOJEOs3X4hwboKWANf7DT5PZKJZ5KorQPsYRSq0E3wSOsFCSsdVCKUGsAAAA/pipermail/i2p/2005-September/000878.html"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
<info>
|
||||
<appname>i2p</appname>
|
||||
<appversion>0.6.1.6</appversion>
|
||||
<appversion>0.6.1.7</appversion>
|
||||
<authors>
|
||||
<author name="I2P" email="support@i2p.net"/>
|
||||
</authors>
|
||||
|
||||
@@ -9,3 +9,6 @@ being compiled by jrandom on osx/ppc with GMP-4.1.4.
|
||||
On Sep 18, 2005, libjbigi-linux-athlon64.so was added to jbigi.jar after
|
||||
being compiled by jrandom on linux/p4 (cross compiled to --host=x86_64)
|
||||
with GMP-4.1.4.
|
||||
|
||||
On Nov 29, 2005, the libjbigi-osx-none.jnilib was added back to
|
||||
jbigi.jar after being mistakenly removed in the Sep 18 update (d'oh!)
|
||||
|
||||
Binary file not shown.
Binary file not shown.
4
news.xml
4
news.xml
@@ -1,5 +1,5 @@
|
||||
<i2p.news date="$Date: 2005/11/15 22:20:22 $">
|
||||
<i2p.release version="0.6.1.6" date="2005/11/26" minVersion="0.6"
|
||||
<i2p.news date="$Date: 2005/11/26 13:26:24 $">
|
||||
<i2p.release version="0.6.1.7" date="2005/12/01" minVersion="0.6"
|
||||
anonurl="http://i2p/NF2RLVUxVulR3IqK0sGJR0dHQcGXAzwa6rEO4WAWYXOHw-DoZhKnlbf1nzHXwMEJoex5nFTyiNMqxJMWlY54cvU~UenZdkyQQeUSBZXyuSweflUXFqKN-y8xIoK2w9Ylq1k8IcrAFDsITyOzjUKoOPfVq34rKNDo7fYyis4kT5bAHy~2N1EVMs34pi2RFabATIOBk38Qhab57Umpa6yEoE~rbyR~suDRvD7gjBvBiIKFqhFueXsR2uSrPB-yzwAGofTXuklofK3DdKspciclTVzqbDjsk5UXfu2nTrC1agkhLyqlOfjhyqC~t1IXm-Vs2o7911k7KKLGjB4lmH508YJ7G9fLAUyjuB-wwwhejoWqvg7oWvqo4oIok8LG6ECR71C3dzCvIjY2QcrhoaazA9G4zcGMm6NKND-H4XY6tUWhpB~5GefB3YczOqMbHq4wi0O9MzBFrOJEOs3X4hwboKWANf7DT5PZKJZ5KorQPsYRSq0E3wSOsFCSsdVCKUGsAAAA/i2p/i2pupdate.sud"
|
||||
publicurl="http://dev.i2p.net/i2p/i2pupdate.sud"
|
||||
anonannouncement="http://i2p/NF2RLVUxVulR3IqK0sGJR0dHQcGXAzwa6rEO4WAWYXOHw-DoZhKnlbf1nzHXwMEJoex5nFTyiNMqxJMWlY54cvU~UenZdkyQQeUSBZXyuSweflUXFqKN-y8xIoK2w9Ylq1k8IcrAFDsITyOzjUKoOPfVq34rKNDo7fYyis4kT5bAHy~2N1EVMs34pi2RFabATIOBk38Qhab57Umpa6yEoE~rbyR~suDRvD7gjBvBiIKFqhFueXsR2uSrPB-yzwAGofTXuklofK3DdKspciclTVzqbDjsk5UXfu2nTrC1agkhLyqlOfjhyqC~t1IXm-Vs2o7911k7KKLGjB4lmH508YJ7G9fLAUyjuB-wwwhejoWqvg7oWvqo4oIok8LG6ECR71C3dzCvIjY2QcrhoaazA9G4zcGMm6NKND-H4XY6tUWhpB~5GefB3YczOqMbHq4wi0O9MzBFrOJEOs3X4hwboKWANf7DT5PZKJZ5KorQPsYRSq0E3wSOsFCSsdVCKUGsAAAA/pipermail/i2p/2005-September/000878.html"
|
||||
|
||||
@@ -38,8 +38,6 @@ import net.i2p.data.i2np.GarlicMessage;
|
||||
import net.i2p.router.message.GarlicMessageHandler;
|
||||
//import net.i2p.router.message.TunnelMessageHandler;
|
||||
import net.i2p.router.networkdb.kademlia.FloodfillNetworkDatabaseFacade;
|
||||
import net.i2p.router.transport.udp.UDPTransport;
|
||||
import net.i2p.router.transport.udp.UDPAddress;
|
||||
import net.i2p.router.startup.StartupJob;
|
||||
import net.i2p.stat.Rate;
|
||||
import net.i2p.stat.RateStat;
|
||||
@@ -218,51 +216,6 @@ public class Router {
|
||||
_context.jobQueue().addJob(new PersistRouterInfoJob());
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when our RouterInfo is loaded by LoadRouterInfoJob
|
||||
* to store our most recently known address to determine if
|
||||
* it has changed while we were down.
|
||||
*/
|
||||
public boolean updateExternalAddress(Collection addrs, boolean reboot) {
|
||||
if ("false".equalsIgnoreCase(_context.getProperty(Router.PROP_DYNAMIC_KEYS, "false")))
|
||||
return false; // no one cares. pretend it didn't change
|
||||
boolean ret = false;
|
||||
for (Iterator i = addrs.iterator(); i.hasNext(); ) {
|
||||
RouterAddress addr = (RouterAddress)i.next();
|
||||
if (UDPTransport.STYLE.equalsIgnoreCase(addr.getTransportStyle()))
|
||||
ret = updateExternalAddress(addr, reboot);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by TransportImpl.replaceAddress to notify the router of an
|
||||
* address change. It is the caller's responsibility to make sure this
|
||||
* really is a substantial change.
|
||||
*
|
||||
*/
|
||||
public boolean updateExternalAddress(RouterAddress addr, boolean rebootRouter) {
|
||||
String newExternal = null;
|
||||
// TCP is often incorrectly initialized to 83.246.74.28 for some
|
||||
// reason. Numerous hosts in the netdb report this address for TCP.
|
||||
// It is also easier to lie over the TCP transport. So only trust UDP.
|
||||
if (!UDPTransport.STYLE.equalsIgnoreCase(addr.getTransportStyle()))
|
||||
return false;
|
||||
|
||||
if ("false".equalsIgnoreCase(_context.getProperty(Router.PROP_DYNAMIC_KEYS, "false")))
|
||||
return false; // no one cares. pretend it didn't change
|
||||
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Rekeying and restarting due to " + addr.getTransportStyle()
|
||||
+ " address update. new address: " + addr);
|
||||
if (rebootRouter) {
|
||||
_context.router().rebuildNewIdentity();
|
||||
} else {
|
||||
_context.router().killKeys();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* True if the router has tried to communicate with another router who is running a higher
|
||||
* incompatible protocol version.
|
||||
@@ -459,6 +412,14 @@ public class Router {
|
||||
*/
|
||||
public void rebuildNewIdentity() {
|
||||
killKeys();
|
||||
try {
|
||||
for (Iterator iter = _shutdownTasks.iterator(); iter.hasNext(); ) {
|
||||
Runnable task = (Runnable)iter.next();
|
||||
task.run();
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
_log.log(Log.CRIT, "Error running shutdown task", t);
|
||||
}
|
||||
// hard and ugly
|
||||
finalShutdown(EXIT_HARD_RESTART);
|
||||
}
|
||||
@@ -870,6 +831,9 @@ public class Router {
|
||||
public void finalShutdown(int exitCode) {
|
||||
_log.log(Log.CRIT, "Shutdown(" + exitCode + ") complete", new Exception("Shutdown"));
|
||||
try { _context.logManager().shutdown(); } catch (Throwable t) { }
|
||||
if ("true".equalsIgnoreCase(_context.getProperty(PROP_DYNAMIC_KEYS, "false")))
|
||||
killKeys();
|
||||
|
||||
File f = new File(getPingFile());
|
||||
f.delete();
|
||||
if (_killVMOnEnd) {
|
||||
|
||||
@@ -52,6 +52,7 @@ class RouterThrottleImpl implements RouterThrottle {
|
||||
_context.statManager().createRateStat("router.throttleTunnelBandwidthExceeded", "How much bandwidth is allocated when we refuse due to bandwidth allocation?", "Throttle", new long[] { 10*60*1000, 60*60*1000, 24*60*60*1000 });
|
||||
_context.statManager().createRateStat("router.throttleTunnelBytesAllowed", "How many bytes are allowed to be sent when we get a tunnel request (period is how many are currently allocated)?", "Throttle", new long[] { 10*60*1000, 60*60*1000, 24*60*60*1000 });
|
||||
_context.statManager().createRateStat("router.throttleTunnelBytesUsed", "Used Bps at request (period = max KBps)?", "Throttle", new long[] { 10*60*1000, 60*60*1000, 24*60*60*1000 });
|
||||
_context.statManager().createRateStat("router.throttleTunnelFailCount1m", "How many messages failed to be sent in the last 2 minutes when we throttle based on a spike in failures (period = 10 minute average failure count)?", "Throttle", new long[] { 60*1000, 10*60*1000, 60*60*1000});
|
||||
}
|
||||
|
||||
public boolean acceptNetworkMessage() {
|
||||
@@ -79,6 +80,12 @@ class RouterThrottleImpl implements RouterThrottle {
|
||||
}
|
||||
|
||||
public int acceptTunnelRequest(TunnelCreateMessage msg) {
|
||||
if (_context.getProperty(Router.PROP_SHUTDOWN_IN_PROGRESS) != null) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Refusing tunnel request since we are shutting down ASAP");
|
||||
return TunnelHistory.TUNNEL_REJECT_CRIT;
|
||||
}
|
||||
|
||||
long lag = _context.jobQueue().getMaxLag();
|
||||
RateStat rs = _context.statManager().getRate("router.throttleNetworkCause");
|
||||
Rate r = null;
|
||||
@@ -117,14 +124,27 @@ class RouterThrottleImpl implements RouterThrottle {
|
||||
return TunnelHistory.TUNNEL_REJECT_TRANSIENT_OVERLOAD;
|
||||
}
|
||||
|
||||
int numTunnels = _context.tunnelManager().getParticipatingCount();
|
||||
|
||||
if (_context.getProperty(Router.PROP_SHUTDOWN_IN_PROGRESS) != null) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Refusing tunnel request since we are shutting down ASAP");
|
||||
return TunnelHistory.TUNNEL_REJECT_CRIT;
|
||||
rs = _context.statManager().getRate("transport.sendMessageFailureLifetime");
|
||||
r = null;
|
||||
if (rs != null)
|
||||
r = rs.getRate(60*1000);
|
||||
double failCount = (r != null ? r.getCurrentEventCount() + r.getLastEventCount() : 0);
|
||||
if (failCount > 100) {
|
||||
long periods = r.getLifetimePeriods();
|
||||
long maxFailCount = r.getExtremeEventCount();
|
||||
if ( (periods > 0) && (maxFailCount > 100) ) {
|
||||
if (_context.random().nextInt((int)maxFailCount) <= failCount) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Refusing tunnel request with the job lag of " + lag
|
||||
+ "since the 1 minute message failure count is too high (" + failCount + "/" + maxFailCount + ")");
|
||||
_context.statManager().addRateData("router.throttleTunnelFailCount1m", (long)failCount, (long)maxFailCount);
|
||||
return TunnelHistory.TUNNEL_REJECT_TRANSIENT_OVERLOAD;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int numTunnels = _context.tunnelManager().getParticipatingCount();
|
||||
|
||||
if (numTunnels > getMinThrottleTunnels()) {
|
||||
double growthFactor = getTunnelGrowthFactor();
|
||||
Rate avgTunnels = _context.statManager().getRate("tunnel.participatingTunnels").getRate(60*60*1000);
|
||||
|
||||
@@ -15,8 +15,8 @@ import net.i2p.CoreVersion;
|
||||
*
|
||||
*/
|
||||
public class RouterVersion {
|
||||
public final static String ID = "$Revision: 1.301 $ $Date: 2005/11/26 11:51:19 $";
|
||||
public final static String VERSION = "0.6.1.6";
|
||||
public final static String ID = "$Revision: 1.306 $ $Date: 2005/11/30 15:48:26 $";
|
||||
public final static String VERSION = "0.6.1.7";
|
||||
public final static long BUILD = 0;
|
||||
public static void main(String args[]) {
|
||||
System.out.println("I2P Router version: " + VERSION + "-" + BUILD);
|
||||
|
||||
@@ -68,8 +68,8 @@ class FloodfillPeerSelector extends PeerSelector {
|
||||
}
|
||||
public List getFloodfillParticipants() { return _floodfillMatches; }
|
||||
public void add(Hash entry) {
|
||||
if (_context.profileOrganizer().isFailing(entry))
|
||||
return;
|
||||
//if (_context.profileOrganizer().isFailing(entry))
|
||||
// return;
|
||||
if ( (_toIgnore != null) && (_toIgnore.contains(entry)) )
|
||||
return;
|
||||
if (entry.equals(_context.routerHash()))
|
||||
|
||||
@@ -657,8 +657,8 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
|
||||
}
|
||||
} else if (routerInfo.getPublished() > now + Router.CLOCK_FUDGE_FACTOR) {
|
||||
long age = routerInfo.getPublished() - _context.clock().now();
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Peer " + key.toBase64() + " published their routerInfo in the future?! ["
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Peer " + key.toBase64() + " published their routerInfo in the future?! ["
|
||||
+ new Date(routerInfo.getPublished()) + "]", new Exception("Rejecting store"));
|
||||
return "Peer " + key.toBase64() + " published " + DataHelper.formatDuration(age) + " in the future?!";
|
||||
} else if (_enforceNetId && (routerInfo.getNetworkId() != Router.NETWORK_ID) ){
|
||||
|
||||
@@ -11,8 +11,6 @@ package net.i2p.router.startup;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
import net.i2p.data.DataFormatException;
|
||||
import net.i2p.data.PrivateKey;
|
||||
@@ -78,7 +76,6 @@ public class LoadRouterInfoJob extends JobImpl {
|
||||
fis1 = new FileInputStream(rif);
|
||||
info = new RouterInfo();
|
||||
info.readBytes(fis1);
|
||||
getContext().router().updateExternalAddress(info.getAddresses(), false);
|
||||
_log.debug("Reading in routerInfo from " + rif.getAbsolutePath() + " and it has " + info.getAddresses().size() + " addresses");
|
||||
}
|
||||
|
||||
|
||||
@@ -169,6 +169,7 @@ public class ConnectionHandler {
|
||||
if (_error == null) {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Establishment successful! returning the con");
|
||||
con.setIsOutbound(false);
|
||||
return con;
|
||||
} else {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
|
||||
@@ -43,6 +43,7 @@ public class TCPConnection {
|
||||
private long _lastRead;
|
||||
private long _lastWrite;
|
||||
private long _offsetReceived;
|
||||
private boolean _isOutbound;
|
||||
|
||||
public TCPConnection(RouterContext ctx) {
|
||||
_context = ctx;
|
||||
@@ -60,6 +61,7 @@ public class TCPConnection {
|
||||
_lastRead = 0;
|
||||
_lastWrite = 0;
|
||||
_offsetReceived = 0;
|
||||
_isOutbound = false;
|
||||
_runner = new ConnectionRunner(_context, this);
|
||||
_context.statManager().createRateStat("tcp.probabalisticDropQueueSize", "How many bytes were queued to be sent when a message as dropped probabalistically?", "TCP", new long[] { 60*1000l, 10*60*1000l, 60*60*1000l, 24*60*60*1000l } );
|
||||
_context.statManager().createRateStat("tcp.queueSize", "How many bytes were queued on a connection?", "TCP", new long[] { 60*1000l, 10*60*1000l, 60*60*1000l, 24*60*60*1000l } );
|
||||
@@ -86,6 +88,8 @@ public class TCPConnection {
|
||||
public long getOffsetReceived() { return _offsetReceived; }
|
||||
public void setOffsetReceived(long ms) { _offsetReceived = ms; }
|
||||
public TCPTransport getTransport() { return _transport; }
|
||||
public boolean getIsOutbound() { return _isOutbound; }
|
||||
public void setIsOutbound(boolean outbound) { _isOutbound = outbound; }
|
||||
|
||||
/**
|
||||
* Actually start processing the messages on the connection (and reading
|
||||
|
||||
@@ -47,14 +47,17 @@ public class TCPConnectionEstablisher implements Runnable {
|
||||
+ info.getIdentity().getHash().toBase64(), e);
|
||||
}
|
||||
if (con != null) {
|
||||
con.setIsOutbound(true);
|
||||
_transport.connectionEstablished(con);
|
||||
} else {
|
||||
if (!_context.router().isAlive()) return;
|
||||
_transport.addConnectionErrorMessage(cb.getError());
|
||||
Hash peer = info.getIdentity().getHash();
|
||||
_context.profileManager().commErrorOccurred(peer);
|
||||
_context.shitlist().shitlistRouter(peer, "Unable to contact");
|
||||
_context.netDb().fail(peer);
|
||||
// disabling in preparation for dropping tcp, since other transports may work, and
|
||||
// hence shitlisting is not appropriate
|
||||
//_context.shitlist().shitlistRouter(peer, "Unable to contact");
|
||||
//_context.netDb().fail(peer);
|
||||
}
|
||||
|
||||
// this removes the _pending block on the address and
|
||||
|
||||
@@ -783,12 +783,21 @@ public class TCPTransport extends TransportImpl {
|
||||
/** Make this stuff pretty (only used in the old console) */
|
||||
public void renderStatusHTML(Writer out) throws IOException {
|
||||
StringBuffer buf = new StringBuffer(1024);
|
||||
int outbound = 0;
|
||||
int inbound = 0;
|
||||
synchronized (_connectionLock) {
|
||||
long offsetTotal = 0;
|
||||
buf.append("<b>Connections (").append(_connectionsByIdent.size()).append("):</b><ul>\n");
|
||||
for (Iterator iter = _connectionsByIdent.values().iterator(); iter.hasNext(); ) {
|
||||
TCPConnection con = (TCPConnection)iter.next();
|
||||
buf.append("<li>");
|
||||
if (con.getIsOutbound()) {
|
||||
outbound++;
|
||||
buf.append("Outbound to ");
|
||||
} else {
|
||||
inbound++;
|
||||
buf.append("Inbound from ");
|
||||
}
|
||||
buf.append(con.getRemoteRouterIdentity().getHash().toBase64().substring(0,6));
|
||||
buf.append(": up for ").append(DataHelper.formatDuration(con.getLifetime()));
|
||||
buf.append(" transferring at ");
|
||||
@@ -817,6 +826,7 @@ public class TCPTransport extends TransportImpl {
|
||||
buf.append("</li>\n");
|
||||
}
|
||||
buf.append("</ul>\n");
|
||||
buf.append("<b>Inbound: ").append(inbound).append(", Outbound: ").append(outbound).append("</b><br />\n");
|
||||
}
|
||||
|
||||
buf.append("<b>Most recent connection errors:</b><ul>");
|
||||
|
||||
@@ -126,19 +126,26 @@ public class EstablishmentManager {
|
||||
return;
|
||||
}
|
||||
UDPAddress addr = new UDPAddress(ra);
|
||||
RemoteHostId to = null;
|
||||
InetAddress remAddr = addr.getHostAddress();
|
||||
int port = addr.getPort();
|
||||
RemoteHostId to = new RemoteHostId(remAddr.getAddress(), port);
|
||||
|
||||
if (!_transport.isValid(to.getIP())) {
|
||||
_transport.failed(msg);
|
||||
_context.shitlist().shitlistRouter(msg.getTarget().getIdentity().calculateHash(), "Invalid SSU address");
|
||||
return;
|
||||
if ( (remAddr != null) && (port > 0) ) {
|
||||
to = new RemoteHostId(remAddr.getAddress(), port);
|
||||
|
||||
if (!_transport.isValid(to.getIP())) {
|
||||
_transport.failed(msg);
|
||||
_context.shitlist().shitlistRouter(msg.getTarget().getIdentity().calculateHash(), "Invalid SSU address");
|
||||
return;
|
||||
}
|
||||
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Add outbound establish state to: " + to);
|
||||
} else {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Add indirect outbound establish state to: " + addr);
|
||||
to = new RemoteHostId(msg.getTarget().getIdentity().calculateHash().getData());
|
||||
}
|
||||
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Add outobund establish state to: " + to);
|
||||
|
||||
OutboundEstablishState state = null;
|
||||
int deferred = 0;
|
||||
synchronized (_outboundStates) {
|
||||
@@ -465,12 +472,18 @@ public class EstablishmentManager {
|
||||
long now = _context.clock().now();
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Send request to: " + state.getRemoteHostId().toString());
|
||||
_transport.send(_builder.buildSessionRequestPacket(state));
|
||||
UDPPacket packet = _builder.buildSessionRequestPacket(state);
|
||||
if (packet != null) {
|
||||
_transport.send(packet);
|
||||
} else {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Unable to build a session request packet for " + state.getRemoteHostId());
|
||||
}
|
||||
state.requestSent();
|
||||
}
|
||||
|
||||
private static final long MAX_NONCE = 0xFFFFFFFFl;
|
||||
/** if we don't get a relayResponse in 3 seconds, try again with another intro peer */
|
||||
/** if we don't get a relayResponse in 3 seconds, try again */
|
||||
private static final int INTRO_ATTEMPT_TIMEOUT = 3*1000;
|
||||
|
||||
private void handlePendingIntro(OutboundEstablishState state) {
|
||||
@@ -488,7 +501,11 @@ public class EstablishmentManager {
|
||||
SimpleTimer.getInstance().addEvent(new FailIntroduction(state, nonce), INTRO_ATTEMPT_TIMEOUT);
|
||||
state.setIntroNonce(nonce);
|
||||
_context.statManager().addRateData("udp.sendIntroRelayRequest", 1, 0);
|
||||
_transport.send(_builder.buildRelayRequest(_transport, state, _transport.getIntroKey()));
|
||||
UDPPacket requests[] = _builder.buildRelayRequest(_transport, state, _transport.getIntroKey());
|
||||
for (int i = 0; i < requests.length; i++) {
|
||||
if (requests[i] != null)
|
||||
_transport.send(requests[i]);
|
||||
}
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Send intro for " + state.getRemoteHostId().toString() + " with our intro key as " + _transport.getIntroKey().toBase64());
|
||||
state.introSent();
|
||||
@@ -542,7 +559,15 @@ public class EstablishmentManager {
|
||||
}
|
||||
_context.statManager().addRateData("udp.receiveIntroRelayResponse", state.getLifetime(), 0);
|
||||
int port = reader.getRelayResponseReader().readCharliePort();
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Received relay intro for " + state.getRemoteIdentity().calculateHash().toBase64() + " - they are on "
|
||||
+ addr.toString() + ":" + port + " (according to " + bob.toString(true) + ")");
|
||||
RemoteHostId oldId = state.getRemoteHostId();
|
||||
state.introduced(addr, ip, port);
|
||||
synchronized (_outboundStates) {
|
||||
_outboundStates.remove(oldId);
|
||||
_outboundStates.put(state.getRemoteHostId(), state);
|
||||
}
|
||||
notifyActivity();
|
||||
}
|
||||
|
||||
@@ -763,7 +788,8 @@ public class EstablishmentManager {
|
||||
|
||||
Hash peer = outboundState.getRemoteIdentity().calculateHash();
|
||||
_context.shitlist().shitlistRouter(peer, err);
|
||||
_context.profileManager().commErrorOccurred(peer);
|
||||
_transport.dropPeer(peer);
|
||||
//_context.profileManager().commErrorOccurred(peer);
|
||||
} else {
|
||||
while (true) {
|
||||
OutNetMessage msg = outboundState.getNextQueuedMessage();
|
||||
|
||||
@@ -77,9 +77,15 @@ public class OutboundEstablishState {
|
||||
RouterIdentity remotePeer, SessionKey introKey, UDPAddress addr) {
|
||||
_context = ctx;
|
||||
_log = ctx.logManager().getLog(OutboundEstablishState.class);
|
||||
_bobIP = (remoteHost != null ? remoteHost.getAddress() : null);
|
||||
_bobPort = remotePort;
|
||||
_remoteHostId = new RemoteHostId(_bobIP, _bobPort);
|
||||
if ( (remoteHost != null) && (remotePort > 0) ) {
|
||||
_bobIP = remoteHost.getAddress();
|
||||
_bobPort = remotePort;
|
||||
_remoteHostId = new RemoteHostId(_bobIP, _bobPort);
|
||||
} else {
|
||||
_bobIP = null;
|
||||
_bobPort = -1;
|
||||
_remoteHostId = new RemoteHostId(remotePeer.calculateHash().getData());
|
||||
}
|
||||
_remotePeer = remotePeer;
|
||||
_introKey = introKey;
|
||||
_keyBuilder = null;
|
||||
@@ -387,6 +393,8 @@ public class OutboundEstablishState {
|
||||
_bobIP = bobIP;
|
||||
_bobPort = bobPort;
|
||||
_remoteHostId = new RemoteHostId(bobIP, bobPort);
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Introduced to " + _remoteHostId + ", now lets get on with establishing");
|
||||
}
|
||||
|
||||
/** how long have we been trying to establish this session? */
|
||||
|
||||
@@ -746,28 +746,28 @@ public class PacketBuilder {
|
||||
private byte[] getOurExplicitIP() { return null; }
|
||||
private int getOurExplicitPort() { return 0; }
|
||||
|
||||
public UDPPacket buildRelayRequest(UDPTransport transport, OutboundEstablishState state, SessionKey ourIntroKey) {
|
||||
/** build intro packets for each of the published introducers */
|
||||
public UDPPacket[] buildRelayRequest(UDPTransport transport, OutboundEstablishState state, SessionKey ourIntroKey) {
|
||||
UDPAddress addr = state.getRemoteAddress();
|
||||
int count = addr.getIntroducerCount();
|
||||
if (count <= 0)
|
||||
return null;
|
||||
int index = _context.random().nextInt(count);
|
||||
return new UDPPacket[0];
|
||||
UDPPacket rv[] = new UDPPacket[count];
|
||||
for (int i = 0; i < count; i++) {
|
||||
int cur = (i + index) % count;
|
||||
InetAddress iaddr = addr.getIntroducerHost(cur);
|
||||
int iport = addr.getIntroducerPort(cur);
|
||||
byte ikey[] = addr.getIntroducerKey(cur);
|
||||
long tag = addr.getIntroducerTag(cur);
|
||||
InetAddress iaddr = addr.getIntroducerHost(i);
|
||||
int iport = addr.getIntroducerPort(i);
|
||||
byte ikey[] = addr.getIntroducerKey(i);
|
||||
long tag = addr.getIntroducerTag(i);
|
||||
if ( (ikey == null) || (iport <= 0) || (iaddr == null) || (tag <= 0) ) {
|
||||
if (_log.shouldLog(_log.WARN))
|
||||
_log.warn("Cannot build a relay request to " + state.getRemoteIdentity().calculateHash().toBase64()
|
||||
+ ", as their UDP address is invalid: addr=" + addr + " index=" + cur);
|
||||
+ ", as their UDP address is invalid: addr=" + addr + " index=" + i);
|
||||
continue;
|
||||
}
|
||||
if (transport.isValid(iaddr.getAddress()))
|
||||
return buildRelayRequest(iaddr, iport, ikey, tag, ourIntroKey, state.getIntroNonce(), true);
|
||||
rv[i] = buildRelayRequest(iaddr, iport, ikey, tag, ourIntroKey, state.getIntroNonce(), true);
|
||||
}
|
||||
return null;
|
||||
return rv;
|
||||
}
|
||||
|
||||
public UDPPacket buildRelayRequest(InetAddress introHost, int introPort, byte introKey[], long introTag, SessionKey ourIntroKey, long introNonce, boolean encrypt) {
|
||||
|
||||
@@ -418,6 +418,11 @@ public class PeerState {
|
||||
}
|
||||
return _consecutiveFailedSends;
|
||||
}
|
||||
public long getInactivityTime() {
|
||||
long now = _context.clock().now();
|
||||
long lastActivity = Math.max(_lastReceiveTime, _lastSendFullyTime);
|
||||
return now - lastActivity;
|
||||
}
|
||||
|
||||
/** how fast we are sending *ack* packets */
|
||||
public int getSendACKBps() { return _sendACKBps; }
|
||||
|
||||
@@ -1,28 +1,37 @@
|
||||
package net.i2p.router.transport.udp;
|
||||
|
||||
import net.i2p.data.Base64;
|
||||
import net.i2p.data.DataHelper;
|
||||
|
||||
/**
|
||||
* Unique ID for a peer - its IP + port, all bundled into a tidy obj.
|
||||
* Aint it cute?
|
||||
* If the remote peer is not reachabe through an IP+port, this contains
|
||||
* the hash of their identity.
|
||||
*
|
||||
*/
|
||||
final class RemoteHostId {
|
||||
private byte _ip[];
|
||||
private int _port;
|
||||
private byte _peerHash[];
|
||||
|
||||
public RemoteHostId(byte ip[], int port) {
|
||||
_ip = ip;
|
||||
_port = port;
|
||||
}
|
||||
public RemoteHostId(byte peerHash[]) {
|
||||
_peerHash = peerHash;
|
||||
}
|
||||
|
||||
public byte[] getIP() { return _ip; }
|
||||
public int getPort() { return _port; }
|
||||
public byte[] getPeerHash() { return _peerHash; }
|
||||
|
||||
public int hashCode() {
|
||||
int rv = 0;
|
||||
for (int i = 0; i < _ip.length; i++)
|
||||
for (int i = 0; _ip != null && i < _ip.length; i++)
|
||||
rv += _ip[i] << i;
|
||||
for (int i = 0; _peerHash != null && i < _peerHash.length; i++)
|
||||
rv += _peerHash[i] << i;
|
||||
rv += _port;
|
||||
return rv;
|
||||
}
|
||||
@@ -33,15 +42,19 @@ final class RemoteHostId {
|
||||
if (!(obj instanceof RemoteHostId))
|
||||
throw new ClassCastException("obj is a " + obj.getClass().getName());
|
||||
RemoteHostId id = (RemoteHostId)obj;
|
||||
return (_port == id.getPort()) && DataHelper.eq(_ip, id.getIP());
|
||||
return (_port == id.getPort()) && DataHelper.eq(_ip, id.getIP()) && DataHelper.eq(_peerHash, id.getPeerHash());
|
||||
}
|
||||
|
||||
public String toString() { return toString(true); }
|
||||
public String toString(boolean includePort) {
|
||||
if (includePort)
|
||||
return toString(_ip) + ':' + _port;
|
||||
else
|
||||
return toString(_ip);
|
||||
if (_ip != null) {
|
||||
if (includePort)
|
||||
return toString(_ip) + ':' + _port;
|
||||
else
|
||||
return toString(_ip);
|
||||
} else {
|
||||
return Base64.encode(_peerHash);
|
||||
}
|
||||
}
|
||||
public static String toString(byte ip[]) {
|
||||
StringBuffer buf = new StringBuffer(ip.length+5);
|
||||
|
||||
@@ -23,6 +23,7 @@ import net.i2p.data.i2np.DatabaseStoreMessage;
|
||||
import net.i2p.router.CommSystemFacade;
|
||||
import net.i2p.router.OutNetMessage;
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.router.Router;
|
||||
import net.i2p.router.transport.Transport;
|
||||
import net.i2p.router.transport.TransportImpl;
|
||||
import net.i2p.router.transport.TransportBid;
|
||||
@@ -96,6 +97,8 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
|
||||
/** do we require introducers, regardless of our status? */
|
||||
public static final String PROP_FORCE_INTRODUCERS = "i2np.udp.forceIntroducers";
|
||||
/** do we allow direct SSU connections, sans introducers? */
|
||||
public static final String PROP_ALLOW_DIRECT = "i2np.udp.allowDirect";
|
||||
|
||||
/** how many relays offered to us will we use at a time? */
|
||||
public static final int PUBLIC_RELAY_COUNT = 3;
|
||||
@@ -526,8 +529,10 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
return super.getCurrentAddress();
|
||||
}
|
||||
|
||||
private void dropPeer(PeerState peer) {
|
||||
dropPeer(peer, true);
|
||||
void dropPeer(Hash peer) {
|
||||
PeerState state = getPeerState(peer);
|
||||
if (state != null)
|
||||
dropPeer(state, false);
|
||||
}
|
||||
private void dropPeer(PeerState peer, boolean shouldShitlist) {
|
||||
if (_log.shouldLog(Log.INFO)) {
|
||||
@@ -794,8 +799,8 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
_log.info("Picked peers: " + found);
|
||||
_introducersSelectedOn = _context.clock().now();
|
||||
}
|
||||
}
|
||||
if ( (_externalListenPort > 0) && (_externalListenHost != null) && (isValid(_externalListenHost.getAddress())) ) {
|
||||
}
|
||||
if ( allowDirectUDP() && (_externalListenPort > 0) && (_externalListenHost != null) && (isValid(_externalListenHost.getAddress())) ) {
|
||||
options.setProperty(UDPAddress.PROP_PORT, String.valueOf(_externalListenPort));
|
||||
options.setProperty(UDPAddress.PROP_HOST, _externalListenHost.getHostAddress());
|
||||
// if we have explicit external addresses, they had better be reachable
|
||||
@@ -827,15 +832,26 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
protected void replaceAddress(RouterAddress address, RouterAddress oldAddress) {
|
||||
replaceAddress(address);
|
||||
if (oldAddress != null) {
|
||||
// fire a router.updateExternalAddress only if the address /really/ changed.
|
||||
// updating the introducers doesn't require a real change, only updating the
|
||||
// IP or port does.
|
||||
UDPAddress old = new UDPAddress(oldAddress);
|
||||
InetAddress oldHost = old.getHostAddress();
|
||||
UDPAddress newAddr = new UDPAddress(address);
|
||||
InetAddress newHost = newAddr.getHostAddress();
|
||||
if ( (old.getPort() != newAddr.getPort()) || (!oldHost.equals(newHost)) )
|
||||
_context.router().updateExternalAddress(address, true);
|
||||
if ( (old.getPort() > 0) && (oldHost != null) && (isValid(oldHost.getAddress())) &&
|
||||
(newAddr.getPort() > 0) && (newHost != null) && (isValid(newHost.getAddress())) ) {
|
||||
if ( (old.getPort() != newAddr.getPort()) || (!oldHost.equals(newHost)) ) {
|
||||
// substantial data has changed, so if we are in 'dynamic keys' mode, restart the
|
||||
// router hard and regenerate a new identity
|
||||
if ("true".equalsIgnoreCase(_context.getProperty(Router.PROP_DYNAMIC_KEYS, "false"))) {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("SSU address updated. new address: "
|
||||
+ newAddr.getHostAddress() + ":" + newAddr.getPort() + ", old address: "
|
||||
+ old.getHostAddress() + ":" + old.getPort());
|
||||
// shutdown itself checks the DYNAMIC_KEYS flag, and if its set to true, deletes
|
||||
// the keys
|
||||
_context.router().shutdown(Router.EXIT_HARD_RESTART);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -852,6 +868,11 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
}
|
||||
}
|
||||
|
||||
private boolean allowDirectUDP() {
|
||||
String allowDirect = _context.getProperty(PROP_ALLOW_DIRECT);
|
||||
return ( (allowDirect == null) || (Boolean.valueOf(allowDirect).booleanValue()) );
|
||||
}
|
||||
|
||||
String getPacketHandlerStatus() {
|
||||
PacketHandler handler = _handler;
|
||||
if (handler != null)
|
||||
@@ -859,6 +880,8 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
private static final int DROP_INACTIVITY_TIME = 10*1000;
|
||||
|
||||
public void failed(OutboundMessageState msg) {
|
||||
if (msg == null) return;
|
||||
@@ -875,7 +898,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
consecutive = msg.getPeer().incrementConsecutiveFailedSends();
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Consecutive failure #" + consecutive + " sending to " + msg.getPeer());
|
||||
if (consecutive > MAX_CONSECUTIVE_FAILED)
|
||||
if ( (consecutive > MAX_CONSECUTIVE_FAILED) && (msg.getPeer().getInactivityTime() > DROP_INACTIVITY_TIME))
|
||||
dropPeer(msg.getPeer(), false);
|
||||
}
|
||||
failed(msg.getMessage());
|
||||
|
||||
Reference in New Issue
Block a user