diff --git a/router/java/src/org/cybergarage/http/HTTPRequest.java b/router/java/src/org/cybergarage/http/HTTPRequest.java index 990429f67..8efcb67b5 100644 --- a/router/java/src/org/cybergarage/http/HTTPRequest.java +++ b/router/java/src/org/cybergarage/http/HTTPRequest.java @@ -388,6 +388,16 @@ public class HTTPRequest extends HTTPPacket private Socket postSocket = null; + private String bindTo = null; + + /** + * I2P - bind HTTP socket to specified local host address + * + * @param fromHost null to not bind to a particlar local address + * @since 0.9.50 + */ + public void setBindHost(String host) { bindTo = host; } + public HTTPResponse post(String host, int port, boolean isKeepAlive) { HTTPResponse httpRes = new HTTPResponse(); @@ -413,6 +423,8 @@ public class HTTPRequest extends HTTPPacket // And set the soTimeout to 2 second (for reads). //postSocket = new Socket(host, port); postSocket = new Socket(); + if (bindTo != null) + postSocket.bind(new InetSocketAddress(bindTo, 0)); postSocket.setSoTimeout(2000); SocketAddress sa = new InetSocketAddress(host, port); postSocket.connect(sa, 3000); diff --git a/router/java/src/org/cybergarage/upnp/Action.java b/router/java/src/org/cybergarage/upnp/Action.java index ccdccc438..cc7755129 100644 --- a/router/java/src/org/cybergarage/upnp/Action.java +++ b/router/java/src/org/cybergarage/upnp/Action.java @@ -52,7 +52,7 @@ public class Action //////////////////////////////////////////////// private Node serviceNode; - private Node actionNode; + private final Node actionNode; private Node getServiceNode() { @@ -369,12 +369,25 @@ public class Action //////////////////////////////////////////////// public boolean postControlAction() + { + return postControlAction(null); + } + + /** + * I2P - bind HTTP socket to specified local host address + * + * @param fromHost null to not bind to a particlar local address + * @since 0.9.50 + */ + public boolean postControlAction(String fromHost) { // Thanks for Giordano Sassaroli (08/30/03) ArgumentList actionArgList = getArgumentList(); ArgumentList actionInputArgList = getInputArgumentList(); ActionRequest ctrlReq = new ActionRequest(); ctrlReq.setRequest(this, actionInputArgList); + if (fromHost != null) + ctrlReq.setBindHost(fromHost); if (Debug.isOn() == true) ctrlReq.print(); ActionResponse ctrlRes = ctrlReq.post(); diff --git a/router/java/src/org/cybergarage/upnp/ControlPoint.java b/router/java/src/org/cybergarage/upnp/ControlPoint.java index fa5b0874b..1bc628aa0 100644 --- a/router/java/src/org/cybergarage/upnp/ControlPoint.java +++ b/router/java/src/org/cybergarage/upnp/ControlPoint.java @@ -108,6 +108,9 @@ public class ControlPoint implements HTTPRequestListener private final static String DEFAULT_EVENTSUB_URI = "/evetSub"; + // I2P + private static final boolean ALLOW_IPV6_LOCATION = true; + //////////////////////////////////////////////// // Member //////////////////////////////////////////////// @@ -277,15 +280,20 @@ public class ControlPoint implements HTTPRequestListener Debug.warning("Ignoring localhost device at " + location); return; } - if (host.startsWith("[")) { - Debug.warning("Ignoring IPv6 device at " + location); - return; + if (host.startsWith("[") && host.endsWith("]")) { + if (!ALLOW_IPV6_LOCATION) { + Debug.warning("Ignoring IPv6 device at " + location); + return; + } + // fixup for valid checks below + host = host.substring(1, host.length() - 1); } if (!"http".equals(locationUrl.getProtocol())) { Debug.warning("Ignoring non-http device at " + location); return; } - if (!Addresses.isIPv4Address(host)) { + if (!Addresses.isIPv4Address(host) && + (!ALLOW_IPV6_LOCATION || !Addresses.isIPv6Address(host))) { Debug.warning("Ignoring non-IPv4 address at " + location); return; } @@ -294,7 +302,7 @@ public class ControlPoint implements HTTPRequestListener Debug.warning("Ignoring bad IP at " + location); return; } - if (TransportUtil.isPubliclyRoutable(ip, false)) { + if (TransportUtil.isPubliclyRoutable(ip, ALLOW_IPV6_LOCATION)) { Debug.warning("Ignoring public address at " + location); return; } diff --git a/router/java/src/org/cybergarage/upnp/Device.java b/router/java/src/org/cybergarage/upnp/Device.java index 08b48d874..e9f3a550a 100644 --- a/router/java/src/org/cybergarage/upnp/Device.java +++ b/router/java/src/org/cybergarage/upnp/Device.java @@ -731,9 +731,18 @@ public class Device implements org.cybergarage.http.HTTPRequestListener, } public SSDPPacket getSSDPPacket() { + return getSSDPPacket(false); + } + + /** + * I2P for multiple location support + * + * @since 0.9.50 + */ + public SSDPPacket getSSDPPacket(boolean preferIPv6) { if (isRootDevice() == false) return null; - return getDeviceData().getSSDPPacket(); + return getDeviceData().getSSDPPacket(preferIPv6); } // ////////////////////////////////////////////// @@ -745,10 +754,19 @@ public class Device implements org.cybergarage.http.HTTPRequestListener, } public String getLocation() { - SSDPPacket packet = getSSDPPacket(); + return getLocation(false); + } + + /** + * I2P for multiple location support + * + * @since 0.9.50 + */ + public String getLocation(boolean preferIPv6) { + SSDPPacket packet = getSSDPPacket(preferIPv6); if (packet != null) return packet.getLocation(); - return getDeviceData().getLocation(); + return getDeviceData().getLocation(preferIPv6); } // ////////////////////////////////////////////// diff --git a/router/java/src/org/cybergarage/upnp/control/ControlRequest.java b/router/java/src/org/cybergarage/upnp/control/ControlRequest.java index b5d519b4f..b904d1c10 100644 --- a/router/java/src/org/cybergarage/upnp/control/ControlRequest.java +++ b/router/java/src/org/cybergarage/upnp/control/ControlRequest.java @@ -50,6 +50,9 @@ import org.cybergarage.upnp.*; public class ControlRequest extends SOAPRequest { + // I2P see setRequestHost(); + private static final String WAN_IPV6_CONNECTION = "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1"; + //////////////////////////////////////////////// // Constructor //////////////////////////////////////////////// @@ -114,8 +117,13 @@ public class ControlRequest extends SOAPRequest // Thanks for Rob van den Boomen (02/17/04) // BUGFIX, set urlbase from location string if not set in description.xml - if (postURL == null || postURL.length() <= 0) - postURL = service.getRootDevice().getLocation(); + if (postURL == null || postURL.length() <= 0) { + // I2P + // if service is ipv6 service... + String type = service.getServiceType(); + boolean preferIPv6 = WAN_IPV6_CONNECTION.equals(type); + postURL = service.getRootDevice().getLocation(preferIPv6); + } String reqHost = HTTP.getHost(postURL); int reqPort = HTTP.getPort(postURL); diff --git a/router/java/src/org/cybergarage/upnp/control/QueryRequest.java b/router/java/src/org/cybergarage/upnp/control/QueryRequest.java index bd178f0f8..bcd9c21e4 100644 --- a/router/java/src/org/cybergarage/upnp/control/QueryRequest.java +++ b/router/java/src/org/cybergarage/upnp/control/QueryRequest.java @@ -74,7 +74,7 @@ public class QueryRequest extends ControlRequest { Service service = stateVar.getService(); - String ctrlURL = service.getControlURL(); + //String ctrlURL = service.getControlURL(); setRequestHost(service); diff --git a/router/java/src/org/cybergarage/upnp/xml/DeviceData.java b/router/java/src/org/cybergarage/upnp/xml/DeviceData.java index 9b8d14675..dd5ff1dba 100644 --- a/router/java/src/org/cybergarage/upnp/xml/DeviceData.java +++ b/router/java/src/org/cybergarage/upnp/xml/DeviceData.java @@ -19,6 +19,8 @@ package org.cybergarage.upnp.xml; import java.io.*; import java.net.InetAddress; +import java.net.MalformedURLException; +import java.net.URL; import org.cybergarage.util.*; import org.cybergarage.http.*; @@ -27,6 +29,11 @@ import org.cybergarage.upnp.*; import org.cybergarage.upnp.ssdp.*; import org.cybergarage.upnp.device.*; +/** + * + * I2P added multiple location support + * + */ public class DeviceData extends NodeData { public DeviceData() @@ -61,12 +68,43 @@ public class DeviceData extends NodeData //////////////////////////////////////////////// private String location = ""; + private String location_ipv6 = ""; public String getLocation() { - return location; + return getLocation(false); + } + + /** + * I2P for multiple location support + * + * @since 0.9.50 + */ + public String getLocation(boolean preferIPv6) { + if (preferIPv6) { + if (location_ipv6 != null && !location_ipv6.isEmpty()) + return location_ipv6; + return location; + } else { + if (location != null && !location.isEmpty()) + return location; + return location_ipv6; + } } public void setLocation(String location) { + if (location != null) { + try { + URL url = new URL(location); + String host = url.getHost(); + if (host != null && host.startsWith("[")) { + location_ipv6 = location; + return; + } + } catch (MalformedURLException me) { + Debug.warning("Bad location: " + location, me); + return; + } + } this.location = location; } @@ -241,12 +279,44 @@ public class DeviceData extends NodeData //////////////////////////////////////////////// private SSDPPacket ssdpPacket = null; + private SSDPPacket ssdpPacket_ipv6 = null; public SSDPPacket getSSDPPacket() { - return ssdpPacket; + return getSSDPPacket(false); + } + + /** + * I2P for multiple location support + * + * @since 0.9.50 + */ + public SSDPPacket getSSDPPacket(boolean preferIPv6) { + if (preferIPv6) { + if (ssdpPacket_ipv6 != null) + return ssdpPacket_ipv6; + return ssdpPacket; + } else { + if (ssdpPacket != null) + return ssdpPacket; + return ssdpPacket_ipv6; + } } public void setSSDPPacket(SSDPPacket packet) { + String location = packet.getLocation(); + if (location != null) { + try { + URL url = new URL(location); + String host = url.getHost(); + if (host != null && host.startsWith("[")) { + ssdpPacket_ipv6 = packet; + return; + } + } catch (MalformedURLException me) { + Debug.warning("Bad location: " + location, me); + return; + } + } ssdpPacket = packet; } diff --git a/router/java/src/org/cybergarage/xml/Parser.java b/router/java/src/org/cybergarage/xml/Parser.java index eaba31e3e..d5786266e 100644 --- a/router/java/src/org/cybergarage/xml/Parser.java +++ b/router/java/src/org/cybergarage/xml/Parser.java @@ -71,12 +71,13 @@ public abstract class Parser throw new ParserException("Not HTTP"); String host = locationURL.getHost(); if (host == null || - !Addresses.isIPv4Address(host) || host.startsWith("127.")) throw new ParserException("Bad host " + host); + if (host.startsWith("[") && host.endsWith("]")) + host = host.substring(1, host.length() - 1); byte[] ip = Addresses.getIP(host); if (ip == null || - TransportUtil.isPubliclyRoutable(ip, false)) + TransportUtil.isPubliclyRoutable(ip, true)) throw new ParserException("Bad host " + host); int port = locationURL.getPort();