/****************************************************************** * * 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). * *******************************************************************/ package org.cybergarage.upnp; import org.cybergarage.net.*; import org.cybergarage.util.*; import org.cybergarage.xml.*; import org.cybergarage.http.*; import org.cybergarage.upnp.control.*; import org.cybergarage.upnp.ssdp.*; import org.cybergarage.upnp.device.*; import org.cybergarage.upnp.event.*; import java.net.*; 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) { ssdpNotifySocketList = new SSDPNotifySocketList(); ssdpSearchResponseSocketList = new SSDPSearchResponseSocketList(); setSSDPPort(ssdpPort); setHTTPPort(httpPort); setDeviceDisposer(null); setExpiredDeviceMonitoringInterval(DEFAULT_EXPIRED_DEVICE_MONITORING_INTERVAL); setRenewSubscriber(null); setNMPRMode(false); setRenewSubscriber(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); 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