diff --git a/router/java/src/net/i2p/router/transport/UPnP.java b/router/java/src/net/i2p/router/transport/UPnP.java index 28eb6c125..c4706ffe2 100644 --- a/router/java/src/net/i2p/router/transport/UPnP.java +++ b/router/java/src/net/i2p/router/transport/UPnP.java @@ -1634,6 +1634,9 @@ public class UPnP extends ControlPoint implements DeviceChangeListener, EventLis ": " + DataHelper.escapeHTML(device.getFriendlyName()) + ""); System.out.println("

UDN: " + DataHelper.escapeHTML(device.getUDN())); System.out.println("
IP: " + getIP(device)); + String loc = device.getLocation(); + if (loc != null && loc.length() > 0) + System.out.println("
URL: " + loc + ""); System.out.println(sb.toString()); sb.setLength(0); } diff --git a/router/java/src/org/cybergarage/upnp/ControlPoint.java b/router/java/src/org/cybergarage/upnp/ControlPoint.java index 0d8b8b62c..00638a119 100644 --- a/router/java/src/org/cybergarage/upnp/ControlPoint.java +++ b/router/java/src/org/cybergarage/upnp/ControlPoint.java @@ -64,6 +64,7 @@ package org.cybergarage.upnp; import java.net.InetAddress; import java.net.MalformedURLException; import java.net.URL; +import java.util.Locale; import org.cybergarage.http.HTTPRequest; import org.cybergarage.http.HTTPRequestListener; @@ -253,6 +254,15 @@ public class ControlPoint implements HTTPRequestListener String location = ssdpPacket.getLocation(); try { URL locationUrl = new URL(location); + // I2P + // Roku fake json port, the real UPnP port is 8060 + if (locationUrl.getPort() == 9080) { + String lcusn = usn.toLowerCase(Locale.US); + if (lcusn.contains("rku") || lcusn.contains("roku")) { + Debug.warning("Ignoring Roku at " + location); + return; + } + } Parser parser = UPnP.getXMLParser(); Node rootNode = parser.parse(locationUrl); Device rootDev = getDevice(rootNode); @@ -270,12 +280,10 @@ public class ControlPoint implements HTTPRequestListener performAddDeviceListener( rootDev ); } catch (MalformedURLException me) { - Debug.warning(ssdpPacket.toString()); - Debug.warning(me); + Debug.warning("Bad location: " + location, me); } catch (ParserException pe) { - Debug.warning(ssdpPacket.toString()); - Debug.warning(pe); + Debug.warning("Error parsing data at location: " + location, pe); } } diff --git a/router/java/src/org/cybergarage/xml/Parser.java b/router/java/src/org/cybergarage/xml/Parser.java index 8ae1d0001..404b1ba99 100644 --- a/router/java/src/org/cybergarage/xml/Parser.java +++ b/router/java/src/org/cybergarage/xml/Parser.java @@ -21,6 +21,7 @@ package org.cybergarage.xml; import java.io.File; import java.io.FileInputStream; +import java.io.IOException; import java.io.InputStream; import java.io.ByteArrayInputStream; import java.net.HttpURLConnection; @@ -29,6 +30,7 @@ import java.net.URL; import org.cybergarage.http.HTTP; import org.cybergarage.http.HTTPRequest; import org.cybergarage.http.HTTPResponse; +import org.cybergarage.util.Debug; public abstract class Parser { @@ -58,9 +60,15 @@ public abstract class Parser if (port == -1) port = 80; String uri = locationURL.getPath(); + // I2P note: Roku port 9080 now ignored in ControlPoint.addDevice() + // I2P fix - Roku + if (uri.length() <= 0) + uri = "/"; + HttpURLConnection urlCon = null; + InputStream urlIn = null; try { - HttpURLConnection urlCon = (HttpURLConnection)locationURL.openConnection(); + urlCon = (HttpURLConnection)locationURL.openConnection(); // I2P mods to prevent hangs (see HTTPRequest for more info) // this seems to work, getInputStream actually does the connect(), // (as shown by a thread dump) @@ -73,29 +81,50 @@ public abstract class Parser if (host != null) urlCon.setRequestProperty(HTTP.HOST, host); - InputStream urlIn = urlCon.getInputStream(); + // I2P fix + int code = urlCon.getResponseCode(); + if (code < 200 || code >= 300) + throw new ParserException("Bad response code " + code); + // I2P fix - Roku port 9080 + // not valid json either; returns "status=ok" + if ("application/json".equals(urlCon.getContentType())) + throw new ParserException("JSON response"); + urlIn = urlCon.getInputStream(); Node rootElem = parse(urlIn); - - urlIn.close(); - urlCon.disconnect(); return rootElem; + } catch (ParserException pe) { + throw pe; } catch (Exception e) { + // Why try twice??? //throw new ParserException(e); + Debug.warning("Failed fetch but retrying with HTTPRequest, URL: " + locationURL, e); + } finally { + if (urlIn != null) try { urlIn.close(); } catch (IOException ioe) {} + if (urlCon != null) urlCon.disconnect(); } HTTPRequest httpReq = new HTTPRequest(); httpReq.setMethod(HTTP.GET); httpReq.setURI(uri); HTTPResponse httpRes = httpReq.post(host, port); - if (httpRes.isSuccessful() == false) - throw new ParserException("HTTP comunication failed: no answer from peer." + - "Unable to retrive resoure -> "+locationURL.toString()); + if (!httpRes.isSuccessful()) + throw new ParserException("HTTP comunication failed. " + + "Unable to retrieve resource -> " + locationURL + + "\nRequest:\n" + httpReq + + "\nResponse:\n" + httpRes); String content = new String(httpRes.getContent()); ByteArrayInputStream strBuf = new ByteArrayInputStream(content.getBytes()); - return parse(strBuf); + try { + return parse(strBuf); + } catch (ParserException pe) { + Debug.warning("Parse error at resource " + locationURL + + "\nRequest:\n" + httpReq + + "\nResponse:\n" + httpRes, pe); + throw pe; + } } ////////////////////////////////////////////////