Transport: Fix thrashing of UPnP IPv6 listen sockets

Strip % suffixes from addresses before comparing
Fix HTTPMUSocket.getLocalAddress() to return the correct bound address
Throw exception on multicast socket bind failures, don't attempt
further operations on failed sockets
Add toString() to sockets for debugging
Log tweaks
This commit is contained in:
zzz
2022-05-11 11:54:25 -04:00
parent 07dbab9f02
commit 81255e19ae
12 changed files with 128 additions and 32 deletions

View File

@ -1,4 +1,5 @@
2022-05-11 zzz
* Transport: Fix thrashing of UPnP IPv6 listen sockets
* Util: Rename modified apache classes (Gitlab ticket #353)
2022-05-02 zzz

View File

@ -18,7 +18,7 @@ public class RouterVersion {
/** deprecated */
public final static String ID = "Git";
public final static String VERSION = CoreVersion.VERSION;
public final static long BUILD = 17;
public final static long BUILD = 18;
/** for example "-test" */
public final static String EXTRA = "-rc";

View File

@ -3,6 +3,7 @@
* http://www.gnu.org/ for further details of the GPL. */
package net.i2p.router.transport;
import java.io.IOException;
import java.io.Serializable;
import java.net.InetAddress;
import java.net.Inet6Address;
@ -724,12 +725,20 @@ public class UPnP extends ControlPoint implements DeviceChangeListener, EventLis
int slash = addr.indexOf('/');
if (slash >= 0)
addr = addr.substring(slash + 1);
int pct = addr.indexOf('%');
if (pct > 0)
addr = addr.substring(0, pct);
if (!addrs.contains(addr)) {
// the first time through this will close a lot of sockets,
// because HTTPServerList binds to every address,
// including IPv6 deprecated
iter.remove();
skt.close();
skt.stop();
if (_log.shouldWarn())
_log.warn("Closed HTTP server socket: " + addr);
} else if (_log.shouldDebug()) {
_log.debug("Retained HTTP server socket: " + addr);
}
oldaddrs.add(addr);
}
@ -758,6 +767,9 @@ public class UPnP extends ControlPoint implements DeviceChangeListener, EventLis
for (Iterator<SSDPSearchResponseSocket> iter = list.iterator(); iter.hasNext(); ) {
SSDPSearchResponseSocket skt = iter.next();
String addr = skt.getLocalAddress();
int pct = addr.indexOf('%');
if (pct > 0)
addr = addr.substring(0, pct);
if (!addrs.contains(addr)) {
iter.remove();
skt.setControlPoint(null);
@ -765,6 +777,8 @@ public class UPnP extends ControlPoint implements DeviceChangeListener, EventLis
skt.stop();
if (_log.shouldWarn())
_log.warn("Closed SSDP search response socket: " + addr);
} else if (_log.shouldDebug()) {
_log.debug("Retained SSDP search response socket: " + addr);
}
oldaddrs.add(addr);
}
@ -785,6 +799,9 @@ public class UPnP extends ControlPoint implements DeviceChangeListener, EventLis
for (Iterator<SSDPNotifySocket> iter = nlist.iterator(); iter.hasNext(); ) {
SSDPNotifySocket skt = iter.next();
String addr = skt.getLocalAddress();
int pct = addr.indexOf('%');
if (pct > 0)
addr = addr.substring(0, pct);
if (!addrs.contains(addr)) {
iter.remove();
skt.setControlPoint(null);
@ -792,20 +809,29 @@ public class UPnP extends ControlPoint implements DeviceChangeListener, EventLis
skt.stop();
if (_log.shouldWarn())
_log.warn("Closed SSDP notify socket: " + addr);
} else if (_log.shouldDebug()) {
_log.debug("Retained 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);
try {
SSDPNotifySocket socket = new SSDPNotifySocket(addr);
socket.setControlPoint(this);
socket.start();
nlist.add(socket);
if (_log.shouldWarn())
_log.warn("Added SSDP notify socket: " + addr);
} catch (IOException ioe) {
if (_log.shouldWarn())
_log.warn("Failed to add SSDP notify socket: " + addr, ioe);
}
}
}
if (_log.shouldDebug())
_log.debug("Current sockets:\nHTTP: " + hlist + "\nSearch response: " + list + "\nNotify: " + nlist);
}
}
@ -1562,7 +1588,8 @@ public class UPnP extends ControlPoint implements DeviceChangeListener, EventLis
Service service;
synchronized(lock) {
if(!isNATPresent()) {
_log.error("Can't removeMapping: " + isNATPresent() + " " + _router);
if (_log.shouldWarn())
_log.warn("Can't removeMapping: " + isNATPresent() + " " + _router);
return false;
}
service = fp.isIP6 ? _service6 : _service;

View File

@ -262,4 +262,8 @@ public class HTTPServer implements Runnable
httpServerThread = null;
return true;
}
/** I2P */
@Override
public String toString() { return getBindAddress(); }
}

View File

@ -98,6 +98,7 @@ package org.cybergarage.upnp;
import java.io.File;
import java.io.InputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.URL;
import java.util.Calendar;
@ -1439,7 +1440,14 @@ public class Device implements org.cybergarage.http.HTTPRequestListener,
public void announce(String bindAddr) {
String devLocation = getLocationURL(bindAddr);
SSDPNotifySocket ssdpSock = new SSDPNotifySocket(bindAddr);
SSDPNotifySocket ssdpSock;
// I2P
try {
ssdpSock = new SSDPNotifySocket(bindAddr);
} catch (IOException ioe) {
Debug.warning("Failed announce from " + bindAddr, ioe);
return;
}
SSDPNotifyRequest ssdpReq = new SSDPNotifyRequest();
ssdpReq.setServer(UPnP.getServerName());
@ -1514,7 +1522,14 @@ public class Device implements org.cybergarage.http.HTTPRequestListener,
}
public void byebye(String bindAddr) {
SSDPNotifySocket ssdpSock = new SSDPNotifySocket(bindAddr);
SSDPNotifySocket ssdpSock;
// I2P
try {
ssdpSock = new SSDPNotifySocket(bindAddr);
} catch (IOException ioe) {
Debug.warning("Failed byebye from " + bindAddr, ioe);
return;
}
SSDPNotifyRequest ssdpReq = new SSDPNotifyRequest();
ssdpReq.setNTS(NTS.BYEBYE);

View File

@ -73,6 +73,7 @@ package org.cybergarage.upnp;
import java.io.File;
import java.io.InputStream;
import java.io.IOException;
import java.net.URL;
import java.util.Iterator;
@ -662,9 +663,14 @@ public class Service
ssdpReq.setNT(serviceNT);
ssdpReq.setUSN(serviceUSN);
SSDPNotifySocket ssdpSock = new SSDPNotifySocket(bindAddr);
Device.notifyWait();
ssdpSock.post(ssdpReq);
// I2P
try {
SSDPNotifySocket ssdpSock = new SSDPNotifySocket(bindAddr);
Device.notifyWait();
ssdpSock.post(ssdpReq);
} catch (IOException ioe) {
Debug.warning("Failed announce from " + bindAddr, ioe);
}
}
public void byebye(String bindAddr)
@ -679,9 +685,14 @@ public class Service
ssdpReq.setNT(devNT);
ssdpReq.setUSN(devUSN);
SSDPNotifySocket ssdpSock = new SSDPNotifySocket(bindAddr);
Device.notifyWait();
ssdpSock.post(ssdpReq);
// I2P
try {
SSDPNotifySocket ssdpSock = new SSDPNotifySocket(bindAddr);
Device.notifyWait();
ssdpSock.post(ssdpReq);
} catch (IOException ioe) {
Debug.warning("Failed announce from " + bindAddr, ioe);
}
}
public boolean serviceSearchResponse(SSDPPacket ssdpPacket)

View File

@ -55,6 +55,8 @@ public class HTTPMUSocket
private InetSocketAddress ssdpMultiGroup = null;
private MulticastSocket ssdpMultiSock = null;
private NetworkInterface ssdpMultiIf = null;
/** I2P */
private InetAddress _bindAddress;
////////////////////////////////////////////////
// Constructor
@ -80,6 +82,7 @@ public class HTTPMUSocket
public String getLocalAddress()
{
/**** I2P fix
if (ssdpMultiGroup == null || ssdpMultiIf == null)
return "";
InetAddress mcastAddr = ssdpMultiGroup.getAddress();
@ -92,6 +95,10 @@ public class HTTPMUSocket
return addr.getHostAddress();
}
return "";
****/
if (_bindAddress == null)
return "";
return _bindAddress.getHostAddress();
}
/**
@ -151,6 +158,8 @@ public class HTTPMUSocket
ssdpMultiGroup = new InetSocketAddress(InetAddress.getByName(addr), port);
ssdpMultiIf = NetworkInterface.getByInetAddress(bindAddr);
ssdpMultiSock.joinGroup(ssdpMultiGroup, ssdpMultiIf);
// I2P
_bindAddress = bindAddr;
}
catch (Exception e) {
Debug.warning(e);
@ -256,5 +265,10 @@ public class HTTPMUSocket
return recvPacket;
}
/** I2P */
@Override
public String toString() { return getLocalAddress(); }
}

View File

@ -268,5 +268,10 @@ public class HTTPUSocket
return true;
}
*/
/** I2P */
@Override
public String toString() { return localAddr; }
}

View File

@ -54,7 +54,7 @@ public class SSDPNotifySocket extends HTTPMUSocket implements Runnable
// Constructor
////////////////////////////////////////////////
public SSDPNotifySocket(String bindAddr)
public SSDPNotifySocket(String bindAddr) throws IOException
{
String addr = SSDP.ADDRESS;
useIPv6Address = false;
@ -62,7 +62,9 @@ public class SSDPNotifySocket extends HTTPMUSocket implements Runnable
addr = SSDP.getIPv6Address();
useIPv6Address = true;
}
open(addr, SSDP.PORT, bindAddr);
boolean ok = open(addr, SSDP.PORT, bindAddr);
if (!ok)
throw new IOException("Bind to " + bindAddr + " failed");
Debug.message("Opened SSDP notify socket at " + bindAddr + ':' + SSDP.PORT);
setControlPoint(null);
}

View File

@ -15,12 +15,14 @@
package org.cybergarage.upnp.ssdp;
import java.io.IOException;
import java.net.InetAddress;
import java.util.*;
import org.cybergarage.net.*;
import org.cybergarage.upnp.*;
import org.cybergarage.util.Debug;
public class SSDPNotifySocketList extends Vector<SSDPNotifySocket>
{
@ -86,8 +88,12 @@ public class SSDPNotifySocketList extends Vector<SSDPNotifySocket>
for (int i = 0; i < bindAddresses.length; i++) {
if(bindAddresses[i]!=null){
SSDPNotifySocket ssdpNotifySocket = new SSDPNotifySocket(bindAddresses[i]);
add(ssdpNotifySocket);
try {
SSDPNotifySocket ssdpNotifySocket = new SSDPNotifySocket(bindAddresses[i]);
add(ssdpNotifySocket);
} catch (IOException ioe) {
Debug.warning("Failed bind to " + bindAddresses[i], ioe);
}
}
}
return true;

View File

@ -54,8 +54,10 @@ public class SSDPSearchSocket extends HTTPMUSocket implements Runnable
* @param multicast The multicast address to use as destination
* @since 1.8
*/
public SSDPSearchSocket(String bindAddr,int port,String multicast){
open(bindAddr,multicast);
public SSDPSearchSocket(String bindAddr,int port,String multicast) throws IOException {
boolean ok = open(bindAddr,multicast);
if (!ok)
throw new IOException("Bind to " + bindAddr + " failed");
}
/**
@ -63,12 +65,15 @@ public class SSDPSearchSocket extends HTTPMUSocket implements Runnable
* @param bindAddr the binding address for sending multicast packet
* @since 1.8
*/
public SSDPSearchSocket(InetAddress bindAddr){
public SSDPSearchSocket(InetAddress bindAddr) throws IOException {
boolean ok;
if(bindAddr.getAddress().length!=4){
this.open((Inet6Address)bindAddr);
ok = this.open((Inet6Address)bindAddr);
}else{
this.open((Inet4Address)bindAddr);
ok = this.open((Inet4Address)bindAddr);
}
if (!ok)
throw new IOException("Bind to " + bindAddr + " failed");
}
////////////////////////////////////////////////

View File

@ -18,11 +18,13 @@
package org.cybergarage.upnp.ssdp;
import java.io.IOException;
import java.net.InetAddress;
import java.util.Vector;
import org.cybergarage.net.HostInterface;
import org.cybergarage.upnp.device.SearchListener;
import org.cybergarage.util.Debug;
public class SSDPSearchSocketList extends Vector<SSDPSearchSocket>
{
@ -101,12 +103,16 @@ public class SSDPSearchSocketList extends Vector<SSDPSearchSocket>
for (int i = 0; i < bindAddresses.length; i++) {
if(bindAddresses[i]!=null){
SSDPSearchSocket ssdpSearchSocket;
if(HostInterface.isIPv6Address(bindAddresses[i]))
ssdpSearchSocket = new SSDPSearchSocket(bindAddresses[i],port ,multicastIPv6 );
else
ssdpSearchSocket = new SSDPSearchSocket(bindAddresses[i],port,multicastIPv4 );
add(ssdpSearchSocket);
try {
SSDPSearchSocket ssdpSearchSocket;
if(HostInterface.isIPv6Address(bindAddresses[i]))
ssdpSearchSocket = new SSDPSearchSocket(bindAddresses[i],port ,multicastIPv6 );
else
ssdpSearchSocket = new SSDPSearchSocket(bindAddresses[i],port,multicastIPv4 );
add(ssdpSearchSocket);
} catch (IOException ioe) {
Debug.warning("Failed bind to " + bindAddresses[i], ioe);
}
}
}
return true;