From b61861f840b94e570047371b6ef3b53fd937741c Mon Sep 17 00:00:00 2001
From: zzz <zzz@mail.i2p>
Date: Wed, 29 Apr 2009 18:23:15 +0000
Subject: [PATCH] - Tweak UPnP warning messages - Remove unused
 verifyupdate.jsp - Start of callbacks from UPnP to transports - Tell UDP
 local addresses at startup

---
 apps/routerconsole/jsp/config.jsp             |  5 +-
 apps/routerconsole/jsp/verifyupdate.jsp       | 12 ----
 .../transport/CommSystemFacadeImpl.java       |  2 +-
 .../net/i2p/router/transport/Transport.java   |  5 ++
 .../i2p/router/transport/TransportImpl.java   | 23 ++++++++
 .../router/transport/TransportManager.java    | 57 +++++++++++++++----
 .../net/i2p/router/transport/UPnPManager.java | 36 ++++++++++--
 .../router/transport/ntcp/NTCPTransport.java  | 13 +++++
 .../router/transport/udp/UDPTransport.java    |  9 +++
 .../java/src/org/cybergarage/util/Debug.java  | 36 ++++++------
 10 files changed, 148 insertions(+), 50 deletions(-)
 delete mode 100644 apps/routerconsole/jsp/verifyupdate.jsp

diff --git a/apps/routerconsole/jsp/config.jsp b/apps/routerconsole/jsp/config.jsp
index 10232ec730..5eb809ed5f 100644
--- a/apps/routerconsole/jsp/config.jsp
+++ b/apps/routerconsole/jsp/config.jsp
@@ -100,9 +100,10 @@
  <input name ="udpPort" type="text" size="6" value="<jsp:getProperty name="nethelper" property="configuredUdpPort" />" /><br />
 <input type="checkbox" name="requireIntroductions" value="true" <jsp:getProperty name="nethelper" property="requireIntroductionsChecked" /> />
  Require SSU introductions
- <i>(Enable if you cannot open your firewall)</i><br />
+ <i>(Enable if you cannot open your firewall)</i>
+ <p>
  Current External UDP address: <i><jsp:getProperty name="nethelper" property="udpAddress" /></i><br />
- <p>If you can, please poke a hole in your NAT or firewall to allow unsolicited UDP packets to reach
+ </p><p>If you can, please poke a hole in your NAT or firewall to allow unsolicited UDP packets to reach
     you on your external UDP address.  If you can't, I2P now includes supports UDP hole punching
     with "SSU introductions" - peers who will relay a request from someone you don't know to your
     router for your router so that you can make an outbound connection to them.  I2P will use these
diff --git a/apps/routerconsole/jsp/verifyupdate.jsp b/apps/routerconsole/jsp/verifyupdate.jsp
deleted file mode 100644
index 2d13d3508d..0000000000
--- a/apps/routerconsole/jsp/verifyupdate.jsp
+++ /dev/null
@@ -1,12 +0,0 @@
-<%@page contentType="text/html" %>
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
-
-<html><head>
-<title>I2P Router Console - verify update file signature</title>
-</head>
-<body>
-
-<!-- net.i2p.crypto.TrustedUpdate.verify(request.getParameter("filename")) -->
-
-</body>
-</html>
diff --git a/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java b/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java
index 217054d405..9060ede84c 100644
--- a/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java
+++ b/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java
@@ -241,7 +241,7 @@ public class CommSystemFacadeImpl extends CommSystemFacade {
     public void notifyReplaceAddress(RouterAddress UDPAddr) {
         if (UDPAddr == null)
             return;
-        NTCPTransport t = (NTCPTransport) _manager.getNTCPTransport();
+        NTCPTransport t = (NTCPTransport) _manager.getTransport(NTCPTransport.STYLE);
         if (t == null)
             return;
         Properties UDPProps = UDPAddr.getOptions();
diff --git a/router/java/src/net/i2p/router/transport/Transport.java b/router/java/src/net/i2p/router/transport/Transport.java
index f95d2dc8f8..145129651e 100644
--- a/router/java/src/net/i2p/router/transport/Transport.java
+++ b/router/java/src/net/i2p/router/transport/Transport.java
@@ -35,6 +35,11 @@ public interface Transport {
     public RouterAddress startListening();
     public void stopListening();
     public RouterAddress getCurrentAddress();
+    public static final String SOURCE_UPNP = "UPnP";
+    public static final String SOURCE_INTERFACE = "Local interface";
+    public static final String SOURCE_CONFIG = "Configuration change";
+    public void externalAddressReceived(String source, byte[] ip, int port);
+    public void forwardPortStatus(int port, boolean success, String reason);
     public void setListener(TransportEventListener listener);
     public String getStyle();
     
diff --git a/router/java/src/net/i2p/router/transport/TransportImpl.java b/router/java/src/net/i2p/router/transport/TransportImpl.java
index cff0d9a468..685f6189ef 100644
--- a/router/java/src/net/i2p/router/transport/TransportImpl.java
+++ b/router/java/src/net/i2p/router/transport/TransportImpl.java
@@ -422,6 +422,29 @@ public abstract class TransportImpl implements Transport {
             _context.commSystem().notifyReplaceAddress(address);
     }
 
+    /**
+     *  Notify a transport of an external address change.
+     *  This may be from a local interface, UPnP, a config change, etc.
+     *  This should not be called if the ip didn't change
+     *  (from that source's point of view), or is a local address,
+     *  or if the ip is IPv6, but the transport should check anyway.
+     *  The transport should also do its own checking on whether to accept
+     *  notifications from this source.
+     *
+     *  This can be called before startListening() to set an initial address,
+     *  or after the transport is running.
+     *
+     *  @param source defined in Transport.java
+     *  @param ip typ. IPv4 non-local
+     *  @param port 0 for unknown or unchanged
+     */
+    public void externalAddressReceived(String source, byte[] ip, int port) {}
+
+    /**
+     *  Notify a transport of the results of trying to forward a port
+     */
+    public void forwardPortStatus(int port, boolean success, String reason) {}
+
     /** Who to notify on message availability */
     public void setListener(TransportEventListener listener) { _listener = listener; }
     /** Make this stuff pretty (only used in the old console) */
diff --git a/router/java/src/net/i2p/router/transport/TransportManager.java b/router/java/src/net/i2p/router/transport/TransportManager.java
index e0eefe9a54..ea3e09b82f 100644
--- a/router/java/src/net/i2p/router/transport/TransportManager.java
+++ b/router/java/src/net/i2p/router/transport/TransportManager.java
@@ -10,6 +10,8 @@ package net.i2p.router.transport;
 
 import java.io.IOException;
 import java.io.Writer;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -54,7 +56,7 @@ public class TransportManager implements TransportEventListener {
         _context.statManager().createRateStat("transport.bidFailAllTransports", "Could not attempt to bid on message, as all of the transports had failed", "Transport", new long[] { 60*1000, 10*60*1000, 60*60*1000 });
         _transports = new ArrayList();
         if (Boolean.valueOf(_context.getProperty(PROP_ENABLE_UPNP)).booleanValue())
-            _upnpManager = new UPnPManager(context);
+            _upnpManager = new UPnPManager(context, this);
     }
     
     public void addTransport(Transport transport) {
@@ -75,14 +77,11 @@ public class TransportManager implements TransportEventListener {
             enableUDP = DEFAULT_ENABLE_UDP;
         if ("true".equalsIgnoreCase(enableUDP)) {
             UDPTransport udp = new UDPTransport(_context);
-            udp.setListener(this);
-            _transports.add(udp);
-        }
-        if (enableNTCP(_context)) {
-            NTCPTransport ntcp = new NTCPTransport(_context);
-            ntcp.setListener(this);
-            _transports.add(ntcp);
+            addTransport(udp);
+            initializeAddress(udp);
         }
+        if (enableNTCP(_context))
+            addTransport(new NTCPTransport(_context));
         if (_transports.size() <= 0)
             _log.log(Log.CRIT, "No transports are enabled");
     }
@@ -94,6 +93,41 @@ public class TransportManager implements TransportEventListener {
         return "true".equalsIgnoreCase(enableNTCP);
     }
     
+    private static void initializeAddress(Transport t) {
+        String ips = Addresses.getAnyAddress();
+        if (ips == null)
+            return;
+        InetAddress ia = null;
+        try {
+            ia = InetAddress.getByName(ips);
+        } catch (UnknownHostException e) {return;}
+        if (ia == null)
+            return;
+        byte[] ip = ia.getAddress();
+        t.externalAddressReceived(Transport.SOURCE_INTERFACE, ip, 0);
+    }
+
+    /**
+     * callback from UPnP
+     * Only tell SSU, it will tell NTCP
+     *
+     */
+    public void externalAddressReceived(String source, byte[] ip, int port) {
+        Transport t = getTransport(UDPTransport.STYLE);
+        if (t != null)
+            t.externalAddressReceived(source, ip, port);
+    }
+
+    /**
+     * callback from UPnP
+     *
+     */
+    public void forwardPortStatus(String style, int port, boolean success, String reason) {
+        Transport t = getTransport(style);
+        if (t != null)
+            t.forwardPortStatus(port, success, reason);
+    }
+
     public void startListening() {
         if (_upnpManager != null)
             _upnpManager.start();
@@ -102,7 +136,8 @@ public class TransportManager implements TransportEventListener {
         for (int i = 0; i < _transports.size(); i++) {
             Transport t = (Transport)_transports.get(i);
             RouterAddress addr = t.startListening();
-            _log.debug("Transport " + i + " (" + t.getStyle() + ") started");
+            if (_log.shouldLog(Log.DEBUG))
+                _log.debug("Transport " + i + " (" + t.getStyle() + ") started");
         }
         _log.debug("Done start listening on transports");
         _context.router().rebuildRouterInfo();
@@ -123,10 +158,10 @@ public class TransportManager implements TransportEventListener {
         _transports.clear();
     }
     
-    public Transport getNTCPTransport() {
+    public Transport getTransport(String style) {
         for (int i = 0; i < _transports.size(); i++) {
             Transport t = (Transport)_transports.get(i);
-            if("NTCP".equals(t.getStyle()))
+            if(style.equals(t.getStyle()))
                 return t;
         }
         return null;
diff --git a/router/java/src/net/i2p/router/transport/UPnPManager.java b/router/java/src/net/i2p/router/transport/UPnPManager.java
index a508cabef3..ca7873903b 100644
--- a/router/java/src/net/i2p/router/transport/UPnPManager.java
+++ b/router/java/src/net/i2p/router/transport/UPnPManager.java
@@ -4,6 +4,7 @@ package net.i2p.router.transport;
  * public domain
  */
 
+import java.net.InetAddress;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Properties;
@@ -23,9 +24,7 @@ import org.freenetproject.ForwardPortStatus;
  * Bridge from the I2P RouterAddress data structure to
  * the freenet data structures
  *
- * No disable option yet.
  * UPnP listens on ports 1900, 8008, and 8058 - no config option yet.
- * No routerconsole support yet.
  *
  * @author zzz
  */
@@ -35,9 +34,12 @@ public class UPnPManager {
     private UPnP _upnp;
     private UPnPCallback _upnpCallback;
     private boolean _isRunning;
+    private InetAddress _detectedAddress;
+    private TransportManager _manager;
 
-    public UPnPManager(RouterContext context) {
+    public UPnPManager(RouterContext context, TransportManager manager) {
         _context = context;
+        _manager = manager;
         _log = _context.logManager().getLog(UPnPManager.class);
         _upnp = new UPnP(context);
         _upnpCallback = new UPnPCallback();
@@ -60,6 +62,7 @@ public class UPnPManager {
         if (_isRunning)
             _upnp.terminate();
         _isRunning = false;
+        _detectedAddress = null;
     }
     
     /** call when the ports might have changed */
@@ -98,7 +101,10 @@ public class UPnPManager {
         _upnp.onChangePublicPorts(forwards, _upnpCallback);
     }
 
-    /** just logs for now */
+    /**
+     *  This is the callback from UPnP.
+     *  It calls the TransportManager callbacks.
+     */
     private class UPnPCallback implements ForwardPortCallback {
 	
         /** Called to indicate status on one or more forwarded ports. */
@@ -107,10 +113,19 @@ public class UPnPManager {
                  _log.debug("UPnP Callback:");
 
             DetectedIP[] ips = _upnp.getAddress();
+            byte[] detected = null;
             if (ips != null) {
                 for (DetectedIP ip : ips) {
-                    if (_log.shouldLog(Log.DEBUG))
-                        _log.debug("External address: " + ip.publicAddress + " type: " + ip.natType);
+                    // store the first public one and tell the transport manager if it changed
+                    if (TransportImpl.isPubliclyRoutable(ip.publicAddress.getAddress())) {
+                        if (_log.shouldLog(Log.DEBUG))
+                            _log.debug("External address: " + ip.publicAddress + " type: " + ip.natType);
+                        if (!ip.publicAddress.equals(_detectedAddress)) {
+                            _detectedAddress = ip.publicAddress;
+                            _manager.externalAddressReceived(Transport.SOURCE_UPNP, _detectedAddress.getAddress(), 0);
+                        }
+                        break;
+                    }
                 }
             } else {
                 if (_log.shouldLog(Log.DEBUG))
@@ -122,6 +137,15 @@ public class UPnPManager {
                 if (_log.shouldLog(Log.DEBUG))
                     _log.debug(fp.name + " " + fp.protocol + " " + fp.portNumber +
                                " status: " + fps.status + " reason: " + fps.reasonString + " ext port: " + fps.externalPort);
+                String style;
+                if (fp.protocol == ForwardPort.PROTOCOL_UDP_IPV4)
+                    style = "SSU";
+                else if (fp.protocol == ForwardPort.PROTOCOL_TCP_IPV4)
+                    style = "NTCP";
+                else
+                    continue;
+                boolean success = fps.status >= ForwardPortStatus.PROBABLE_SUCCESS;
+                _manager.forwardPortStatus(style, fp.portNumber, success, fps.reasonString);
             }
         }
     }
diff --git a/router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java b/router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java
index 4464e5f2d0..32a108ec06 100644
--- a/router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java
+++ b/router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java
@@ -539,6 +539,19 @@ public class NTCPTransport extends TransportImpl {
         }
     }
 
+    /**
+     *  If we didn't used to be forwarded, and we have an address,
+     *  and we are configured to use UPnP, update our RouterAddress
+     */
+    public void forwardPortStatus(int port, boolean success, String reason) {
+        if (_log.shouldLog(Log.WARN)) {
+            if (success)
+                _log.warn("UPnP has opened the NTCP port: " + port);
+            else
+                _log.warn("UPnP has failed to open the NTCP port: " + port + " reason: " + reason);
+        }
+    }
+
     /**
      *  This doesn't (completely) block, caller should check isAlive()
      *  before calling startListening() or restartListening()
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 69e5190fb9..9e4289e386 100644
--- a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java
+++ b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java
@@ -326,6 +326,15 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
         _lastInboundReceivedOn = System.currentTimeMillis(); 
     }
     
+    /**
+     * From config, UPnP, local i/f, ...
+     */
+    public void externalAddressReceived(String source, byte[] ip, int port) {
+        String s = RemoteHostId.toString(ip);
+        if (_log.shouldLog(Log.WARN))
+            _log.warn("Received address: " + s + " port: " + port + " from: " + source);
+    }
+
     /**
      * Someone we tried to contact gave us what they think our IP address is.
      * Right now, we just blindly trust them, changing our IP and port on a
diff --git a/router/java/src/org/cybergarage/util/Debug.java b/router/java/src/org/cybergarage/util/Debug.java
index 6cd9d939e8..caf6352ec2 100644
--- a/router/java/src/org/cybergarage/util/Debug.java
+++ b/router/java/src/org/cybergarage/util/Debug.java
@@ -3,7 +3,7 @@
 *	CyberUtil for Java
 *
 *	Copyright (C) Satoshi Konno 2002
-*
+*
 *	File: Debug.java
 *
 *	Revision;
@@ -12,40 +12,40 @@
 *		- first revision.
 *
 ******************************************************************/
-
+
 package org.cybergarage.util;
-
+
 public final class Debug
 {
 	public static boolean enabled = false;
 	
 	public static final void on() {
 		enabled = true;
-	}
+	}
 	public static final void off() {
 		enabled = false;
-	}
+	}
 	public static boolean isOn() {
 		return enabled;
-	}
-	public static final void message(String s) {
-		if (enabled == true)
-			System.out.println("CyberGarage message : " + s);
-	}
+	}
+	public static final void message(String s) {
+		if (enabled == true)
+			System.out.println("UPnP message : " + s);
+	}
 	public static final void message(String m1, String m2) {
 		if (enabled == true)
-			System.out.println("CyberGarage message : ");
+			System.out.println("UPnP message : ");
 			System.out.println(m1);
 			System.out.println(m2);
 	}
-	public static final void warning(String s) {
-		System.out.println("CyberGarage warning : " + s);
-	}
+	public static final void warning(String s) {
+		System.out.println("UPnP warning : " + s);
+	}
 	public static final void warning(String m, Exception e) {
-		System.out.println("CyberGarage warning : " + m + " (" + e.getMessage() + ")");
+		System.out.println("UPnP warning : " + m + " (" + e.getMessage() + ")");
 	}
 	public static final void warning(Exception e) {
-		warning(e.getMessage());
+		warning(e.getMessage());
 		e.printStackTrace();
-	}
-}
\ No newline at end of file
+	}
+}
-- 
GitLab