From aed8ffa8d3af017f607cb20c2a8c6d0b586b222b Mon Sep 17 00:00:00 2001 From: BWS Systems Date: Mon, 1 Jul 2019 15:47:23 -0500 Subject: [PATCH] Remove extra SEARCH response, use upnp original for udp send change --- pom.xml | 7 +- .../HABridge/upnp/UpnpListener.java | 197 ++++++++++++------ 2 files changed, 134 insertions(+), 70 deletions(-) diff --git a/pom.xml b/pom.xml index 03650f9..cce4885 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.bwssystems.HABridge ha-bridge - 5.3.0RC8 + 5.3.0RC9 jar HA Bridge @@ -134,6 +134,11 @@ commons-lang3 3.5 + + org.jmdns + jmdns + 3.5.5 + diff --git a/src/main/java/com/bwssystems/HABridge/upnp/UpnpListener.java b/src/main/java/com/bwssystems/HABridge/upnp/UpnpListener.java index 8167f1c..f7f331a 100644 --- a/src/main/java/com/bwssystems/HABridge/upnp/UpnpListener.java +++ b/src/main/java/com/bwssystems/HABridge/upnp/UpnpListener.java @@ -15,10 +15,14 @@ import java.net.*; import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.Enumeration; + import org.apache.http.conn.util.*; +import javax.jmdns.JmDNS; +import javax.jmdns.ServiceInfo; public class UpnpListener { private Logger log = LoggerFactory.getLogger(UpnpListener.class); + private UDPDatagramSender theUDPDatagramSender; private MulticastSocket upnpMulticastSocket; private int httpServerPort; private String upnpConfigIP; @@ -31,41 +35,67 @@ public class UpnpListener { private String bridgeSNUUID; private HuePublicConfig aHueConfig; private Integer theUpnpSendDelay; - private String responseTemplateOriginal = "HTTP/1.1 200 OK\r\n" + "CACHE-CONTROL: max-age=86400\r\n" + "EXT:\r\n" - + "LOCATION: http://%s:%s/description.xml\r\n" + "SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/" - + HueConstants.API_VERSION + "\r\n" + "ST: urn:schemas-upnp-org:device:basic:1\r\n" + "USN: uuid:" - + HueConstants.UUID_PREFIX + "%s::urn:schemas-upnp-org:device:basic:1\r\n\r\n"; - private String responseTemplate1 = "HTTP/1.1 200 OK\r\n" + "HOST: %s:%s\r\n" + "CACHE-CONTROL: max-age=100\r\n" - + "EXT:\r\n" + "LOCATION: http://%s:%s/description.xml\r\n" + "SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/" - + HueConstants.API_VERSION + "\r\n" + "HUE-BRIDGEID: %s\r\n" + "ST: upnp:rootdevice\r\n" + "USN: uuid:" - + HueConstants.UUID_PREFIX + "%s::upnp:rootdevice\r\n\r\n"; - private String responseTemplate2 = "HTTP/1.1 200 OK\r\n" + "HOST: %s:%s\r\n" + "CACHE-CONTROL: max-age=100\r\n" - + "EXT:\r\n" + "LOCATION: http://%s:%s/description.xml\r\n" + "SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/" - + HueConstants.API_VERSION + "\r\n" + "HUE-BRIDGEID: %s\r\n" + "ST: uuid:" + HueConstants.UUID_PREFIX - + "%s\r\n" + "USN: uuid:" + HueConstants.UUID_PREFIX + "%s\r\n\r\n"; - private String responseTemplate3 = "HTTP/1.1 200 OK\r\n" + "HOST: %s:%s\r\n" + "CACHE-CONTROL: max-age=100\r\n" - + "EXT:\r\n" + "LOCATION: http://%s:%s/description.xml\r\n" + "SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/" - + HueConstants.API_VERSION + "\r\n" + "HUE-BRIDGEID: %s\r\n" + "ST: urn:schemas-upnp-org:device:basic:1\r\n" - + "USN: uuid:" + HueConstants.UUID_PREFIX + "%s\r\n\r\n"; + private String responseTemplate1 = "HTTP/1.1 200 OK\r\n" + + "HOST: %s:%s\r\n" + + "CACHE-CONTROL: max-age=100\r\n" + + "EXT:\r\n" + + "LOCATION: http://%s:%s/description.xml\r\n" + + "SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/" + HueConstants.API_VERSION + "\r\n" + + "HUE-BRIDGEID: %s\r\n" + + "ST: upnp:rootdevice\r\n" + + "USN: uuid:" + HueConstants.UUID_PREFIX + "%s::upnp:rootdevice\r\n\r\n"; + private String responseTemplate2 = "HTTP/1.1 200 OK\r\n" + + "HOST: %s:%s\r\n" + + "CACHE-CONTROL: max-age=100\r\n" + + "EXT:\r\n" + + "LOCATION: http://%s:%s/description.xml\r\n" + + "SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/" + HueConstants.API_VERSION + "\r\n" + + "HUE-BRIDGEID: %s\r\n" + + "ST: uuid:" + HueConstants.UUID_PREFIX + "%s\r\n" + + "USN: uuid:" + HueConstants.UUID_PREFIX + "%s\r\n\r\n"; + private String responseTemplate3 = "HTTP/1.1 200 OK\r\n" + + "HOST: %s:%s\r\n" + + "CACHE-CONTROL: max-age=100\r\n" + + "EXT:\r\n" + + "LOCATION: http://%s:%s/description.xml\r\n" + + "SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/" + HueConstants.API_VERSION + "\r\n" + + "HUE-BRIDGEID: %s\r\n" + + "ST: urn:schemas-upnp-org:device:basic:1\r\n" + + "USN: uuid:" + HueConstants.UUID_PREFIX + "%s\r\n\r\n"; - private String notifyTemplate = "NOTIFY * HTTP/1.1\r\n" + "HOST: %s:%s\r\n" + "CACHE-CONTROL: max-age=100\r\n" - + "LOCATION: http://%s:%s/description.xml\r\n" + "SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/" - + HueConstants.API_VERSION + "\r\n" + "NTS: ssdp:alive\r\n" + "HUE-BRIDGEID: %s\r\n" + "NT: uuid:" - + HueConstants.UUID_PREFIX + "%s\r\n" + "USN: uuid:" + HueConstants.UUID_PREFIX + "%s\r\n\r\n"; + private String notifyTemplate = "NOTIFY * HTTP/1.1\r\n" + + "HOST: %s:%s\r\n" + + "CACHE-CONTROL: max-age=100\r\n" + + "LOCATION: http://%s:%s/description.xml\r\n" + + "SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/" + HueConstants.API_VERSION + "\r\n" + + "NTS: ssdp:alive\r\n" + + "HUE-BRIDGEID: %s\r\n" + + "NT: uuid:" + HueConstants.UUID_PREFIX + "%s\r\n" + + "USN: uuid:" + HueConstants.UUID_PREFIX + "%s\r\n\r\n"; - private String notifyTemplate2 = "NOTIFY * HTTP/1.1\r\n" + "HOST: %s:%s\r\n" + "CACHE-CONTROL: max-age=100\r\n" - + "LOCATION: http://%s:%s/description.xml\r\n" + "SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/" - + HueConstants.API_VERSION + "\r\n" + "NTS: ssdp:alive\r\n" + "HUE-BRIDGEID: %s\r\n" - + "NT: upnp:rootdevice\r\n" + "USN: uuid:" + HueConstants.UUID_PREFIX + "%s::upnp:rootdevice\r\n\r\n"; + private String notifyTemplate2 = "NOTIFY * HTTP/1.1\r\n" + + "HOST: %s:%s\r\n" + + "CACHE-CONTROL: max-age=100\r\n" + + "LOCATION: http://%s:%s/description.xml\r\n" + + "SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/" + HueConstants.API_VERSION + "\r\n" + + "NTS: ssdp:alive\r\n" + "HUE-BRIDGEID: %s\r\n" + + "NT: upnp:rootdevice\r\n" + + "USN: uuid:" + HueConstants.UUID_PREFIX + "%s::upnp:rootdevice\r\n\r\n"; - private String notifyTemplate3 = "NOTIFY * HTTP/1.1\r\n" + "HOST: %s:%s\r\n" + "CACHE-CONTROL: max-age=100\r\n" - + "LOCATION: http://%s:%s/description.xml\r\n" + "SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/" - + HueConstants.API_VERSION + "\r\n" + "NTS: ssdp:alive\r\n" + "HUE-BRIDGEID: %s\r\n" - + "NT: urn:schemas-upnp-org:device:basic:1\r\n" + "USN: uuid:" + HueConstants.UUID_PREFIX + "%s\r\n\r\n"; + private String notifyTemplate3 = "NOTIFY * HTTP/1.1\r\n" + + "HOST: %s:%s\r\n" + + "CACHE-CONTROL: max-age=100\r\n" + + "LOCATION: http://%s:%s/description.xml\r\n" + + "SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/" + HueConstants.API_VERSION + "\r\n" + + "NTS: ssdp:alive\r\n" + + "HUE-BRIDGEID: %s\r\n" + + "NT: urn:schemas-upnp-org:device:basic:1\r\n" + + "USN: uuid:" + HueConstants.UUID_PREFIX + "%s\r\n\r\n"; public UpnpListener(BridgeSettingsDescriptor theSettings, BridgeControlDescriptor theControl, UDPDatagramSender aUdpDatagramSender) throws IOException { super(); + theUDPDatagramSender = aUdpDatagramSender; upnpMulticastSocket = null; httpServerPort = Integer.valueOf(theSettings.getServerPort()); upnpConfigIP = theSettings.getUpnpConfigAddress(); @@ -106,6 +136,7 @@ public class UpnpListener { return false; } + InetAddress theUpnpAddress = null; while (ifs.hasMoreElements()) { NetworkInterface xface = ifs.nextElement(); Enumeration addrs = xface.getInetAddresses(); @@ -126,6 +157,10 @@ public class UpnpListener { + addr); IPsPerNic++; } + + if (addr.getHostAddress().equals(upnpConfigIP)) { + theUpnpAddress = addr; + } } } log.debug("Checking " + name + " to our interface set"); @@ -143,6 +178,22 @@ public class UpnpListener { } } + JmDNS jmdns = null; + if (theUpnpAddress != null) { + log.info("Create and run mDNS service."); + try { + // Create a JmDNS instance + jmdns = JmDNS.create(theUpnpAddress); + + // Register a service - Defined TXT keys: bridgeid, modelid + ServiceInfo serviceInfo = ServiceInfo.create("_hue._tcp.local.", "hue", httpServerPort, "modelid=" + HueConstants.MODEL_ID + "\" \"bridgeid=" + bridgeId); + jmdns.registerService(serviceInfo); + + } catch (IOException e) { + log.warn("Could not start mDNS service for hue api. {}", e.getMessage()); + } + } + log.info("UPNP Discovery Listener running and ready...."); boolean loopControl = true; boolean error = false; @@ -167,15 +218,28 @@ public class UpnpListener { log.debug("UpnpListener send upnp exception: ", e); } } - +/* current = Instant.now(); if (ChronoUnit.MILLIS.between(previous, current) > Configuration.UPNP_NOTIFY_TIMEOUT) { - sendUpnpNotify(socketAddress.getAddress()); + try { + sendUpnpNotify(socketAddress.getAddress()); + } catch (IOException e) { + log.warn("UpnpListener encountered an error sending upnp notify packets. IP: " + + packet.getAddress().getHostAddress() + " with message: " + e.getMessage()); + log.debug("UpnpListener send upnp notify exception: ", e); + } previous = Instant.now(); - } + } +*/ } catch (SocketTimeoutException e) { - sendUpnpNotify(socketAddress.getAddress()); + try { + sendUpnpNotify(socketAddress.getAddress()); + } catch (IOException en) { + log.warn("UpnpListener encountered an error sending upnp notify packets. IP: " + + packet.getAddress().getHostAddress() + " with message: " + en.getMessage()); + log.debug("UpnpListener send upnp notify exception: ", en); + } } catch (IOException e) { log.error("UpnpListener encountered an error reading socket. Shutting down", e); error = true; @@ -190,6 +254,10 @@ public class UpnpListener { } } upnpMulticastSocket.close(); + if(jmdns != null) { + // Unregister all services + jmdns.unregisterAllServices(); + } if (bridgeControl.isReinit()) log.info("UPNP Discovery Listener - ended, restart found"); if (bridgeControl.isStop()) @@ -209,8 +277,9 @@ public class UpnpListener { String packetString = new String(packet.getData(), 0, packet.getLength()); if (packetString != null && packetString.startsWith("M-SEARCH * HTTP/1.1") && packetString.contains("\"ssdp:discover\"")) { - if ((packetString.contains("ST: urn:schemas-upnp-org:device:basic:1") - || packetString.contains("ST: upnp:rootdevice") || packetString.contains("ST: ssdp:all"))) { + if ((packetString.contains("ST: urn:schemas-upnp-org:device:basic:1") || + packetString.contains("ST: upnp:rootdevice") || + packetString.contains("ST: ssdp:all"))) { if (traceupnp) { log.info("Traceupnp: SSDP M-SEARCH packet from " + packet.getAddress().getHostAddress() + ":" + packet.getPort()); @@ -248,31 +317,6 @@ public class UpnpListener { // noop } - if (upnpOriginal) { - discoveryResponse = String.format(responseTemplateOriginal, Configuration.UPNP_MULTICAST_ADDRESS, - Configuration.UPNP_DISCOVERY_PORT, httpLocationAddress, httpServerPort, bridgeId, bridgeSNUUID); - if (traceupnp) { - log.info("Traceupnp: send upnp discovery template Original with response address: " - + httpLocationAddress + ":" + httpServerPort + " to address: " + requester + ":" + sourcePort); - } - log.debug("sendUpnpResponse to address: " + requester + ":" + sourcePort - + " with discovery responseTemplateOriginal is <<<" + discoveryResponse + ">>>"); - sendUDPResponse(discoveryResponse.getBytes(), requester, sourcePort); - } else { - discoveryResponse = String.format(responseTemplateOriginal, Configuration.UPNP_MULTICAST_ADDRESS, - Configuration.UPNP_DISCOVERY_PORT, httpLocationAddress, httpServerPort, bridgeId, bridgeSNUUID); - if (traceupnp) { - log.info("Traceupnp: send upnp discovery template Original with response address: " - + httpLocationAddress + ":" + httpServerPort + " to address: " + requester + ":" + sourcePort); - } - log.debug("sendUpnpResponse to address: " + requester + ":" + sourcePort - + " with discovery responseTemplateOriginal is <<<" + discoveryResponse + ">>>"); - sendUDPResponse(discoveryResponse.getBytes(), requester, sourcePort); - try { - Thread.sleep(theUpnpSendDelay); - } catch (InterruptedException e) { - // noop - } discoveryResponse = String.format(responseTemplate1, Configuration.UPNP_MULTICAST_ADDRESS, Configuration.UPNP_DISCOVERY_PORT, httpLocationAddress, httpServerPort, bridgeId, bridgeSNUUID); if (traceupnp) { @@ -313,18 +357,21 @@ public class UpnpListener { log.debug("sendUpnpResponse to address: " + requester + ":" + sourcePort + " discovery responseTemplate3 is <<<" + discoveryResponse + ">>>"); sendUDPResponse(discoveryResponse.getBytes(), requester, sourcePort); - } } private void sendUDPResponse(byte[] udpMessage, InetAddress requester, int sourcePort) throws IOException { log.debug("Sending response string: <<<" + new String(udpMessage) + ">>>"); - if (upnpMulticastSocket == null) - throw new IOException("Socket not initialized"); - DatagramPacket response = new DatagramPacket(udpMessage, udpMessage.length, requester, sourcePort); - upnpMulticastSocket.send(response); + if(upnpOriginal) { + theUDPDatagramSender.sendUDPResponse(udpMessage, requester, sourcePort); + } else { + if (upnpMulticastSocket == null) + throw new IOException("Socket not initialized"); + DatagramPacket response = new DatagramPacket(udpMessage, udpMessage.length, requester, sourcePort); + upnpMulticastSocket.send(response); + } } - protected void sendUpnpNotify(InetAddress aSocketAddress) { + protected void sendUpnpNotify(InetAddress aSocketAddress) throws IOException { String notifyData = null; try { Thread.sleep(theUpnpSendDelay); @@ -334,7 +381,11 @@ public class UpnpListener { notifyData = String.format(notifyTemplate, Configuration.UPNP_MULTICAST_ADDRESS, Configuration.UPNP_DISCOVERY_PORT, upnpConfigIP, httpServerPort, bridgeId, bridgeSNUUID, bridgeSNUUID); - sendNotifyDatagram(notifyData, aSocketAddress, "notifyTemplate1"); + if (traceupnp) { + log.info("Traceupnp: sendUpnpNotify notifyTemplate1"); + } + log.debug("sendUpnpNotify notifyTemplate1 is <<<{}>>>", notifyData); + sendUDPResponse(notifyData.getBytes(), aSocketAddress, Configuration.UPNP_DISCOVERY_PORT); try { Thread.sleep(theUpnpSendDelay); @@ -344,8 +395,12 @@ public class UpnpListener { notifyData = String.format(notifyTemplate2, Configuration.UPNP_MULTICAST_ADDRESS, Configuration.UPNP_DISCOVERY_PORT, upnpConfigIP, httpServerPort, bridgeId, bridgeSNUUID); - sendNotifyDatagram(notifyData, aSocketAddress, "notifyTemplate2"); - + if (traceupnp) { + log.info("Traceupnp: sendUpnpNotify notifyTemplate2"); + } + log.debug("sendUpnpNotify notifyTemplate2 is <<<{}>>>", notifyData); + sendUDPResponse(notifyData.getBytes(), aSocketAddress, Configuration.UPNP_DISCOVERY_PORT); + try { Thread.sleep(theUpnpSendDelay); } catch (InterruptedException e) { @@ -354,7 +409,11 @@ public class UpnpListener { notifyData = String.format(notifyTemplate3, Configuration.UPNP_MULTICAST_ADDRESS, Configuration.UPNP_DISCOVERY_PORT, upnpConfigIP, httpServerPort, bridgeId, bridgeSNUUID); - sendNotifyDatagram(notifyData, aSocketAddress, "notifyTemplate3"); + if (traceupnp) { + log.info("Traceupnp: sendUpnpNotify notifyTemplate3"); + } + log.debug("sendUpnpNotify notifyTemplate3 is <<<{}>>>", notifyData); + sendUDPResponse(notifyData.getBytes(), aSocketAddress, Configuration.UPNP_DISCOVERY_PORT); } public void sendNotifyDatagram(String notifyData, InetAddress aSocketAddress, String templateNumber) {