forked from I2P_Developers/i2p.i2p
Transport: Rescan addresses and UPnP after network reconnection
Log network disconnect/reconnect Don't even try to start UPnP if network disconnected Fix UPnP repeatedly decrementing listen ports on failure Make more classes and methods package private Log and javadoc tweaks
This commit is contained in:
@ -618,8 +618,18 @@ public class CommSystemFacadeImpl extends CommSystemFacade {
|
||||
public void timeReached() {
|
||||
boolean good = Addresses.isConnected();
|
||||
if (_netMonitorStatus != good) {
|
||||
if (good)
|
||||
_log.logAlways(Log.INFO, "Network reconnected");
|
||||
else
|
||||
_log.error("Network disconnected");
|
||||
_context.router().eventLog().addEvent(EventLog.NETWORK, good ? "connected" : "disconnected");
|
||||
_netMonitorStatus = good;
|
||||
if (good) {
|
||||
// Check local addresses
|
||||
_manager.initializeAddress();
|
||||
// fire UPnP
|
||||
_manager.transportAddressChanged();
|
||||
}
|
||||
}
|
||||
reschedule(good ? LONG_DELAY : SHORT_DELAY);
|
||||
}
|
||||
|
@ -14,6 +14,8 @@ import java.net.InetAddress;
|
||||
import java.net.Inet6Address;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@ -43,6 +45,17 @@ import net.i2p.util.SystemVersion;
|
||||
import net.i2p.util.Translate;
|
||||
import net.i2p.util.VersionComparator;
|
||||
|
||||
/**
|
||||
* Keeps track of the enabled transports.
|
||||
* Starts UPnP.
|
||||
* Pluggable transport support incomplete.
|
||||
*
|
||||
* Public only for a couple things in the console and Android.
|
||||
* To be made package private.
|
||||
* Everything external should go through CommSystemFacadeImpl.
|
||||
* Not a public API, not for external use.
|
||||
*
|
||||
*/
|
||||
public class TransportManager implements TransportEventListener {
|
||||
private final Log _log;
|
||||
/**
|
||||
@ -144,10 +157,10 @@ public class TransportManager implements TransportEventListener {
|
||||
|
||||
private void removeTransport(Transport transport) {
|
||||
if (transport == null) return;
|
||||
transport.setListener(null);
|
||||
Transport old = _transports.remove(transport.getStyle());
|
||||
if (old != null && _log.shouldLog(Log.WARN))
|
||||
_log.warn("Removing transport " + transport.getStyle());
|
||||
transport.setListener(null);
|
||||
}
|
||||
|
||||
private void configTransports() {
|
||||
@ -183,6 +196,26 @@ public class TransportManager implements TransportEventListener {
|
||||
* It's the transport's job to ignore what it can't handle.
|
||||
*/
|
||||
private void initializeAddress(Transport t) {
|
||||
initializeAddress(Collections.singleton(t));
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify all transports of ALL routable interface addresses, including IPv6.
|
||||
* It's the transport's job to ignore what it can't handle.
|
||||
* @since 0.9.34
|
||||
*/
|
||||
void initializeAddress() {
|
||||
initializeAddress(_transports.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify transports of ALL routable interface addresses, including IPv6.
|
||||
* It's the transport's job to ignore what it can't handle.
|
||||
* @since 0.9.34
|
||||
*/
|
||||
private void initializeAddress(Collection<Transport> ts) {
|
||||
if (ts.isEmpty())
|
||||
return;
|
||||
Set<String> ipset = Addresses.getAddresses(false, true); // non-local, include IPv6
|
||||
//
|
||||
// Avoid IPv6 temporary addresses if we have a non-temporary one
|
||||
@ -226,9 +259,11 @@ public class TransportManager implements TransportEventListener {
|
||||
addresses.addAll(tempV6Addresses);
|
||||
}
|
||||
}
|
||||
for (InetAddress ia : addresses) {
|
||||
byte[] ip = ia.getAddress();
|
||||
t.externalAddressReceived(SOURCE_INTERFACE, ip, 0);
|
||||
for (Transport t : ts) {
|
||||
for (InetAddress ia : addresses) {
|
||||
byte[] ip = ia.getAddress();
|
||||
t.externalAddressReceived(SOURCE_INTERFACE, ip, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -238,7 +273,7 @@ public class TransportManager implements TransportEventListener {
|
||||
* Tell all transports... but don't loop.
|
||||
*
|
||||
*/
|
||||
public void externalAddressReceived(Transport.AddressSource source, byte[] ip, int port) {
|
||||
void externalAddressReceived(Transport.AddressSource source, byte[] ip, int port) {
|
||||
for (Transport t : _transports.values()) {
|
||||
// don't loop
|
||||
if (!(source == SOURCE_SSU && t.getStyle().equals(UDPTransport.STYLE)))
|
||||
@ -253,7 +288,7 @@ public class TransportManager implements TransportEventListener {
|
||||
*
|
||||
* @since 0.9.20
|
||||
*/
|
||||
public void externalAddressRemoved(Transport.AddressSource source, boolean ipv6) {
|
||||
void externalAddressRemoved(Transport.AddressSource source, boolean ipv6) {
|
||||
for (Transport t : _transports.values()) {
|
||||
// don't loop
|
||||
if (!(source == SOURCE_SSU && t.getStyle().equals(UDPTransport.STYLE)))
|
||||
@ -265,13 +300,13 @@ public class TransportManager implements TransportEventListener {
|
||||
* callback from UPnP
|
||||
*
|
||||
*/
|
||||
public void forwardPortStatus(String style, byte[] ip, int port, int externalPort, boolean success, String reason) {
|
||||
void forwardPortStatus(String style, byte[] ip, int port, int externalPort, boolean success, String reason) {
|
||||
Transport t = getTransport(style);
|
||||
if (t != null)
|
||||
t.forwardPortStatus(ip, port, externalPort, success, reason);
|
||||
}
|
||||
|
||||
public synchronized void startListening() {
|
||||
synchronized void startListening() {
|
||||
if (_dhThread.getState() == Thread.State.NEW)
|
||||
_dhThread.start();
|
||||
// For now, only start UPnP if we have no publicly-routable addresses
|
||||
@ -307,7 +342,7 @@ public class TransportManager implements TransportEventListener {
|
||||
_context.router().rebuildRouterInfo();
|
||||
}
|
||||
|
||||
public synchronized void restart() {
|
||||
synchronized void restart() {
|
||||
stopListening();
|
||||
try { Thread.sleep(5*1000); } catch (InterruptedException ie) {}
|
||||
startListening();
|
||||
@ -316,7 +351,7 @@ public class TransportManager implements TransportEventListener {
|
||||
/**
|
||||
* Can be restarted.
|
||||
*/
|
||||
public synchronized void stopListening() {
|
||||
synchronized void stopListening() {
|
||||
if (_upnpManager != null)
|
||||
_upnpManager.stop();
|
||||
for (Transport t : _transports.values()) {
|
||||
@ -330,14 +365,14 @@ public class TransportManager implements TransportEventListener {
|
||||
* Cannot be restarted.
|
||||
* @since 0.9
|
||||
*/
|
||||
public synchronized void shutdown() {
|
||||
synchronized void shutdown() {
|
||||
stopListening();
|
||||
_dhThread.shutdown();
|
||||
Addresses.clearCaches();
|
||||
TransportImpl.clearCaches();
|
||||
}
|
||||
|
||||
public Transport getTransport(String style) {
|
||||
Transport getTransport(String style) {
|
||||
return _transports.get(style);
|
||||
}
|
||||
|
||||
@ -347,7 +382,7 @@ public class TransportManager implements TransportEventListener {
|
||||
* @return SortedMap of style to Transport (a copy)
|
||||
* @since 0.9.31
|
||||
*/
|
||||
public SortedMap<String, Transport> getTransports() {
|
||||
SortedMap<String, Transport> getTransports() {
|
||||
TreeMap<String, Transport> rv = new TreeMap<String, Transport>();
|
||||
rv.putAll(_transports);
|
||||
// TODO (also synch)
|
||||
@ -359,7 +394,7 @@ public class TransportManager implements TransportEventListener {
|
||||
* How many peers are we currently connected to, that we have
|
||||
* sent a message to or received a message from in the last five minutes.
|
||||
*/
|
||||
public int countActivePeers() {
|
||||
int countActivePeers() {
|
||||
int peers = 0;
|
||||
for (Transport t : _transports.values()) {
|
||||
peers += t.countActivePeers();
|
||||
@ -372,7 +407,7 @@ public class TransportManager implements TransportEventListener {
|
||||
* sent a message to in the last minute.
|
||||
* Unused for anything, to be removed.
|
||||
*/
|
||||
public int countActiveSendPeers() {
|
||||
int countActiveSendPeers() {
|
||||
int peers = 0;
|
||||
for (Transport t : _transports.values()) {
|
||||
peers += t.countActiveSendPeers();
|
||||
@ -386,7 +421,7 @@ public class TransportManager implements TransportEventListener {
|
||||
*
|
||||
* @param pct percent of limit 0-100
|
||||
*/
|
||||
public boolean haveOutboundCapacity(int pct) {
|
||||
boolean haveOutboundCapacity(int pct) {
|
||||
for (Transport t : _transports.values()) {
|
||||
if (t.haveCapacity(pct))
|
||||
return true;
|
||||
@ -399,7 +434,7 @@ public class TransportManager implements TransportEventListener {
|
||||
* Are all transports well below their outbound connection limit
|
||||
* Use for throttling in the router.
|
||||
*/
|
||||
public boolean haveHighOutboundCapacity() {
|
||||
boolean haveHighOutboundCapacity() {
|
||||
if (_transports.isEmpty())
|
||||
return false;
|
||||
for (Transport t : _transports.values()) {
|
||||
@ -415,7 +450,7 @@ public class TransportManager implements TransportEventListener {
|
||||
*
|
||||
* @param pct percent of limit 0-100
|
||||
*/
|
||||
public boolean haveInboundCapacity(int pct) {
|
||||
boolean haveInboundCapacity(int pct) {
|
||||
for (Transport t : _transports.values()) {
|
||||
if (t.hasCurrentAddress() && t.haveCapacity(pct))
|
||||
return true;
|
||||
@ -429,7 +464,7 @@ public class TransportManager implements TransportEventListener {
|
||||
* A positive number means our clock is ahead of theirs.
|
||||
* Note: this method returns them in whimsical order.
|
||||
*/
|
||||
public Vector<Long> getClockSkews() {
|
||||
Vector<Long> getClockSkews() {
|
||||
Vector<Long> skews = new Vector<Long>();
|
||||
for (Transport t : _transports.values()) {
|
||||
Vector<Long> tempSkews = t.getClockSkews();
|
||||
@ -445,7 +480,7 @@ public class TransportManager implements TransportEventListener {
|
||||
* Previously returned short, now enum as of 0.9.20
|
||||
* @return the best status of any transport
|
||||
*/
|
||||
public Status getReachabilityStatus() {
|
||||
Status getReachabilityStatus() {
|
||||
Status rv = Status.UNKNOWN;
|
||||
for (Transport t : _transports.values()) {
|
||||
Status s = t.getReachabilityStatus();
|
||||
@ -459,12 +494,12 @@ public class TransportManager implements TransportEventListener {
|
||||
* @deprecated unused
|
||||
*/
|
||||
@Deprecated
|
||||
public void recheckReachability() {
|
||||
void recheckReachability() {
|
||||
for (Transport t : _transports.values())
|
||||
t.recheckReachability();
|
||||
}
|
||||
|
||||
public boolean isBacklogged(Hash peer) {
|
||||
boolean isBacklogged(Hash peer) {
|
||||
for (Transport t : _transports.values()) {
|
||||
if (t.isBacklogged(peer))
|
||||
return true;
|
||||
@ -472,7 +507,7 @@ public class TransportManager implements TransportEventListener {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isEstablished(Hash peer) {
|
||||
boolean isEstablished(Hash peer) {
|
||||
for (Transport t : _transports.values()) {
|
||||
if (t.isEstablished(peer))
|
||||
return true;
|
||||
@ -486,7 +521,7 @@ public class TransportManager implements TransportEventListener {
|
||||
*
|
||||
* @since 0.9.24
|
||||
*/
|
||||
public void mayDisconnect(Hash peer) {
|
||||
void mayDisconnect(Hash peer) {
|
||||
for (Transport t : _transports.values()) {
|
||||
t.mayDisconnect(peer);
|
||||
}
|
||||
@ -497,7 +532,7 @@ public class TransportManager implements TransportEventListener {
|
||||
* based on the last time we tried it for each transport?
|
||||
* This is NOT reset if the peer contacts us.
|
||||
*/
|
||||
public boolean wasUnreachable(Hash peer) {
|
||||
boolean wasUnreachable(Hash peer) {
|
||||
for (Transport t : _transports.values()) {
|
||||
if (!t.wasUnreachable(peer))
|
||||
return false;
|
||||
@ -516,14 +551,14 @@ public class TransportManager implements TransportEventListener {
|
||||
*
|
||||
* @return IPv4 or IPv6 or null
|
||||
*/
|
||||
public byte[] getIP(Hash peer) {
|
||||
byte[] getIP(Hash peer) {
|
||||
return TransportImpl.getIP(peer);
|
||||
}
|
||||
|
||||
/**
|
||||
* This forces a rebuild
|
||||
*/
|
||||
public List<RouterAddress> getAddresses() {
|
||||
List<RouterAddress> getAddresses() {
|
||||
List<RouterAddress> rv = new ArrayList<RouterAddress>(4);
|
||||
// do this first since SSU may force a NTCP change
|
||||
for (Transport t : _transports.values())
|
||||
@ -583,14 +618,15 @@ public class TransportManager implements TransportEventListener {
|
||||
return rv;
|
||||
}
|
||||
|
||||
public TransportBid getBid(OutNetMessage msg) {
|
||||
TransportBid getBid(OutNetMessage msg) {
|
||||
List<TransportBid> bids = getBids(msg);
|
||||
if ( (bids == null) || (bids.isEmpty()) )
|
||||
return null;
|
||||
else
|
||||
return bids.get(0);
|
||||
}
|
||||
public List<TransportBid> getBids(OutNetMessage msg) {
|
||||
|
||||
List<TransportBid> getBids(OutNetMessage msg) {
|
||||
if (msg == null)
|
||||
throw new IllegalArgumentException("Null message? no bidding on a null outNetMessage!");
|
||||
if (_context.router().getRouterInfo().equals(msg.getTarget()))
|
||||
@ -620,7 +656,7 @@ public class TransportManager implements TransportEventListener {
|
||||
return rv;
|
||||
}
|
||||
|
||||
public TransportBid getNextBid(OutNetMessage msg) {
|
||||
TransportBid getNextBid(OutNetMessage msg) {
|
||||
int unreachableTransports = 0;
|
||||
Hash peer = msg.getTarget().getIdentity().calculateHash();
|
||||
Set<String> failedTransports = msg.getFailedTransports();
|
||||
@ -711,7 +747,11 @@ public class TransportManager implements TransportEventListener {
|
||||
_log.warn("Error receiving message", iae);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* TransportEventListener
|
||||
* calls UPnPManager rescan() and update()
|
||||
*/
|
||||
public void transportAddressChanged() {
|
||||
if (_upnpManager != null) {
|
||||
_upnpManager.rescan();
|
||||
@ -720,7 +760,7 @@ public class TransportManager implements TransportEventListener {
|
||||
}
|
||||
}
|
||||
|
||||
public List<String> getMostRecentErrorMessages() {
|
||||
List<String> getMostRecentErrorMessages() {
|
||||
List<String> rv = new ArrayList<String>(16);
|
||||
for (Transport t : _transports.values()) {
|
||||
rv.addAll(t.getMostRecentErrorMessages());
|
||||
|
@ -72,7 +72,7 @@ import org.freenetproject.ForwardPortStatus;
|
||||
* TODO: Advertise the node like the MDNS plugin does
|
||||
* TODO: Implement EventListener and react on ip-change
|
||||
*/
|
||||
public class UPnP extends ControlPoint implements DeviceChangeListener, EventListener {
|
||||
class UPnP extends ControlPoint implements DeviceChangeListener, EventListener {
|
||||
private final Log _log;
|
||||
private final I2PAppContext _context;
|
||||
|
||||
@ -161,6 +161,14 @@ public class UPnP extends ControlPoint implements DeviceChangeListener, EventLis
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* As we only support a single active IGD, and we don't currently have any way
|
||||
* to get any IPv6 addresses, this will return at most one IPv4 address.
|
||||
*
|
||||
* Blocking!!!
|
||||
*
|
||||
* @return array of length 1 containing an IPv4 address, or null
|
||||
*/
|
||||
public DetectedIP[] getAddress() {
|
||||
_log.info("UP&P.getAddress() is called \\o/");
|
||||
if(isDisabled) {
|
||||
@ -475,7 +483,7 @@ public class UPnP extends ControlPoint implements DeviceChangeListener, EventLis
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the external address the NAT thinks we have. Blocking.
|
||||
* @return the external IPv4 address the NAT thinks we have. Blocking.
|
||||
* null if we can't find it.
|
||||
*/
|
||||
private String getNATAddress() {
|
||||
@ -1241,6 +1249,8 @@ public class UPnP extends ControlPoint implements DeviceChangeListener, EventLis
|
||||
cp.listSubDev(device.toString(), device, sb);
|
||||
System.out.println("<h3>Device " + (++i) +
|
||||
": " + DataHelper.escapeHTML(device.getFriendlyName()) + "</h3>");
|
||||
System.out.println("<p>UDN: " + DataHelper.escapeHTML(device.getUDN()));
|
||||
System.out.println("<br>IP: " + getIP(device));
|
||||
System.out.println(sb.toString());
|
||||
sb.setLength(0);
|
||||
}
|
||||
|
@ -69,24 +69,27 @@ class UPnPManager {
|
||||
// set up logging in the UPnP package
|
||||
Debug.initialize(context);
|
||||
_upnp = new UPnP(context);
|
||||
_upnp.setHTTPPort(_context.getProperty(PROP_HTTP_PORT, DEFAULT_HTTP_PORT));
|
||||
_upnp.setSSDPPort(_context.getProperty(PROP_SSDP_PORT, DEFAULT_SSDP_PORT));
|
||||
_upnpCallback = new UPnPCallback();
|
||||
_rescanner = new Rescanner();
|
||||
}
|
||||
|
||||
/**
|
||||
* Blocking, may take a while
|
||||
* Blocking, may take a while.
|
||||
* May be called even if already running.
|
||||
*/
|
||||
public synchronized void start() {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("UPnP Start");
|
||||
_shouldBeRunning = true;
|
||||
if (!_isRunning) {
|
||||
if (!_isRunning && Addresses.isConnected()) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("UPnP Start");
|
||||
long b = _context.clock().now();
|
||||
try {
|
||||
// We set these here every time, because ControlPoint auto-decrements on failure,
|
||||
// and will eventually hit 1024 and then negative
|
||||
_upnp.setHTTPPort(_context.getProperty(PROP_HTTP_PORT, DEFAULT_HTTP_PORT));
|
||||
_upnp.setSSDPPort(_context.getProperty(PROP_SSDP_PORT, DEFAULT_SSDP_PORT));
|
||||
_isRunning = _upnp.runPlugin();
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
if (_log.shouldDebug())
|
||||
_log.info("UPnP runPlugin took " + (_context.clock().now() - b));
|
||||
} catch (RuntimeException e) {
|
||||
// NPE in UPnP (ticket #728), can't let it bring us down
|
||||
@ -98,8 +101,6 @@ class UPnPManager {
|
||||
}
|
||||
if (_isRunning) {
|
||||
_rescanner.schedule(RESCAN_LONG_DELAY);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("UPnP Start Done");
|
||||
} else {
|
||||
_rescanner.schedule(RESCAN_SHORT_DELAY);
|
||||
// Do we have a non-loopback, non-broadcast address?
|
||||
@ -150,9 +151,9 @@ class UPnPManager {
|
||||
if (_lastRescan + RESCAN_MIN_DELAY > now)
|
||||
return;
|
||||
_lastRescan = now;
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("UPnP Rescan Start");
|
||||
if (_isRunning) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("UPnP Rescan");
|
||||
// TODO default search MX (jitter) is 3 seconds... reduce?
|
||||
// See also:
|
||||
// Adaptive Jitter Control for UPnP M-Search
|
||||
@ -249,6 +250,7 @@ class UPnPManager {
|
||||
if (ips != null) {
|
||||
for (DetectedIP ip : ips) {
|
||||
// store the first public one and tell the transport manager if it changed
|
||||
// Note that getAddress() will actually return a max of one address.
|
||||
if (TransportUtil.isPubliclyRoutable(ip.publicAddress.getAddress(), false)) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("External address: " + ip.publicAddress + " type: " + ip.natType);
|
||||
|
Reference in New Issue
Block a user