Changed SSDPClient to use multicast and listen to the network
This commit is contained in:
parent
868364a0ca
commit
37c1809a61
7 changed files with 120 additions and 59 deletions
|
|
@ -31,6 +31,7 @@ import java.util.Iterator;
|
|||
|
||||
public class HttpHeader {
|
||||
// HTTP info
|
||||
private boolean request;
|
||||
private String type;
|
||||
private String url;
|
||||
private HashMap<String, String> urlAttributes;
|
||||
|
|
@ -49,6 +50,18 @@ public class HttpHeader {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return true if this header represents a server response
|
||||
*/
|
||||
public boolean isResponse(){
|
||||
return !request;
|
||||
}
|
||||
/**
|
||||
* @return true if this header represents a client request
|
||||
*/
|
||||
public boolean isRequest(){
|
||||
return request;
|
||||
}
|
||||
/**
|
||||
* @return the HTTP message type( ex. GET,POST...)
|
||||
*/
|
||||
|
|
@ -117,13 +130,7 @@ public class HttpHeader {
|
|||
}
|
||||
|
||||
|
||||
protected HashMap<String,String> getCookieMap(){
|
||||
return cookies;
|
||||
}
|
||||
protected HashMap<String,String> getUrlAttributeMap(){
|
||||
return urlAttributes;
|
||||
}
|
||||
|
||||
protected void setIsRequest(boolean request) { this.request = request; }
|
||||
protected void setRequestType(String type){
|
||||
this.type = type.trim();
|
||||
}
|
||||
|
|
@ -146,6 +153,13 @@ public class HttpHeader {
|
|||
headers.put(key.trim(), value.trim());
|
||||
}
|
||||
|
||||
protected HashMap<String,String> getCookieMap(){
|
||||
return cookies;
|
||||
}
|
||||
protected HashMap<String,String> getUrlAttributeMap(){
|
||||
return urlAttributes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public String toString(){
|
||||
|
|
|
|||
|
|
@ -87,11 +87,13 @@ public class HttpHeaderParser {
|
|||
protected static void parseStatusLine(HttpHeader header, String line){
|
||||
// Server Response
|
||||
if( line.startsWith("HTTP/") ){
|
||||
header.setIsRequest(false);
|
||||
header.setHTTPVersion( Float.parseFloat( line.substring( 5 , 8)));
|
||||
header.setHTTPCode( Integer.parseInt( line.substring( 9, 12 )));
|
||||
}
|
||||
// Client Request
|
||||
else if(line.contains("HTTP/")){
|
||||
header.setIsRequest(true);
|
||||
header.setRequestType( line.substring(0, line.indexOf(" ")));
|
||||
header.setHTTPVersion( Float.parseFloat( line.substring(line.lastIndexOf("HTTP/")+5 , line.length()).trim()));
|
||||
line = (line.substring(header.getRequestType().length()+1, line.lastIndexOf("HTTP/")));
|
||||
|
|
|
|||
|
|
@ -208,9 +208,9 @@ public class HttpPrintStream extends OutputStream{
|
|||
else{
|
||||
if(res_status_code != null){
|
||||
if( message_type==HttpMessageType.REQUEST )
|
||||
out.print(req_type + " " + req_url + " HTTP/1.0");
|
||||
out.print(req_type + " " + req_url + " HTTP/1.1");
|
||||
else
|
||||
out.print("HTTP/1.0 " + res_status_code + " " + getStatusString(res_status_code));
|
||||
out.print("HTTP/1.1 " + res_status_code + " " + getStatusString(res_status_code));
|
||||
out.println();
|
||||
res_status_code = null;
|
||||
req_type = null;
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@
|
|||
|
||||
package zutil.net.ssdp;
|
||||
|
||||
import zutil.io.StringOutputStream;
|
||||
import zutil.log.LogUtil;
|
||||
import zutil.net.http.HttpHeader;
|
||||
import zutil.net.http.HttpHeaderParser;
|
||||
|
|
@ -32,6 +31,7 @@ import zutil.net.http.HttpPrintStream;
|
|||
import zutil.net.threaded.ThreadedUDPNetwork;
|
||||
import zutil.net.threaded.ThreadedUDPNetworkThread;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.DatagramPacket;
|
||||
import java.net.InetAddress;
|
||||
|
|
@ -40,6 +40,9 @@ import java.util.LinkedList;
|
|||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import static zutil.net.ssdp.SSDPServer.SSDP_MULTICAST_ADDR;
|
||||
import static zutil.net.ssdp.SSDPServer.SSDP_PORT;
|
||||
|
||||
/**
|
||||
* An SSDP client class that will request
|
||||
* service information.
|
||||
|
|
@ -48,6 +51,7 @@ import java.util.logging.Logger;
|
|||
*/
|
||||
public class SSDPClient extends ThreadedUDPNetwork implements ThreadedUDPNetworkThread{
|
||||
private static final Logger logger = LogUtil.getLogger();
|
||||
public static final String USER_AGENT = "Zutil SSDP Client";
|
||||
/** Mapping of search targets and list of associated services **/
|
||||
private HashMap<String, LinkedList<StandardSSDPInfo>> services_st;
|
||||
/** Map of all unique services received **/
|
||||
|
|
@ -63,6 +67,7 @@ public class SSDPClient extends ThreadedUDPNetwork implements ThreadedUDPNetwork
|
|||
* @throws IOException
|
||||
*/
|
||||
public SSDPClient() throws IOException{
|
||||
super( SSDP_MULTICAST_ADDR, SSDP_PORT );
|
||||
super.setThread(this);
|
||||
|
||||
services_st = new HashMap<>();
|
||||
|
|
@ -88,14 +93,15 @@ public class SSDPClient extends ThreadedUDPNetwork implements ThreadedUDPNetwork
|
|||
public void requestService(String searchTarget, HashMap<String,String> headers){
|
||||
try {
|
||||
// Generate an SSDP discover message
|
||||
StringOutputStream msg = new StringOutputStream();
|
||||
HttpPrintStream http = new HttpPrintStream( msg, HttpPrintStream.HttpMessageType.REQUEST );
|
||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||
HttpPrintStream http = new HttpPrintStream( buffer, HttpPrintStream.HttpMessageType.REQUEST );
|
||||
http.setRequestType("M-SEARCH");
|
||||
http.setRequestURL("*");
|
||||
http.setHeader("Host", SSDPServer.SSDP_MULTICAST_ADDR +":"+ SSDPServer.SSDP_PORT );
|
||||
http.setHeader("Host", SSDP_MULTICAST_ADDR +":"+ SSDP_PORT );
|
||||
http.setHeader("ST", searchTarget );
|
||||
http.setHeader("Man", "\"ssdp:discover\"" );
|
||||
http.setHeader("MX", "3" );
|
||||
http.setHeader("USER-AGENT", USER_AGENT );
|
||||
if(headers != null) {
|
||||
for (String key : headers.keySet()) {
|
||||
http.setHeader(key, headers.get(key));
|
||||
|
|
@ -104,11 +110,12 @@ public class SSDPClient extends ThreadedUDPNetwork implements ThreadedUDPNetwork
|
|||
logger.log(Level.FINEST, "Sending Multicast: "+ http);
|
||||
http.flush();
|
||||
|
||||
byte[] data = msg.toString().getBytes();
|
||||
byte[] data = buffer.toByteArray();
|
||||
//System.out.println(new String(data)+"****************");
|
||||
DatagramPacket packet = new DatagramPacket(
|
||||
data, data.length,
|
||||
InetAddress.getByName( SSDPServer.SSDP_MULTICAST_ADDR ),
|
||||
SSDPServer.SSDP_PORT );
|
||||
InetAddress.getByName( SSDP_MULTICAST_ADDR ),
|
||||
SSDP_PORT );
|
||||
super.send( packet );
|
||||
http.close();
|
||||
} catch (Exception e) {
|
||||
|
|
@ -193,18 +200,33 @@ public class SSDPClient extends ThreadedUDPNetwork implements ThreadedUDPNetwork
|
|||
String msg = new String(packet.getData(), packet.getOffset(), packet.getLength());
|
||||
HttpHeaderParser headerParser = new HttpHeaderParser(msg);
|
||||
HttpHeader header = headerParser.read();
|
||||
logger.log(Level.FINEST, "Received(from: " + packet.getAddress() + "): " + header);
|
||||
|
||||
String usn = header.getHeader("USN");
|
||||
String st = header.getHeader("ST");
|
||||
boolean newService = false;
|
||||
StandardSSDPInfo service;
|
||||
StandardSSDPInfo service = null;
|
||||
// Get existing service
|
||||
if (services_usn.containsKey(usn)) {
|
||||
service = services_usn.get(usn);
|
||||
}
|
||||
|
||||
// Remove service
|
||||
if ("NOTIFY".equals(header.getRequestType()) && "ssdp:byebye".equalsIgnoreCase(header.getHeader("NTS"))){
|
||||
logger.log(Level.FINER, "Received NOTIFY:byebye (from: " + packet.getAddress() + "): " + header);
|
||||
if (service != null) {
|
||||
services_usn.remove(usn);
|
||||
if (services_st.containsKey(st))
|
||||
services_st.get(st).remove(service);
|
||||
if (listener != null)
|
||||
listener.serviceLost(service);
|
||||
}
|
||||
}
|
||||
// Existing or new service update
|
||||
else if (header.isResponse() || "NOTIFY".equals(header.getRequestType())) {
|
||||
logger.log(Level.FINER, "Received service update (from: " + packet.getAddress() + "): " + header);
|
||||
boolean newService = false;
|
||||
|
||||
// Add new service
|
||||
else {
|
||||
if (service == null){
|
||||
newService = true;
|
||||
service = new StandardSSDPInfo();
|
||||
services_usn.put(usn, service);
|
||||
|
|
@ -224,7 +246,11 @@ public class SSDPClient extends ThreadedUDPNetwork implements ThreadedUDPNetwork
|
|||
service.readHeaders(header);
|
||||
|
||||
if (listener != null && newService)
|
||||
listener.newService(service);
|
||||
listener.serviceDiscovered(service);
|
||||
}
|
||||
else {
|
||||
logger.log(Level.FINEST, "Ignored (from: " + packet.getAddress() + "): " + header);
|
||||
}
|
||||
} catch (IOException e){
|
||||
logger.log(Level.SEVERE, null, e);
|
||||
}
|
||||
|
|
@ -243,6 +269,14 @@ public class SSDPClient extends ThreadedUDPNetwork implements ThreadedUDPNetwork
|
|||
}
|
||||
|
||||
public interface SSDPServiceListener{
|
||||
public void newService(StandardSSDPInfo service);
|
||||
/**
|
||||
* Is called when a new service is discovered. Will only be called once per service.
|
||||
*/
|
||||
void serviceDiscovered(StandardSSDPInfo service);
|
||||
|
||||
/**
|
||||
* Is called when a service goes down and is not available anymore.
|
||||
*/
|
||||
void serviceLost(StandardSSDPInfo service);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ import zutil.net.http.HttpPrintStream;
|
|||
import zutil.net.threaded.ThreadedUDPNetwork;
|
||||
import zutil.net.threaded.ThreadedUDPNetworkThread;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.DatagramPacket;
|
||||
import java.net.InetAddress;
|
||||
|
|
@ -68,9 +69,8 @@ import java.util.logging.Logger;
|
|||
*/
|
||||
public class SSDPServer extends ThreadedUDPNetwork implements ThreadedUDPNetworkThread{
|
||||
private static final Logger logger = LogUtil.getLogger();
|
||||
public static final String SERVER_INFO = "Zutil SSDP Java Server";
|
||||
public static final String SERVER_INFO = "Zutil SSDP Server";
|
||||
public static final int DEFAULT_CACHE_TIME = 60*30; // 30 min
|
||||
public static final int BUFFER_SIZE = 512;
|
||||
public static final String SSDP_MULTICAST_ADDR = "239.255.255.250";
|
||||
public static final int SSDP_PORT = 1900;
|
||||
|
||||
|
|
@ -186,8 +186,8 @@ public class SSDPServer extends ThreadedUDPNetwork implements ThreadedUDPNetwork
|
|||
logger.log(Level.FINEST, "Received Multicast(from: "+packet.getAddress()+"): "+ header);
|
||||
|
||||
// Generate the SSDP response
|
||||
StringOutputStream response = new StringOutputStream();
|
||||
HttpPrintStream http = new HttpPrintStream( response );
|
||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||
HttpPrintStream http = new HttpPrintStream( buffer );
|
||||
http.setStatusCode(200);
|
||||
http.setHeader("Location", services.get(st).getLocation() );
|
||||
http.setHeader("USN", services.get(st).getUSN() );
|
||||
|
|
@ -200,8 +200,7 @@ public class SSDPServer extends ThreadedUDPNetwork implements ThreadedUDPNetwork
|
|||
logger.log(Level.FINEST, "Sending Response: "+ http);
|
||||
http.flush();
|
||||
|
||||
String strData = response.toString();
|
||||
byte[] data = strData.getBytes();
|
||||
byte[] data = buffer.toByteArray();
|
||||
packet = new DatagramPacket(
|
||||
data, data.length,
|
||||
packet.getAddress(),
|
||||
|
|
@ -255,8 +254,8 @@ public class SSDPServer extends ThreadedUDPNetwork implements ThreadedUDPNetwork
|
|||
try {
|
||||
SSDPServiceInfo service = services.get(searchTarget);
|
||||
// Generate the SSDP response
|
||||
StringOutputStream msg = new StringOutputStream();
|
||||
HttpPrintStream http = new HttpPrintStream( msg, HttpPrintStream.HttpMessageType.REQUEST );
|
||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||
HttpPrintStream http = new HttpPrintStream( buffer, HttpPrintStream.HttpMessageType.REQUEST );
|
||||
http.setRequestType("NOTIFY");
|
||||
http.setRequestURL("*");
|
||||
http.setHeader("Server", SERVER_INFO );
|
||||
|
|
@ -271,7 +270,7 @@ public class SSDPServer extends ThreadedUDPNetwork implements ThreadedUDPNetwork
|
|||
logger.log(Level.FINEST, "Sending Notification: " + http);
|
||||
http.flush();
|
||||
|
||||
byte[] data = msg.toString().getBytes();
|
||||
byte[] data = buffer.toByteArray();
|
||||
DatagramPacket packet = new DatagramPacket(
|
||||
data, data.length,
|
||||
InetAddress.getByName( SSDP_MULTICAST_ADDR ),
|
||||
|
|
@ -309,8 +308,8 @@ public class SSDPServer extends ThreadedUDPNetwork implements ThreadedUDPNetwork
|
|||
public void sendByeBye(String searchTarget){
|
||||
try {
|
||||
// Generate the SSDP response
|
||||
StringOutputStream msg = new StringOutputStream();
|
||||
HttpPrintStream http = new HttpPrintStream( msg, HttpPrintStream.HttpMessageType.REQUEST );
|
||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||
HttpPrintStream http = new HttpPrintStream( buffer, HttpPrintStream.HttpMessageType.REQUEST );
|
||||
http.setRequestType("NOTIFY");
|
||||
http.setRequestURL("*");
|
||||
http.setHeader("Server", SERVER_INFO );
|
||||
|
|
@ -321,7 +320,7 @@ public class SSDPServer extends ThreadedUDPNetwork implements ThreadedUDPNetwork
|
|||
logger.log(Level.FINEST, "Sending ByeBye: " + http);
|
||||
http.flush();
|
||||
|
||||
byte[] data = msg.toString().getBytes();
|
||||
byte[] data = buffer.toByteArray();
|
||||
DatagramPacket packet = new DatagramPacket(
|
||||
data, data.length,
|
||||
InetAddress.getByName( SSDP_MULTICAST_ADDR ),
|
||||
|
|
|
|||
|
|
@ -95,7 +95,8 @@ public class SOAPHttpPage implements HttpPage{
|
|||
/**
|
||||
* Enables session support, if enabled then a new instance
|
||||
* of the SOAPInterface will be created, if disabled then
|
||||
* only the given object will be used as an static interface
|
||||
* only the given object will be used as an static interface.
|
||||
* Default is false.
|
||||
*
|
||||
* @param enabled is if session should be enabled
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -41,12 +41,23 @@ public class SSDPClientTest {
|
|||
LogUtil.setGlobalLevel(Level.FINEST);
|
||||
SSDPClient ssdp = new SSDPClient();
|
||||
ssdp.requestService("upnp:rootdevice");
|
||||
ssdp.requestService("urn:schemas-wifialliance-org:device:WFADevice:1");
|
||||
ssdp.requestService("urn:dial-multiscreen-org:service:dial:1"); // Chromecast
|
||||
ssdp.requestService("urn:schemas-upnp-org:device:InternetGatewayDevice:1"); // Routers
|
||||
ssdp.start();
|
||||
|
||||
for(int i=0; true ;++i){
|
||||
while( i==ssdp.getServicesCount("upnp:rootdevice") ){ try{Thread.sleep(100);}catch(Exception e){} }
|
||||
System.out.println("************************" );
|
||||
System.out.println("" + ssdp.getServices("upnp:rootdevice").get(i));
|
||||
}
|
||||
ssdp.setListener(new SSDPClient.SSDPServiceListener() {
|
||||
@Override
|
||||
public void serviceDiscovered(StandardSSDPInfo service) {
|
||||
System.out.println("*********** DISCOVERY *************" );
|
||||
System.out.println("" + service);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serviceLost(StandardSSDPInfo service) {
|
||||
System.out.println("*********** LOST *************" );
|
||||
System.out.println("" + service);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue