diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClientBase.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClientBase.java index 8884210f3e..dec50bdf0b 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClientBase.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClientBase.java @@ -607,6 +607,8 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem error = usingWWWProxy ? "nolsp" : "nols"; } else if (status == MessageStatusMessage.STATUS_SEND_FAILURE_UNSUPPORTED_ENCRYPTION) { error = usingWWWProxy ? "encp" : "enc"; + } else if (status == I2PSocketException.STATUS_CONNECTION_RESET) { + error = usingWWWProxy ? "resetp" : "reset"; } else { error = usingWWWProxy ? "dnfp" : "dnf"; } @@ -638,7 +640,7 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem /** * No jump servers - * @param extraMessage extra message + * @param extraMessage extra message or null, will be HTML-escaped * @since 0.9.14 */ protected void writeErrorMessage(byte[] errMessage, String extraMessage, @@ -649,7 +651,7 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem /** * @param jumpServers comma- or space-separated list, or null - * @param extraMessage extra message + * @param extraMessage extra message or null, will be HTML-escaped * @since 0.9.14 */ protected void writeErrorMessage(byte[] errMessage, String extraMessage, @@ -672,7 +674,7 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem out.write((": " + wwwProxy).getBytes()); } if (extraMessage != null) { - out.write(("

" + extraMessage + "").getBytes()); + out.write(("

" + DataHelper.escapeHTML(extraMessage) + "").getBytes()); } if (jumpServers != null && jumpServers.length() > 0) { boolean first = true; diff --git a/apps/ministreaming/java/src/net/i2p/client/streaming/I2PServerSocket.java b/apps/ministreaming/java/src/net/i2p/client/streaming/I2PServerSocket.java index 3e9f7f1022..16c3776ed6 100644 --- a/apps/ministreaming/java/src/net/i2p/client/streaming/I2PServerSocket.java +++ b/apps/ministreaming/java/src/net/i2p/client/streaming/I2PServerSocket.java @@ -6,8 +6,11 @@ import java.net.SocketTimeoutException; import net.i2p.I2PException; /** - * Defines how to listen for streaming peer connections - * + * Streaming server socket returned by {@link I2PSocketManager#getServerSocket()}. + * Defines how to listen for streaming peer connections. + *

+ * Note that this is not a standard Java {@link java.net.ServerSocket}, + * if you need one of those, use {@link I2PSocketManager#getStandardServerSocket()} instead. */ public interface I2PServerSocket { /** diff --git a/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocket.java b/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocket.java index f84fad967e..c2c3d83704 100644 --- a/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocket.java +++ b/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocket.java @@ -9,9 +9,10 @@ import java.nio.channels.SelectableChannel; import net.i2p.data.Destination; /** - * Minimalistic adapter between the socket api and I2PTunnel's way. - * Note that this interface is a "subinterface" of the interface - * defined in the "official" streaming api. + * Streaming socket returned by {@link I2PSocketManager#connect(Destination)}. + *

+ * Note that this is not a standard Java {@link java.net.Socket}, + * if you need one of those, use {@link I2PSocketManager#connectToSocket(Destination)} instead. */ public interface I2PSocket extends Closeable { /** @@ -27,6 +28,12 @@ public interface I2PSocket extends Closeable { /** * As of 0.9.9 will throw an IOE if socket is closed. * Prior to that would return null instead of throwing IOE. + *

+ * Note that operations on the returned stream may return an + * {@link IOException} whose cause as returned by + * {@link IOException#getCause()} is an {@link I2PSocketException}. + * If so, the client may retrieve a status code via + * {@link I2PSocketException#getStatus()} to provide specific feedback to the user. * * @return an InputStream to read from the socket. Non-null since 0.9.9. * @throws IOException on failure @@ -36,6 +43,12 @@ public interface I2PSocket extends Closeable { /** * As of 0.9.9 will throw an IOE if socket is closed. * Prior to that would return null instead of throwing IOE. + *

+ * Note that operations on the returned stream may return an + * {@link IOException} whose cause as returned by + * {@link IOException#getCause()} is an {@link I2PSocketException}. + * If so, the client may retrieve a status code via + * {@link I2PSocketException#getStatus()} to provide specific feedback to the user. * * @return an OutputStream to write into the socket. Non-null since 0.9.9. * @throws IOException on failure diff --git a/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketException.java b/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketException.java index db4f863dda..5d5e97b65e 100644 --- a/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketException.java +++ b/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketException.java @@ -20,7 +20,18 @@ public class I2PSocketException extends SocketException { private static final String BUNDLE_NAME = "net.i2p.client.streaming.messages"; /** - * Use canned message for this status code + * Router and I2CP status codes are 0 - 511. Start ours at 512. + * @since 0.9.19 + */ + public static final int STATUS_CONNECTION_RESET = 512; + + /** + * Use canned message for this status code. + * + * Standard codes from the router are 0-255, defined in MessageStatusMessage. + * Standard codes from client-side I2CP are 256-511, defined in SendMessageStatusListener. + * Standard codes from streaming are 512-767, defined here. + * * @param status >= 0 from MessageStatusMessage or SendMessageStatusListener */ public I2PSocketException(int status) { @@ -105,6 +116,9 @@ public class I2PSocketException extends SocketException { case SendMessageStatusListener.STATUS_CANCELLED: return _x("Local destination shutdown"); + case STATUS_CONNECTION_RESET: + return _x("Connection was reset"); + case CUSTOM: return super.getMessage(); diff --git a/apps/streaming/java/src/net/i2p/client/streaming/impl/Connection.java b/apps/streaming/java/src/net/i2p/client/streaming/impl/Connection.java index cf306f2b98..72f1022335 100644 --- a/apps/streaming/java/src/net/i2p/client/streaming/impl/Connection.java +++ b/apps/streaming/java/src/net/i2p/client/streaming/impl/Connection.java @@ -12,6 +12,7 @@ import java.util.concurrent.atomic.AtomicLong; import net.i2p.I2PAppContext; import net.i2p.client.I2PSession; +import net.i2p.client.streaming.I2PSocketException; import net.i2p.data.DataHelper; import net.i2p.data.Destination; import net.i2p.util.Log; @@ -606,7 +607,7 @@ class Connection { public void resetReceived() { if (!_resetReceived.compareAndSet(false, true)) return; - IOException ioe = new IOException("Reset received"); + IOException ioe = new I2PSocketException(I2PSocketException.STATUS_CONNECTION_RESET); _outputStream.streamErrorOccurred(ioe); _inputStream.streamErrorOccurred(ioe); _connectionError = "Connection reset"; diff --git a/apps/streaming/java/src/net/i2p/client/streaming/impl/ConnectionManager.java b/apps/streaming/java/src/net/i2p/client/streaming/impl/ConnectionManager.java index 4cc53774ba..8347a974cf 100644 --- a/apps/streaming/java/src/net/i2p/client/streaming/impl/ConnectionManager.java +++ b/apps/streaming/java/src/net/i2p/client/streaming/impl/ConnectionManager.java @@ -262,9 +262,12 @@ class ConnectionManager { // Ditto for blacklist / whitelist // This is a tradeoff, because it will keep retransmitting the SYN for a while, // thus more inbound, but let's not spend several KB on the outbound. - if (_log.shouldLog(Log.INFO)) - _log.info("Dropping RST to " + h); - return null; + if (!Boolean.valueOf(_context.getProperty("i2p.streaming.sendResetOnBlock"))) { + // this is the default. Set property to send reset for debugging. + if (_log.shouldLog(Log.INFO)) + _log.info("Dropping RST to " + h); + return null; + } } } PacketLocal reply = new PacketLocal(_context, from); diff --git a/history.txt b/history.txt index 1347633066..c8cdeb57fe 100644 --- a/history.txt +++ b/history.txt @@ -1,3 +1,11 @@ +2015-03-24 zzz + * Streaming: Throw I2PSocketException when connection is reset, + display new error page in HTTP client (ticket #643) + +2015-03-23 zzz + * Javadoc: Add missing package.html files (ticket #1109) + * Summary bar: linkify news headings, remove 'show news' link + 2015-03-22 zzz * Console: Better status feedback on manual reseed from URL * NetDB: Don't become floodfill w/o ECDSA support @@ -13,7 +21,7 @@ - Finish manual reseed from local file 2015-03-19 zzz - * Reseed: + * Reseed (ticket #1369): - Add form to manually reseed from zip or su3 URL - Add form to manually reseed from local zip or su3 file - Add form to create reseed zip file to share diff --git a/installer/resources/proxy/reset-header.ht b/installer/resources/proxy/reset-header.ht new file mode 100644 index 0000000000..23743ed3d4 --- /dev/null +++ b/installer/resources/proxy/reset-header.ht @@ -0,0 +1,26 @@ +HTTP/1.1 403 Connection Reset +Content-Type: text/html; charset=UTF-8 +Cache-control: no-cache +Connection: close +Proxy-Connection: close + + + +_("Connection Reset") + + + + +

+
+

_("Connection Reset")

+

+_("The connection to the website was reset while the page was loading.") +_("The website could be temporarily unavailable, too busy, or it has blocked your access.") +_("You may want to {0}retry{1}.", "", "")

+
+

_("Could not find the following destination:") +

diff --git a/installer/resources/proxy/resetp-header.ht b/installer/resources/proxy/resetp-header.ht new file mode 100644 index 0000000000..1f1e53dc69 --- /dev/null +++ b/installer/resources/proxy/resetp-header.ht @@ -0,0 +1,26 @@ +HTTP/1.1 403 Connection Reset +Content-Type: text/html; charset=UTF-8 +Cache-control: no-cache +Connection: close +Proxy-Connection: close + + + +_("Connection Reset") + + + + + +
+

_("Connection Reset")

+

+_("The connection to the proxy was reset.") +_("The proxy could be temporarily unavailable, too busy, or it has blocked your access.") +_("You may want to {0}retry{1} as this will randomly reselect an outproxy from the pool you have defined {2}here{3} (if you have more than one configured).", "", "", "", "") +_("If you continue to have trouble you may want to edit your outproxy list {0}here{1}.", "", "") +

+

_("Could not find the following destination:")

diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index 7ca1a3ec2c..46b0184db4 100644 --- a/router/java/src/net/i2p/router/RouterVersion.java +++ b/router/java/src/net/i2p/router/RouterVersion.java @@ -18,10 +18,10 @@ public class RouterVersion { /** deprecated */ public final static String ID = "Monotone"; public final static String VERSION = CoreVersion.VERSION; - public final static long BUILD = 10; + public final static long BUILD = 11; /** for example "-test" */ - public final static String EXTRA = ""; + public final static String EXTRA = "-rc"; public final static String FULL_VERSION = VERSION + "-" + BUILD + EXTRA; public static void main(String args[]) { System.out.println("I2P Router version: " + FULL_VERSION);