Skip to content

Commit 60c07f9

Browse files
committed
Merge pull request #3 from markfalk/master
Added Multi NIC support from markfalk
2 parents 3fe2218 + acc303f commit 60c07f9

File tree

1 file changed

+98
-75
lines changed

1 file changed

+98
-75
lines changed

src/main/java/com/armzilla/ha/upnp/UpnpListener.java

Lines changed: 98 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -11,84 +11,107 @@
1111
import java.io.IOException;
1212
import java.net.*;
1313

14+
import java.util.Enumeration;
15+
import org.apache.http.conn.util.*;
16+
1417
/**
1518
* Created by arm on 4/11/15.
1619
*/
1720
@Component
1821
public class UpnpListener {
19-
private Logger log = Logger.getLogger(UpnpListener.class);
20-
private static final int UPNP_DISCOVERY_PORT = 1900;
21-
private static final String UPNP_MULTICAST_ADDRESS = "239.255.255.250";
22-
23-
@Value("${upnp.response.port}")
24-
private int upnpResponsePort;
25-
26-
@Value("${server.port}")
27-
private int httpServerPort;
28-
29-
@Value("${upnp.config.address}")
30-
private String responseAddress;
31-
32-
@Autowired
33-
private ApplicationContext applicationContext;
34-
35-
@Scheduled(fixedDelay = Integer.MAX_VALUE)
36-
public void startListening(){
37-
log.info("Starting UPNP Discovery Listener");
38-
39-
try (DatagramSocket responseSocket = new DatagramSocket(upnpResponsePort);
40-
MulticastSocket upnpMulticastSocket = new MulticastSocket(UPNP_DISCOVERY_PORT)) {
41-
42-
InetAddress upnpGroupAddress = InetAddress.getByName(UPNP_MULTICAST_ADDRESS);
43-
upnpMulticastSocket.joinGroup(upnpGroupAddress);
44-
45-
while(true){ //trigger shutdown here
46-
byte[] buf = new byte[1024];
47-
DatagramPacket packet = new DatagramPacket(buf, buf.length);
48-
upnpMulticastSocket.receive(packet);
49-
String packetString = new String(packet.getData());
50-
if(isSSDPDiscovery(packetString)){
51-
log.debug("Got SSDP Discovery packet from " + packet.getAddress().getHostAddress() + ":" + packet.getPort());
52-
sendUpnpResponse(responseSocket, packet.getAddress(), packet.getPort());
53-
}
54-
}
55-
} catch (IOException e) {
56-
log.error("UpnpListener encountered an error. Shutting down", e);
57-
ConfigurableApplicationContext context = (ConfigurableApplicationContext) UpnpListener.this.applicationContext;
58-
context.close();
59-
60-
}
61-
log.info("UPNP Discovery Listener Stopped");
62-
63-
}
64-
65-
/**
66-
* very naive ssdp discovery packet detection
67-
* @param body
68-
* @return
69-
*/
70-
protected boolean isSSDPDiscovery(String body){
71-
if(body != null && body.startsWith("M-SEARCH * HTTP/1.1") && body.contains("MAN: \"ssdp:discover\"")){
72-
return true;
73-
}
74-
return false;
75-
}
76-
77-
String discoveryTemplate = "HTTP/1.1 200 OK\r\n" +
78-
"CACHE-CONTROL: max-age=86400\r\n" +
79-
"EXT:\r\n" +
80-
"LOCATION: http://%s:%s/upnp/amazon-ha-bridge/setup.xml\r\n" +
81-
"OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n" +
82-
"01-NLS: %s\r\n" +
83-
"ST: urn:Belkin:device:**\r\n" +
84-
"USN: uuid:Socket-1_0-221438K0100073::urn:Belkin:device:**\r\n\r\n";
85-
protected void sendUpnpResponse(DatagramSocket socket, InetAddress requester, int sourcePort) throws IOException {
86-
String discoveryResponse = String.format(discoveryTemplate, responseAddress, httpServerPort, getRandomUUIDString());
87-
DatagramPacket response = new DatagramPacket(discoveryResponse.getBytes(), discoveryResponse.length(), requester, sourcePort);
88-
socket.send(response);
89-
}
90-
91-
protected String getRandomUUIDString(){
92-
return "88f6698f-2c83-4393-bd03-cd54a9f8595"; // https://xkcd.com/221/
93-
}
22+
private Logger log = Logger.getLogger(UpnpListener.class);
23+
private static final int UPNP_DISCOVERY_PORT = 1900;
24+
private static final String UPNP_MULTICAST_ADDRESS = "239.255.255.250";
25+
26+
@Value("${upnp.response.port}")
27+
private int upnpResponsePort;
28+
29+
@Value("${server.port}")
30+
private int httpServerPort;
31+
32+
@Value("${upnp.config.address}")
33+
private String responseAddress;
34+
35+
@Autowired
36+
private ApplicationContext applicationContext;
37+
38+
@Scheduled(fixedDelay = Integer.MAX_VALUE)
39+
public void startListening(){
40+
log.info("Starting UPNP Discovery Listener");
41+
42+
try (DatagramSocket responseSocket = new DatagramSocket(upnpResponsePort);
43+
MulticastSocket upnpMulticastSocket = new MulticastSocket(UPNP_DISCOVERY_PORT);) {
44+
InetSocketAddress socketAddress = new InetSocketAddress(UPNP_MULTICAST_ADDRESS, UPNP_DISCOVERY_PORT);
45+
Enumeration<NetworkInterface> ifs = NetworkInterface.getNetworkInterfaces();
46+
47+
while (ifs.hasMoreElements()) {
48+
NetworkInterface xface = ifs.nextElement();
49+
Enumeration<InetAddress> addrs = xface.getInetAddresses();
50+
String name = xface.getName();
51+
int IPsPerNic = 0;
52+
53+
while (addrs.hasMoreElements()) {
54+
InetAddress addr = addrs.nextElement();
55+
log.debug(name + " ... has addr " + addr);
56+
if (InetAddressUtils.isIPv4Address(addr.getHostAddress())) {
57+
IPsPerNic++;
58+
}
59+
}
60+
log.debug("Checking " + name + " to our interface set");
61+
if (IPsPerNic > 0) {
62+
upnpMulticastSocket.joinGroup(socketAddress, xface);
63+
log.debug("Adding " + name + " to our interface set");
64+
}
65+
}
66+
67+
while(true){ //trigger shutdown here
68+
byte[] buf = new byte[1024];
69+
DatagramPacket packet = new DatagramPacket(buf, buf.length);
70+
upnpMulticastSocket.receive(packet);
71+
String packetString = new String(packet.getData());
72+
if(isSSDPDiscovery(packetString)){
73+
log.debug("Got SSDP Discovery packet from " + packet.getAddress().getHostAddress() + ":" + packet.getPort());
74+
sendUpnpResponse(responseSocket, packet.getAddress(), packet.getPort());
75+
}
76+
}
77+
78+
} catch (IOException e) {
79+
log.error("UpnpListener encountered an error. Shutting down", e);
80+
ConfigurableApplicationContext context = (ConfigurableApplicationContext) UpnpListener.this.applicationContext;
81+
context.close();
82+
83+
}
84+
log.info("UPNP Discovery Listener Stopped");
85+
86+
}
87+
88+
/**
89+
* very naive ssdp discovery packet detection
90+
* @param body
91+
* @return
92+
*/
93+
protected boolean isSSDPDiscovery(String body){
94+
if(body != null && body.startsWith("M-SEARCH * HTTP/1.1") && body.contains("MAN: \"ssdp:discover\"")){
95+
return true;
96+
}
97+
return false;
98+
}
99+
100+
String discoveryTemplate = "HTTP/1.1 200 OK\r\n" +
101+
"CACHE-CONTROL: max-age=86400\r\n" +
102+
"EXT:\r\n" +
103+
"LOCATION: http://%s:%s/upnp/amazon-ha-bridge/setup.xml\r\n" +
104+
"OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n" +
105+
"01-NLS: %s\r\n" +
106+
"ST: urn:Belkin:device:**\r\n" +
107+
"USN: uuid:Socket-1_0-221438K0100073::urn:Belkin:device:**\r\n\r\n";
108+
protected void sendUpnpResponse(DatagramSocket socket, InetAddress requester, int sourcePort) throws IOException {
109+
String discoveryResponse = String.format(discoveryTemplate, responseAddress, httpServerPort, getRandomUUIDString());
110+
DatagramPacket response = new DatagramPacket(discoveryResponse.getBytes(), discoveryResponse.length(), requester, sourcePort);
111+
socket.send(response);
112+
}
113+
114+
protected String getRandomUUIDString(){
115+
return "88f6698f-2c83-4393-bd03-cd54a9f8595"; // https://xkcd.com/221/
116+
}
94117
}

0 commit comments

Comments
 (0)