UPnP fixes part 4:

Update SSDP listening sockets on interface changes
This commit is contained in:
zzz
2020-05-17 14:56:30 +00:00
parent 25338019ca
commit 1af32bfe79
2 changed files with 139 additions and 3 deletions

View File

@ -28,6 +28,8 @@ import net.i2p.util.I2PThread;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.util.Translate; import net.i2p.util.Translate;
import org.cybergarage.http.HTTPServer;
import org.cybergarage.http.HTTPServerList;
import org.cybergarage.upnp.Action; import org.cybergarage.upnp.Action;
import org.cybergarage.upnp.ActionList; import org.cybergarage.upnp.ActionList;
import org.cybergarage.upnp.Argument; import org.cybergarage.upnp.Argument;
@ -42,7 +44,11 @@ import org.cybergarage.upnp.StateVariable;
import org.cybergarage.upnp.UPnPStatus; import org.cybergarage.upnp.UPnPStatus;
import org.cybergarage.upnp.device.DeviceChangeListener; import org.cybergarage.upnp.device.DeviceChangeListener;
import org.cybergarage.upnp.event.EventListener; import org.cybergarage.upnp.event.EventListener;
import org.cybergarage.upnp.ssdp.SSDPNotifySocket;
import org.cybergarage.upnp.ssdp.SSDPNotifySocketList;
import org.cybergarage.upnp.ssdp.SSDPPacket; import org.cybergarage.upnp.ssdp.SSDPPacket;
import org.cybergarage.upnp.ssdp.SSDPSearchResponseSocket;
import org.cybergarage.upnp.ssdp.SSDPSearchResponseSocketList;
import org.cybergarage.util.Debug; import org.cybergarage.util.Debug;
import org.freenetproject.DetectedIP; import org.freenetproject.DetectedIP;
import org.freenetproject.ForwardPort; import org.freenetproject.ForwardPort;
@ -640,6 +646,133 @@ public class UPnP extends ControlPoint implements DeviceChangeListener, EventLis
} }
} }
/**
* Update the SSDPSearchResponseSocketList,
* SSDPNotifySocketList, and HTTPServerList every time.
* Otherwise, we are just listening on the interfaces that were present when started.
*
* @since 0.9.46
*/
private void updateInterfaces() {
Set<String> addrs = Addresses.getAddresses(true, false, false);
// remove public addresses
// see TransportManager.startListening()
for (Iterator<String> iter = addrs.iterator(); iter.hasNext(); ) {
String addr = iter.next();
byte[] ip = Addresses.getIP(addr);
if (ip == null || TransportUtil.isPubliclyRoutable(ip, false))
iter.remove();
}
Set<String> oldaddrs = new HashSet<String>(addrs.size());
// protect against list mod in super.stop()
synchronized(this) {
// we do this one first because we can detect failure before adding
HTTPServerList hlist = getHTTPServerList();
for (Iterator<HTTPServer> iter = hlist.iterator(); iter.hasNext(); ) {
HTTPServer skt = iter.next();
String addr = skt.getBindAddress();
int slash = addr.indexOf('/');
if (slash >= 0)
addr = addr.substring(slash + 1);
if (!addrs.contains(addr)) {
iter.remove();
skt.close();
skt.stop();
if (_log.shouldWarn())
_log.warn("Closed HTTP server socket: " + addr);
}
oldaddrs.add(addr);
}
for (Iterator<String> iter = addrs.iterator(); iter.hasNext(); ) {
String addr = iter.next();
if (!oldaddrs.contains(addr)) {
HTTPServer socket = new HTTPServer();
boolean ok = socket.open(addr, getHTTPPort());
if (ok) {
socket.addRequestListener(this);
socket.start();
hlist.add(socket);
if (_log.shouldWarn())
_log.warn("Added HTTP server socket: " + addr);
} else {
// so we don't attempt to add to the other lists below
iter.remove();
if (_log.shouldWarn())
_log.warn("open() failed on new HTTP server socket: " + addr);
}
}
}
oldaddrs.clear();
SSDPSearchResponseSocketList list = getSSDPSearchResponseSocketList();
for (Iterator<SSDPSearchResponseSocket> iter = list.iterator(); iter.hasNext(); ) {
SSDPSearchResponseSocket skt = iter.next();
String addr = skt.getLocalAddress();
if (!addrs.contains(addr)) {
iter.remove();
skt.setControlPoint(null);
skt.close();
skt.stop();
if (_log.shouldWarn())
_log.warn("Closed SSDP search response socket: " + addr);
}
oldaddrs.add(addr);
}
for (String addr : addrs) {
if (!oldaddrs.contains(addr)) {
// TODO this calls open() in constructor, fails silently
SSDPSearchResponseSocket socket = new SSDPSearchResponseSocket(addr, getSSDPPort());
socket.setControlPoint(this);
socket.start();
list.add(socket);
if (_log.shouldWarn())
_log.warn("Added SSDP search response socket: " + addr);
}
}
oldaddrs.clear();
SSDPNotifySocketList nlist = getSSDPNotifySocketList();
for (Iterator<SSDPNotifySocket> iter = nlist.iterator(); iter.hasNext(); ) {
SSDPNotifySocket skt = iter.next();
String addr = skt.getLocalAddress();
if (!addrs.contains(addr)) {
iter.remove();
skt.setControlPoint(null);
skt.close();
skt.stop();
if (_log.shouldWarn())
_log.warn("Closed SSDP notify socket: " + addr);
}
oldaddrs.add(addr);
}
for (String addr : addrs) {
if (!oldaddrs.contains(addr)) {
// TODO this calls open() in constructor, fails silently
SSDPNotifySocket socket = new SSDPNotifySocket(addr);
socket.setControlPoint(this);
socket.start();
nlist.add(socket);
if (_log.shouldWarn())
_log.warn("Added SSDP notify socket: " + addr);
}
}
}
}
/**
* We override search() to update the SSDPSearchResponseSocketList,
* SSDPNotifySocketList, and HTTPServerList every time.
* Otherwise, we are just listening on the interfaces that were present when started.
*
* @since 0.9.46
*/
@Override
public void search() {
updateInterfaces();
super.search();
}
/** compare two strings, either of which could be null */ /** compare two strings, either of which could be null */
private static boolean stringEquals(String a, String b) { private static boolean stringEquals(String a, String b) {
if (a != null) if (a != null)

View File

@ -111,12 +111,14 @@ public class ControlPoint implements HTTPRequestListener
private SSDPNotifySocketList ssdpNotifySocketList; private SSDPNotifySocketList ssdpNotifySocketList;
private SSDPSearchResponseSocketList ssdpSearchResponseSocketList; private SSDPSearchResponseSocketList ssdpSearchResponseSocketList;
private SSDPNotifySocketList getSSDPNotifySocketList() /** I2P was private */
protected SSDPNotifySocketList getSSDPNotifySocketList()
{ {
return ssdpNotifySocketList; return ssdpNotifySocketList;
} }
private SSDPSearchResponseSocketList getSSDPSearchResponseSocketList() /** I2P was private */
protected SSDPSearchResponseSocketList getSSDPSearchResponseSocketList()
{ {
return ssdpSearchResponseSocketList; return ssdpSearchResponseSocketList;
} }
@ -574,7 +576,8 @@ public class ControlPoint implements HTTPRequestListener
private HTTPServerList httpServerList = new HTTPServerList(); private HTTPServerList httpServerList = new HTTPServerList();
private HTTPServerList getHTTPServerList() /** I2P was private */
protected HTTPServerList getHTTPServerList()
{ {
return httpServerList; return httpServerList;
} }