Transport: Hooks for pluggable transports (ticket #1170)

This commit is contained in:
zzz
2014-09-26 14:16:08 +00:00
parent 1053bc8bb0
commit 72f57255f0
3 changed files with 125 additions and 5 deletions

View File

@ -14,6 +14,8 @@ import java.util.Collections;
import java.util.List;
import net.i2p.data.Hash;
import net.i2p.data.router.RouterAddress;
import net.i2p.router.transport.Transport;
import net.i2p.router.transport.crypto.DHSessionKeyBuilder;
/**
* Manages the communication subsystem between peers, including connections,
@ -85,6 +87,24 @@ public abstract class CommSystemFacade implements Service {
*/
public void notifyReplaceAddress(RouterAddress UDPAddr) {}
/**
* Pluggable transport
* @since 0.9.16
*/
public void registerTransport(Transport t) {}
/**
* Pluggable transport
* @since 0.9.16
*/
public void unregisterTransport(Transport t) {}
/**
* Hook for pluggable transport creation.
* @since 0.9.16
*/
public DHSessionKeyBuilder.Factory getDHFactory() { return null; }
/**
* These must be increasing in "badness" (see TransportManager.java),
* but UNKNOWN must be last.

View File

@ -22,6 +22,7 @@ import net.i2p.data.router.RouterInfo;
import net.i2p.router.CommSystemFacade;
import net.i2p.router.OutNetMessage;
import net.i2p.router.RouterContext;
import net.i2p.router.transport.crypto.DHSessionKeyBuilder;
import net.i2p.router.transport.udp.UDPTransport;
import net.i2p.router.util.EventLog;
import net.i2p.util.Addresses;
@ -222,6 +223,47 @@ public class CommSystemFacadeImpl extends CommSystemFacade {
}
_manager.externalAddressReceived(Transport.AddressSource.SOURCE_SSU, ip, port);
}
/**
* Pluggable transports. Not for NTCP or SSU.
*
* Do not call from transport constructor. Transport must be ready to be started.
*
* Following transport methods will be called:
* setListener()
* externalAddressReceived() (zero or more times, one for each known address)
* startListening();
*
* @since 0.9.16
*/
@Override
public void registerTransport(Transport t) {
_manager.registerAndStart(t);
}
/**
* Pluggable transports. Not for NTCP or SSU.
*
* Following transport methods will be called:
* setListener(null)
* stoptListening();
*
* @since 0.9.16
*/
@Override
public void unregisterTransport(Transport t) {
_manager.stopAndUnregister(t);
}
/**
* Hook for pluggable transport creation.
*
* @since 0.9.16
*/
@Override
public DHSessionKeyBuilder.Factory getDHFactory() {
return _manager.getDHFactory();
}
/*
* GeoIP stuff

View File

@ -13,6 +13,7 @@ import java.io.Writer;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@ -44,6 +45,8 @@ public class TransportManager implements TransportEventListener {
* If we want more than one transport with the same style we will have to change this.
*/
private final Map<String, Transport> _transports;
/** locking: this */
private final Map<String, Transport> _pluggableTransports;
private final RouterContext _context;
private final UPnPManager _upnpManager;
private final DHSessionKeyBuilder.PrecalcRunner _dhThread;
@ -66,22 +69,74 @@ public class TransportManager implements TransportEventListener {
_context.statManager().createRateStat("transport.bidFailNoTransports", "Could not attempt to bid on message, as none of the transports could attempt it", "Transport", new long[] { 60*1000, 10*60*1000, 60*60*1000 });
_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 ConcurrentHashMap<String, Transport>(2);
_pluggableTransports = new HashMap<String, Transport>(2);
if (_context.getBooleanPropertyDefaultTrue(PROP_ENABLE_UPNP))
_upnpManager = new UPnPManager(context, this);
else
_upnpManager = null;
_dhThread = new DHSessionKeyBuilder.PrecalcRunner(context);
}
/**
* Pluggable transports. Not for NTCP or SSU.
*
* @since 0.9.16
*/
synchronized void registerAndStart(Transport t) {
String style = t.getStyle();
if (style.equals(NTCPTransport.STYLE) || style.equals(UDPTransport.STYLE))
throw new IllegalArgumentException("Builtin transport");
if (_transports.containsKey(style) || _pluggableTransports.containsKey(style))
throw new IllegalStateException("Dup transport");
boolean shouldStart = !_transports.isEmpty();
_pluggableTransports.put(style, t);
addTransport(t);
t.setListener(this);
if (shouldStart) {
initializeAddress(t);
t.startListening();
_context.router().rebuildRouterInfo();
} // else will be started by configTransports() (unlikely)
}
/**
* Pluggable transports. Not for NTCP or SSU.
*
* @since 0.9.16
*/
synchronized void stopAndUnregister(Transport t) {
String style = t.getStyle();
if (style.equals(NTCPTransport.STYLE) || style.equals(UDPTransport.STYLE))
throw new IllegalArgumentException("Builtin transport");
t.setListener(null);
_pluggableTransports.remove(style);
removeTransport(t);
t.stopListening();
_context.router().rebuildRouterInfo();
}
/**
* Hook for pluggable transport creation.
*
* @since 0.9.16
*/
DHSessionKeyBuilder.Factory getDHFactory() {
return _dhThread;
}
public void addTransport(Transport transport) {
private void addTransport(Transport transport) {
if (transport == null) return;
_transports.put(transport.getStyle(), transport);
Transport old = _transports.put(transport.getStyle(), transport);
if (old != null && old != transport && _log.shouldLog(Log.WARN))
_log.warn("Replacing transport " + transport.getStyle());
transport.setListener(this);
}
public void removeTransport(Transport transport) {
private void removeTransport(Transport transport) {
if (transport == null) return;
_transports.remove(transport.getStyle());
Transport old = _transports.remove(transport.getStyle());
if (old != null && _log.shouldLog(Log.WARN))
_log.warn("Removing transport " + transport.getStyle());
transport.setListener(null);
}
@ -174,7 +229,10 @@ public class TransportManager implements TransportEventListener {
tp = getTransport(UDPTransport.STYLE);
if (tp != null)
tps.add(tp);
//for (Transport t : _transports.values()) {
// now add any others (pluggable)
for (Transport t : _pluggableTransports.values()) {
tps.add(t);
}
for (Transport t : tps) {
t.startListening();
if (_log.shouldLog(Log.DEBUG))