Transport: UPnP fixes for Android

This commit is contained in:
zzz
2019-05-31 21:43:41 +00:00
parent 8a4c4694ec
commit 1109331dfc
4 changed files with 103 additions and 1 deletions

View File

@ -52,6 +52,7 @@ import net.i2p.router.startup.StartupJob;
import net.i2p.router.startup.WorkingDir;
import net.i2p.router.tasks.*;
import net.i2p.router.transport.FIFOBandwidthLimiter;
import net.i2p.router.transport.UPnPScannerCallback;
import net.i2p.router.transport.ntcp.NTCPTransport;
import net.i2p.router.transport.udp.UDPTransport;
import net.i2p.router.util.EventLog;
@ -103,6 +104,7 @@ public class Router implements RouterClock.ClockShiftListener {
private FamilyKeyCrypto _familyKeyCrypto;
private boolean _familyKeyCryptoFail;
public final Object _familyKeyLock = new Object();
private UPnPScannerCallback _upnpScannerCallback;
public final static String PROP_CONFIG_FILE = "router.configLocation";
@ -384,6 +386,8 @@ public class Router implements RouterClock.ClockShiftListener {
} catch (NumberFormatException nfe) {}
}
_networkID = id;
// for testing
setUPnPScannerCallback(new LoggerCallback());
changeState(State.INITIALIZED);
// ********* Start no threads before here ********* //
}
@ -606,6 +610,32 @@ public class Router implements RouterClock.ClockShiftListener {
*/
public RouterContext getContext() { return _context; }
private class LoggerCallback implements UPnPScannerCallback {
public void beforeScan() { _log.info("SSDP beforeScan()"); }
public void afterScan() { _log.info("SSDP afterScan()"); }
}
/**
* For Android only.
* MUST be set before runRouter() is called.
*
* @param callback the callback or null to clear it
* @since 0.9.41
*/
public synchronized void setUPnPScannerCallback(UPnPScannerCallback callback) {
_upnpScannerCallback = callback;
}
/**
* For Android only.
*
* @return the callback or null if none
* @since 0.9.41
*/
public synchronized UPnPScannerCallback getUPnPScannerCallback() {
return _upnpScannerCallback;
}
/**
* This must be called after instantiation.
* Starts the threads. Does not install updates.

View File

@ -341,7 +341,10 @@ public class TransportManager implements TransportEventListener {
// Maybe we need a config option to force on? Probably not.
// What firewall supports UPnP and is configured with a public address on the LAN side?
// Unlikely.
if (_upnpManager != null && Addresses.getAnyAddress() == null)
// Always start on Android, as we may have a cellular IPv4 address but
// are routing all traffic through WiFi.
// Also, conditions may change rapidly.
if (_upnpManager != null && (SystemVersion.isAndroid() || Addresses.getAnyAddress() == null))
_upnpManager.start();
configTransports();
_log.debug("Starting up the transport manager");

View File

@ -34,6 +34,8 @@ class UPnPManager {
private final RouterContext _context;
private final UPnP _upnp;
private final UPnPCallback _upnpCallback;
private final UPnPScannerCallback _scannerCallback;
private final DelayedCallback _delayedCallback;
private volatile boolean _isRunning;
private volatile boolean _shouldBeRunning;
private volatile long _lastRescan;
@ -73,6 +75,8 @@ class UPnPManager {
Debug.initialize(context);
_upnp = new UPnP(context);
_upnpCallback = new UPnPCallback();
_scannerCallback = _context.router().getUPnPScannerCallback();
_delayedCallback = (_scannerCallback != null) ? new DelayedCallback() : null;
_rescanner = new Rescanner();
}
@ -91,7 +95,16 @@ class UPnPManager {
// 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));
if (_scannerCallback != null) {
_scannerCallback.beforeScan();
}
_isRunning = _upnp.runPlugin();
if (_scannerCallback != null) {
if (_isRunning)
_delayedCallback.reschedule();
else
_scannerCallback.afterScan();
}
if (_log.shouldDebug())
_log.info("UPnP runPlugin took " + (_context.clock().now() - b));
} catch (RuntimeException e) {
@ -100,6 +113,9 @@ class UPnPManager {
_log.error("UPnP error, please report", e);
_errorLogged = true;
}
if (_scannerCallback != null) {
_scannerCallback.afterScan();
}
}
}
if (_isRunning) {
@ -156,6 +172,8 @@ class UPnPManager {
return false;
_lastRescan = now;
if (_isRunning) {
if (_scannerCallback != null)
_scannerCallback.beforeScan();
if (_log.shouldLog(Log.DEBUG))
_log.debug("UPnP Rescan");
// TODO default search MX (jitter) is 3 seconds... reduce?
@ -163,6 +181,8 @@ class UPnPManager {
// Adaptive Jitter Control for UPnP M-Search
// Kevin Mills and Christopher Dabrowski
_upnp.search();
if (_scannerCallback != null)
_delayedCallback.reschedule();
} else {
start();
}
@ -188,6 +208,33 @@ class UPnPManager {
}
}
}
/**
* Delayed Callback
*
* @since 0.9.41
*/
private class DelayedCallback extends SimpleTimer2.TimedEvent {
/** caller must reschedule() */
public DelayedCallback() {
super(_context.simpleTimer2());
}
public void timeReached() {
_scannerCallback.afterScan();
}
/**
* Pushes out.
* We do it this way because we may have two scans running concurrently,
* we only want to call afterScan() once.
*/
void reschedule() {
// false == use latest time
reschedule((_upnp.getSearchMx() * 1000) + 500, false);
}
}
/**
* Call when the ports might have changed

View File

@ -0,0 +1,22 @@
package net.i2p.router.transport;
/**
* For Android MulticastLock.
*
* @since 0.9.41
*/
public interface UPnPScannerCallback {
/**
* Called before a SSDP search begins.
* This may be called more than once before afterScan()
* if there are multiple searches in parallel.
*/
public void beforeScan();
/**
* Called after a SSDP search ends.
* This will only be called once after the last scan ends.
*/
public void afterScan();
}