From 0133711c3b6ef223fc1b6bff7ff90eecd32882bc Mon Sep 17 00:00:00 2001 From: zzz Date: Mon, 2 Nov 2009 16:41:01 +0000 Subject: [PATCH 01/11] code cleanup --- .../src/net/i2p/router/transport/UPnP.java | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/router/java/src/net/i2p/router/transport/UPnP.java b/router/java/src/net/i2p/router/transport/UPnP.java index 6ed11cdc2..0fc538a3f 100644 --- a/router/java/src/net/i2p/router/transport/UPnP.java +++ b/router/java/src/net/i2p/router/transport/UPnP.java @@ -636,25 +636,20 @@ public class UPnP extends ControlPoint implements DeviceChangeListener, EventLis } public void run() { + HashMap map = new HashMap(1); for(ForwardPort port : portsToForwardNow) { String proto = protoToString(port.protocol); + map.clear(); + ForwardPortStatus fps; if (proto.length() <= 1) { - HashMap map = new HashMap(); - map.put(port, new ForwardPortStatus(ForwardPortStatus.DEFINITE_FAILURE, "Protocol not supported", port.portNumber)); - forwardCallback.portForwardStatus(map); - continue; - } - if(tryAddMapping(proto, port.portNumber, port.name, port)) { - HashMap map = new HashMap(); - map.put(port, new ForwardPortStatus(ForwardPortStatus.MAYBE_SUCCESS, "Port apparently forwarded by UPnP", port.portNumber)); - forwardCallback.portForwardStatus(map); - continue; + fps = new ForwardPortStatus(ForwardPortStatus.DEFINITE_FAILURE, "Protocol not supported", port.portNumber); + } else if(tryAddMapping(proto, port.portNumber, port.name, port)) { + fps = new ForwardPortStatus(ForwardPortStatus.MAYBE_SUCCESS, "Port apparently forwarded by UPnP", port.portNumber); } else { - HashMap map = new HashMap(); - map.put(port, new ForwardPortStatus(ForwardPortStatus.PROBABLE_FAILURE, "UPnP port forwarding apparently failed", port.portNumber)); - forwardCallback.portForwardStatus(map); - continue; + fps = new ForwardPortStatus(ForwardPortStatus.PROBABLE_FAILURE, "UPnP port forwarding apparently failed", port.portNumber); } + map.put(port, fps); + forwardCallback.portForwardStatus(map); } } } From da21c0ddb7854348ed474c1102f7f264486c003f Mon Sep 17 00:00:00 2001 From: zzz Date: Mon, 2 Nov 2009 16:43:04 +0000 Subject: [PATCH 02/11] * UDP: Pick a random port on first install or bind failure - No more port 8887 to prevent easy state-level blocking --- initialNews.xml | 7 -- .../i2p/router/transport/udp/UDPEndpoint.java | 76 +++++++++++++--- .../router/transport/udp/UDPTransport.java | 91 ++++++++++++------- 3 files changed, 123 insertions(+), 51 deletions(-) diff --git a/initialNews.xml b/initialNews.xml index 40892c28d..35800d7d5 100644 --- a/initialNews.xml +++ b/initialNews.xml @@ -11,10 +11,6 @@ While you are waiting, please adjust your bandwidth settings on the configuration page.
  • -If you can, open up port 8887 on your firewall, then enable inbound TCP on the -configuration page. -
  • -
  • Once you have a "shared clients" destination listed on the left, please check out our FAQ. @@ -35,9 +31,6 @@ Passe bitte In der Wartezeit deine Einstellungen zur Bandbreite auf der Einstellungsseite an.
  • -Bitte öffne sobald möglich den Port 8887 in deiner Firewall, aktiviere danach den eingehenden TCP Verkehr auf der Einstellungsseite. -
  • -
  • Sobald auf der linken Seite eine "shared clients" Verbindung aufgelistet ist besuche bitte unsere FAQ.
  • diff --git a/router/java/src/net/i2p/router/transport/udp/UDPEndpoint.java b/router/java/src/net/i2p/router/transport/udp/UDPEndpoint.java index f828361e2..cffb8fd8b 100644 --- a/router/java/src/net/i2p/router/transport/udp/UDPEndpoint.java +++ b/router/java/src/net/i2p/router/transport/udp/UDPEndpoint.java @@ -22,7 +22,11 @@ public class UDPEndpoint { private DatagramSocket _socket; private InetAddress _bindAddress; - public UDPEndpoint(RouterContext ctx, UDPTransport transport, int listenPort, InetAddress bindAddress) throws SocketException { + /** + * @param listenPort -1 or the requested port, may not be honored + * @param bindAddress null ok + */ + public UDPEndpoint(RouterContext ctx, UDPTransport transport, int listenPort, InetAddress bindAddress) { _context = ctx; _log = ctx.logManager().getLog(UDPEndpoint.class); _transport = transport; @@ -30,23 +34,20 @@ public class UDPEndpoint { _listenPort = listenPort; } + /** caller should call getListenPort() after this to get the actual bound port and determine success */ public void startup() { if (_log.shouldLog(Log.DEBUG)) _log.debug("Starting up the UDP endpoint"); shutdown(); - try { - if (_bindAddress == null) - _socket = new DatagramSocket(_listenPort); - else - _socket = new DatagramSocket(_listenPort, _bindAddress); - _sender = new UDPSender(_context, _socket, "UDPSender"); - _receiver = new UDPReceiver(_context, _transport, _socket, "UDPReceiver"); - _sender.startup(); - _receiver.startup(); - } catch (SocketException se) { - _transport.setReachabilityStatus(CommSystemFacade.STATUS_HOSED); - _log.log(Log.CRIT, "Unable to bind on port " + _listenPort, se); + _socket = getSocket(); + if (_socket == null) { + _log.log(Log.CRIT, "UDP Unable to open a port"); + return; } + _sender = new UDPSender(_context, _socket, "UDPSender"); + _receiver = new UDPReceiver(_context, _transport, _socket, "UDPReceiver"); + _sender.startup(); + _receiver.startup(); } public void shutdown() { @@ -60,6 +61,8 @@ public class UDPEndpoint { } public void setListenPort(int newPort) { _listenPort = newPort; } + +/******* public void updateListenPort(int newPort) { if (newPort == _listenPort) return; try { @@ -76,7 +79,54 @@ public class UDPEndpoint { _log.error("Unable to bind on " + _listenPort); } } +********/ + /** 8998 is monotone, and 32000 is the wrapper, so let's stay between those */ + private static final int MIN_RANDOM_PORT = 9111; + private static final int MAX_RANDOM_PORT = 31777; + private static final int MAX_PORT_RETRIES = 20; + + /** + * Open socket using requested port in _listenPort and bind host in _bindAddress. + * If _listenPort <= 0, or requested port is busy, repeatedly try a new random port. + * @return null on failure + * Sets _listenPort to actual port or -1 on failure + */ + private DatagramSocket getSocket() { + DatagramSocket socket = null; + int port = _listenPort; + + for (int i = 0; i < MAX_PORT_RETRIES; i++) { + if (port <= 0) { + // try random ports rather than just do new DatagramSocket() + // so we stay out of the way of other I2P stuff + port = MIN_RANDOM_PORT + _context.random().nextInt(MAX_RANDOM_PORT - MIN_RANDOM_PORT); + } + try { + if (_bindAddress == null) + socket = new DatagramSocket(port); + else + socket = new DatagramSocket(port, _bindAddress); + break; + } catch (SocketException se) { + if (_log.shouldLog(Log.WARN)) + _log.warn("Binding to port " + port + " failed: " + se); + } + port = -1; + } + if (socket == null) { + _log.log(Log.CRIT, "SSU Unable to bind to a port on " + _bindAddress); + } else if (port != _listenPort) { + if (_listenPort > 0) + _log.error("SSU Unable to bind to requested port " + _listenPort + ", using random port " + port); + else + _log.error("SSU selected random port " + port); + } + _listenPort = port; + return socket; + } + + /** call after startup() to get actual port or -1 on startup failure */ public int getListenPort() { return _listenPort; } public UDPSender getSender() { return _sender; } diff --git a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java index 2bdf8a466..2556bdb7b 100644 --- a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java +++ b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java @@ -100,6 +100,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority public static final String STYLE = "SSU"; public static final String PROP_INTERNAL_PORT = "i2np.udp.internalPort"; + /** now unused, we pick a random port */ public static final int DEFAULT_INTERNAL_PORT = 8887; /** since fixed port defaults to true, this doesnt do anything at the moment. * We should have an exception if it matches the existing low port. */ @@ -137,6 +138,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority 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"; + /** this is rarely if ever used, default is to bind to wildcard address */ public static final String PROP_BIND_INTERFACE = "i2np.udp.bindInterface"; /** how many relays offered to us will we use at a time? */ @@ -226,40 +228,41 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority System.arraycopy(_context.routerHash().getData(), 0, _introKey.getData(), 0, SessionKey.KEYSIZE_BYTES); rebuildExternalAddress(); - - int port = -1; - if (_externalListenPort <= 0) { - // no explicit external port, so lets try an internal one - port = _context.getProperty(PROP_INTERNAL_PORT, DEFAULT_INTERNAL_PORT); - // attempt to use it as our external port - this will be overridden by - // externalAddressReceived(...) - _context.router().setConfigSetting(PROP_EXTERNAL_PORT, port+""); - _context.router().saveConfig(); - } else { - port = _externalListenPort; - if (_log.shouldLog(Log.INFO)) - _log.info("Binding to the explicitly specified external port: " + port); - } - if (_endpoint == null) { - String bindTo = _context.getProperty(PROP_BIND_INTERFACE); - InetAddress bindToAddr = null; - if (bindTo != null) { - try { - bindToAddr = InetAddress.getByName(bindTo); - } catch (UnknownHostException uhe) { - if (_log.shouldLog(Log.ERROR)) - _log.error("Invalid SSU bind interface specified [" + bindTo + "]", uhe); - bindToAddr = null; - } - } + + // bind host + String bindTo = _context.getProperty(PROP_BIND_INTERFACE); + InetAddress bindToAddr = null; + if (bindTo != null) { try { - _endpoint = new UDPEndpoint(_context, this, port, bindToAddr); - } catch (SocketException se) { - if (_log.shouldLog(Log.CRIT)) - _log.log(Log.CRIT, "Unable to listen on the UDP port (" + port + ")", se); + bindToAddr = InetAddress.getByName(bindTo); + } catch (UnknownHostException uhe) { + _log.log(Log.CRIT, "Invalid SSU bind interface specified [" + bindTo + "]", uhe); + setReachabilityStatus(CommSystemFacade.STATUS_HOSED); return; } + } + + // Requested bind port + // This may be -1 or may not be honored if busy, + // we will check below after starting up the endpoint. + int port; + int oldIPort = _context.getProperty(PROP_INTERNAL_PORT, -1); + int oldEPort = _context.getProperty(PROP_EXTERNAL_PORT, -1); + if (_externalListenPort <= 0) { + // no explicit external port, so lets try an internal one + if (oldIPort > 0) + port = oldIPort; + else + port = oldEPort; } else { + port = _externalListenPort; + } + if (_log.shouldLog(Log.INFO)) + _log.info("Binding to the port: " + port); + if (_endpoint == null) { + _endpoint = new UDPEndpoint(_context, this, port, bindToAddr); + } else { + // todo, set bind address too _endpoint.setListenPort(port); } @@ -278,7 +281,24 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority if (_flooder == null) _flooder = new UDPFlooder(_context, this); + // Startup the endpoint with the requested port, check the actual port, and + // take action if it failed or was different than requested or it needs to be saved _endpoint.startup(); + int newPort = _endpoint.getListenPort(); + _externalListenPort = newPort; + if (newPort <= 0) { + _log.log(Log.CRIT, "Unable to open UDP port"); + setReachabilityStatus(CommSystemFacade.STATUS_HOSED); + return; + } + if (newPort != port || newPort != oldIPort || newPort != oldEPort) { + // attempt to use it as our external port - this will be overridden by + // externalAddressReceived(...) + _context.router().setConfigSetting(PROP_INTERNAL_PORT, newPort+""); + _context.router().setConfigSetting(PROP_EXTERNAL_PORT, newPort+""); + _context.router().saveConfig(); + } + _establisher.startup(); _handler.startup(); _fragments.startup(); @@ -321,11 +341,16 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority public int getLocalPort() { return _externalListenPort; } public InetAddress getLocalAddress() { return _externalListenHost; } public int getExternalPort() { return _externalListenPort; } + + /** + * _externalListenPort should always be set (by startup()) before this is called, + * so the returned value should be > 0 + */ @Override public int getRequestedPort() { if (_externalListenPort > 0) return _externalListenPort; - return _context.getProperty(PROP_INTERNAL_PORT, DEFAULT_INTERNAL_PORT); + return _context.getProperty(PROP_INTERNAL_PORT, -1); } /** @@ -2003,6 +2028,8 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority buf.append(" ").append(resentTotal); buf.append(" ").append(dupRecvTotal).append("\n"); buf.append(" \n"); + + /***** long bytesTransmitted = _context.bandwidthLimiter().getTotalAllocatedOutboundBytes(); // NPE here early double averagePacketSize = _context.statManager().getRate("udp.sendPacketSize").getLifetimeAverageValue(); @@ -2012,6 +2039,8 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority double bwResent = (nondupSent <= 0 ? 0d : ((((double)resentTotal)*averagePacketSize) / nondupSent)); buf.append("

    Percentage of bytes retransmitted (lifetime): ").append(formatPct(bwResent)); buf.append("

    (Includes retransmission required by packet loss)\n"); + *****/ + out.write(buf.toString()); buf.setLength(0); out.write(KEY); From e952e91b54d89da12b09dd0a72b7c8a136a2473a Mon Sep 17 00:00:00 2001 From: zzz Date: Mon, 2 Nov 2009 16:45:04 +0000 Subject: [PATCH 03/11] tagging --- .../java/src/net/i2p/router/web/ConfigRestartBean.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigRestartBean.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigRestartBean.java index dcefa84e3..657039400 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigRestartBean.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigRestartBean.java @@ -33,7 +33,8 @@ public class ConfigRestartBean { ctx.addShutdownTask(new ConfigServiceHandler.UpdateWrapperManagerTask(Router.EXIT_HARD)); //ctx.router().shutdown(Router.EXIT_HARD); // never returns ctx.router().shutdownGracefully(Router.EXIT_HARD); // give the UI time to respond - } else if ("cancelShutdown".equals(action) || _("Cancel shutdown", ctx).equals(action)) { + } else if ("cancelShutdown".equals(action) || _("Cancel shutdown", ctx).equals(action) || + _("Cancel restart", ctx).equals(action)) { ctx.router().cancelGracefulShutdown(); } else if ("restartImmediate".equals(action) || _("Restart immediately", ctx).equals(action)) { ctx.addShutdownTask(new ConfigServiceHandler.UpdateWrapperManagerTask(Router.EXIT_HARD_RESTART)); From ba95084d27dc11913b1f35927deed459783e3516 Mon Sep 17 00:00:00 2001 From: zzz Date: Mon, 2 Nov 2009 16:45:23 +0000 Subject: [PATCH 04/11] bold the transport --- .../java/src/net/i2p/router/web/NetDbRenderer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/routerconsole/java/src/net/i2p/router/web/NetDbRenderer.java b/apps/routerconsole/java/src/net/i2p/router/web/NetDbRenderer.java index abd20b770..0e792e702 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/NetDbRenderer.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/NetDbRenderer.java @@ -244,7 +244,7 @@ public class NetDbRenderer { } for (Iterator iter = info.getAddresses().iterator(); iter.hasNext(); ) { RouterAddress addr = (RouterAddress)iter.next(); - buf.append(DataHelper.stripHTML(addr.getTransportStyle())).append(": "); + buf.append("").append(DataHelper.stripHTML(addr.getTransportStyle())).append(": "); for (Iterator optIter = addr.getOptions().keySet().iterator(); optIter.hasNext(); ) { String name = (String)optIter.next(); String val = addr.getOptions().getProperty(name); From 7997aeaca5842a56a60a5b4016af30a1cb86eaa1 Mon Sep 17 00:00:00 2001 From: zzz Date: Mon, 2 Nov 2009 16:46:07 +0000 Subject: [PATCH 05/11] adjust the help due to random port --- apps/routerconsole/jsp/config.jsp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/routerconsole/jsp/config.jsp b/apps/routerconsole/jsp/config.jsp index 92975a02e..1013653c1 100644 --- a/apps/routerconsole/jsp/config.jsp +++ b/apps/routerconsole/jsp/config.jsp @@ -104,7 +104,7 @@ " /> <% String[] ips = nethelper.getAddresses(); if (ips.length > 0) { - out.print(" " + intl._("or") + " \n"); for (int i = 0; i < ips.length; i++) { out.print("