org.cybergarage.upnp.ControlPoint Maven / Gradle / Ivy
/******************************************************************
*
* CyberUPnP for Java
*
* Copyright (C) Satoshi Konno 2002-2004
*
* File: ControlPoint.java
*
* Revision:
*
* 11/18/02
* - first revision.
* 05/13/03
* - Changed to create socket threads each local interfaces.
* (HTTP, SSDPNotiry, SSDPSerachResponse)
* 05/28/03
* - Changed to send m-serach packets from SSDPSearchResponseSocket.
* The socket doesn't bind interface address.
* - SSDPSearchResponsSocketList that binds a port and a interface can't
* send m-serch packets of IPv6 on J2SE v 1.4.1_02 and Redhat 9.
* 07/23/03
* - Suzan Foster (suislief)
* - Fixed a bug. HOST field was missing.
* 07/29/03
* - Synchronized when a device is added by the ssdp message.
* 09/08/03
* - Giordano Sassaroli
* - Problem : when an event notification message is received and the message
* contains updates on more than one variable, only the first variable update
* is notified.
* - Error : the other xml nodes of the message are ignored
* - Fix : add two methods to the NotifyRequest for extracting the property array
* and modify the httpRequestRecieved method in ControlPoint
* 12/12/03
* - Added a static() to initialize UPnP class.
* 01/06/04
* - Added the following methods to remove expired devices automatically
* removeExpiredDevices()
* setExpiredDeviceMonitoringInterval()/getExpiredDeviceMonitoringInterval()
* setDeviceDisposer()/getDeviceDisposer()
* 04/20/04
* - Added the following methods.
* start(String target, int mx) and start(String target).
* 06/23/04
* - Added setNMPRMode() and isNMPRMode().
* 07/08/04
* - Added renewSubscriberService().
* - Changed start() to create renew subscriber thread when the NMPR mode is true.
* 08/17/04
* - Fixed removeExpiredDevices() to remove using the device array.
* 10/16/04
* - Oliver Newell
* - Added this class to allow ControlPoint applications to be notified when
* the ControlPoint base class adds/removes a UPnP device
* 03/30/05
* - Changed addDevice() to use Parser::parse(URL).
* 04/12/06
* - Added setUserData() and getUserData() to set a user original data object.
*
*******************************************************************/
package org.cybergarage.upnp;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URL;
import org.cybergarage.http.HTTPRequest;
import org.cybergarage.http.HTTPRequestListener;
import org.cybergarage.http.HTTPServerList;
import org.cybergarage.net.HostInterface;
import org.cybergarage.upnp.control.RenewSubscriber;
import org.cybergarage.upnp.device.DeviceChangeListener;
import org.cybergarage.upnp.device.Disposer;
import org.cybergarage.upnp.device.NotifyListener;
import org.cybergarage.upnp.device.ST;
import org.cybergarage.upnp.device.SearchResponseListener;
import org.cybergarage.upnp.device.USN;
import org.cybergarage.upnp.event.EventListener;
import org.cybergarage.upnp.event.NotifyRequest;
import org.cybergarage.upnp.event.Property;
import org.cybergarage.upnp.event.PropertyList;
import org.cybergarage.upnp.event.Subscription;
import org.cybergarage.upnp.event.SubscriptionRequest;
import org.cybergarage.upnp.event.SubscriptionResponse;
import org.cybergarage.upnp.ssdp.SSDP;
import org.cybergarage.upnp.ssdp.SSDPNotifySocketList;
import org.cybergarage.upnp.ssdp.SSDPPacket;
import org.cybergarage.upnp.ssdp.SSDPSearchRequest;
import org.cybergarage.upnp.ssdp.SSDPSearchResponseSocketList;
import org.cybergarage.util.Debug;
import org.cybergarage.util.ListenerList;
import org.cybergarage.util.Mutex;
import org.cybergarage.xml.Node;
import org.cybergarage.xml.NodeList;
import org.cybergarage.xml.Parser;
import org.cybergarage.xml.ParserException;
public class ControlPoint implements HTTPRequestListener
{
private final static int DEFAULT_EVENTSUB_PORT = 8058;
private final static int DEFAULT_SSDP_PORT = 8008;
private final static int DEFAULT_EXPIRED_DEVICE_MONITORING_INTERVAL = 60;
private final static String DEFAULT_EVENTSUB_URI = "/evetSub";
////////////////////////////////////////////////
// Member
////////////////////////////////////////////////
private SSDPNotifySocketList ssdpNotifySocketList;
private SSDPSearchResponseSocketList ssdpSearchResponseSocketList;
private SSDPNotifySocketList getSSDPNotifySocketList()
{
return ssdpNotifySocketList;
}
private SSDPSearchResponseSocketList getSSDPSearchResponseSocketList()
{
return ssdpSearchResponseSocketList;
}
////////////////////////////////////////////////
// Initialize
////////////////////////////////////////////////
static
{
UPnP.initialize();
}
////////////////////////////////////////////////
// Constructor
////////////////////////////////////////////////
public ControlPoint(int ssdpPort, int httpPort,InetAddress[] binds){
ssdpNotifySocketList = new SSDPNotifySocketList(binds);
ssdpSearchResponseSocketList = new SSDPSearchResponseSocketList(binds);
setSSDPPort(ssdpPort);
setHTTPPort(httpPort);
setDeviceDisposer(null);
setExpiredDeviceMonitoringInterval(DEFAULT_EXPIRED_DEVICE_MONITORING_INTERVAL);
setRenewSubscriber(null);
setNMPRMode(false);
setRenewSubscriber(null);
}
public ControlPoint(int ssdpPort, int httpPort){
this(ssdpPort,httpPort,null);
}
public ControlPoint()
{
this(DEFAULT_SSDP_PORT, DEFAULT_EVENTSUB_PORT);
}
public void finalize()
{
stop();
}
////////////////////////////////////////////////
// Mutex
////////////////////////////////////////////////
private Mutex mutex = new Mutex();
public void lock()
{
mutex.lock();
}
public void unlock()
{
mutex.unlock();
}
////////////////////////////////////////////////
// Port (SSDP)
////////////////////////////////////////////////
private int ssdpPort = 0;
public int getSSDPPort() {
return ssdpPort;
}
public void setSSDPPort(int port) {
ssdpPort = port;
}
////////////////////////////////////////////////
// Port (EventSub)
////////////////////////////////////////////////
private int httpPort = 0;
public int getHTTPPort() {
return httpPort;
}
public void setHTTPPort(int port) {
httpPort = port;
}
////////////////////////////////////////////////
// NMPR
////////////////////////////////////////////////
private boolean nmprMode;
public void setNMPRMode(boolean flag)
{
nmprMode = flag;
}
public boolean isNMPRMode()
{
return nmprMode;
}
////////////////////////////////////////////////
// Device List
////////////////////////////////////////////////
private NodeList devNodeList = new NodeList();
private void addDevice(Node rootNode)
{
devNodeList.add(rootNode);
}
private synchronized void addDevice(SSDPPacket ssdpPacket)
{
if (ssdpPacket.isRootDevice() == false)
return;
String usn = ssdpPacket.getUSN();
String udn = USN.getUDN(usn);
Device dev = getDevice(udn);
if (dev != null) {
dev.setSSDPPacket(ssdpPacket);
return;
}
String location = ssdpPacket.getLocation();
try {
URL locationUrl = new URL(location);
Parser parser = UPnP.getXMLParser();
Node rootNode = parser.parse(locationUrl);
Device rootDev = getDevice(rootNode);
if (rootDev == null)
return;
rootDev.setSSDPPacket(ssdpPacket);
Debug.warning("Add root device", new Exception("received on " + ssdpPacket.getLocalAddress()));
addDevice(rootNode);
// Thanks for Oliver Newell (2004/10/16)
// After node is added, invoke the AddDeviceListener to notify high-level
// control point application that a new device has been added. (The
// control point application must implement the DeviceChangeListener interface
// to receive the notifications)
performAddDeviceListener( rootDev );
}
catch (MalformedURLException me) {
Debug.warning(ssdpPacket.toString());
Debug.warning(me);
}
catch (ParserException pe) {
Debug.warning(ssdpPacket.toString());
Debug.warning(pe);
}
}
private Device getDevice(Node rootNode)
{
if (rootNode == null)
return null;
Node devNode = rootNode.getNode(Device.ELEM_NAME);
if (devNode == null)
return null;
return new Device(rootNode, devNode);
}
public DeviceList getDeviceList()
{
DeviceList devList = new DeviceList();
int nRoots = devNodeList.size();
for (int n=0; n (09/08/03)
if (httpReq.isNotifyRequest() == true) {
NotifyRequest notifyReq = new NotifyRequest(httpReq);
String uuid = notifyReq.getSID();
long seq = notifyReq.getSEQ();
PropertyList props = notifyReq.getPropertyList();
int propCnt = props.size();
for (int n = 0; n < propCnt; n++) {
Property prop = props.getProperty(n);
String varName = prop.getName();
String varValue = prop.getValue();
performEventListener(uuid, seq, varName, varValue);
}
httpReq.returnOK();
return;
}
httpReq.returnBadRequest();
}
////////////////////////////////////////////////
// Event Listener
////////////////////////////////////////////////
private ListenerList eventListenerList = new ListenerList();
public void addEventListener(EventListener listener)
{
eventListenerList.add(listener);
}
public void removeEventListener(EventListener listener)
{
eventListenerList.remove(listener);
}
public void performEventListener(String uuid, long seq, String name, String value)
{
int listenerSize = eventListenerList.size();
for (int n=0; n