/***************************************************************** | | Platinum - SSDP | | Copyright (c) 2004-2010, Plutinosoft, LLC. | All rights reserved. | http://www.plutinosoft.com | | This program is free software; you can redistribute it and/or | modify it under the terms of the GNU General Public License | as published by the Free Software Foundation; either version 2 | of the License, or (at your option) any later version. | | OEMs, ISVs, VARs and other distributors that combine and | distribute commercially licensed software with Platinum software | and do not wish to distribute the source code for the commercially | licensed software under version 2, or (at your option) any later | version, of the GNU General Public License (the "GPL") must enter | into a commercial license agreement with Plutinosoft, LLC. | licensing@plutinosoft.com | | This program is distributed in the hope that it will be useful, | but WITHOUT ANY WARRANTY; without even the implied warranty of | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | GNU General Public License for more details. | | You should have received a copy of the GNU General Public License | along with this program; see the file LICENSE.txt. If not, write to | the Free Software Foundation, Inc., | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | http://www.gnu.org/licenses/gpl-2.0.html | ****************************************************************/ /** @file UPnP SSDP */ #ifndef _PLT_SSDP_H_ #define _PLT_SSDP_H_ /*---------------------------------------------------------------------- | includes +---------------------------------------------------------------------*/ #include "Neptune.h" #include "PltThreadTask.h" #include "PltHttpServerTask.h" /*---------------------------------------------------------------------- | forward declarations +---------------------------------------------------------------------*/ class PLT_DeviceHost; /*---------------------------------------------------------------------- | PLT_SsdpPacketListener class +---------------------------------------------------------------------*/ /** The PLT_SsdpPacketListener class is an interface for handling SSDP packets (M-SEARCH and NOTIFY). */ class PLT_SsdpPacketListener { public: virtual ~PLT_SsdpPacketListener() {} virtual NPT_Result OnSsdpPacket(const NPT_HttpRequest& request, const NPT_HttpRequestContext& context) = 0; }; /*---------------------------------------------------------------------- | PLT_SsdpSearchResponseListener class +---------------------------------------------------------------------*/ /** The PLT_SsdpSearchResponseListener class is an interface for handling SSDP M-SEARCH responses. */ class PLT_SsdpSearchResponseListener { public: virtual ~PLT_SsdpSearchResponseListener() {} virtual NPT_Result ProcessSsdpSearchResponse(NPT_Result res, const NPT_HttpRequestContext& context, NPT_HttpResponse* response) = 0; }; /*---------------------------------------------------------------------- | PLT_SsdpSender class +---------------------------------------------------------------------*/ /** The PLT_SsdpSender class provides a mechanism to format and send SSDP packets. */ class PLT_SsdpSender { public: static NPT_Result SendSsdp(NPT_HttpRequest& request, const char* usn, const char* nt, NPT_UdpSocket& socket, bool notify, const NPT_SocketAddress* addr = NULL); static NPT_Result SendSsdp(NPT_HttpResponse& response, const char* usn, const char* nt, NPT_UdpSocket& socket, bool notify, const NPT_SocketAddress* addr = NULL); private: static NPT_Result FormatPacket(NPT_HttpMessage& message, const char* usn, const char* nt, NPT_UdpSocket& socket, bool notify); }; /*---------------------------------------------------------------------- | PLT_SsdpDeviceSearchResponseInterfaceIterator class +---------------------------------------------------------------------*/ /** The PLT_SsdpDeviceSearchResponseInterfaceIterator class looks for the best network interface to use then sends a SSDP M-SEARCH response. */ class PLT_SsdpDeviceSearchResponseInterfaceIterator { public: PLT_SsdpDeviceSearchResponseInterfaceIterator(PLT_DeviceHost* device, NPT_SocketAddress remote_addr, const char* st) : m_Device(device), m_RemoteAddr(remote_addr), m_ST(st) {} virtual ~PLT_SsdpDeviceSearchResponseInterfaceIterator() {} NPT_Result operator()(NPT_NetworkInterface*& if_addr) const; private: PLT_DeviceHost* m_Device; NPT_SocketAddress m_RemoteAddr; NPT_String m_ST; }; /*---------------------------------------------------------------------- | PLT_SsdpDeviceSearchResponseTask class +---------------------------------------------------------------------*/ /** The PLT_SsdpDeviceSearchResponseTask class is used by a PLT_DeviceHost to respond to SSDP M-SEARCH requests from UPnP ControlPoints. */ class PLT_SsdpDeviceSearchResponseTask : public PLT_ThreadTask { public: PLT_SsdpDeviceSearchResponseTask(PLT_DeviceHost* device, NPT_SocketAddress remote_addr, const char* st) : m_Device(device), m_RemoteAddr(remote_addr), m_ST(st) {} protected: virtual ~PLT_SsdpDeviceSearchResponseTask() {} // PLT_ThreadTask methods virtual void DoRun(); protected: PLT_DeviceHost* m_Device; NPT_SocketAddress m_RemoteAddr; NPT_String m_ST; }; /*---------------------------------------------------------------------- | PLT_SsdpAnnounceInterfaceIterator class +---------------------------------------------------------------------*/ /** The PLT_SsdpAnnounceInterfaceIterator class is used to send SSDP announcements given a list of network interaces. */ class PLT_SsdpAnnounceInterfaceIterator { public: PLT_SsdpAnnounceInterfaceIterator(PLT_DeviceHost* device, bool is_byebye = false, bool broadcast = false) : m_Device(device), m_IsByeBye(is_byebye), m_Broadcast(broadcast) {} NPT_Result operator()(NPT_NetworkInterface*& if_addr) const; private: PLT_DeviceHost* m_Device; bool m_IsByeBye; bool m_Broadcast; }; /*---------------------------------------------------------------------- | PLT_SsdpInitMulticastIterator class +---------------------------------------------------------------------*/ /** The PLT_SsdpInitMulticastIterator class is used to join a multicast group given a list of IP addresses. */ class PLT_SsdpInitMulticastIterator { public: PLT_SsdpInitMulticastIterator(NPT_UdpMulticastSocket* socket) : m_Socket(socket) {} NPT_Result operator()(NPT_IpAddress& if_addr) const { NPT_IpAddress addr; addr.ResolveName("239.255.255.250"); // OSX bug, since we're reusing the socket, we need to leave group first // before joining it m_Socket->LeaveGroup(addr, if_addr); return m_Socket->JoinGroup(addr, if_addr); } private: NPT_UdpMulticastSocket* m_Socket; }; /*---------------------------------------------------------------------- | PLT_SsdpDeviceAnnounceTask class +---------------------------------------------------------------------*/ /** The PLT_SsdpDeviceAnnounceTask class is a task to send UPnP Device SSDP announcements (alive or byebye). It can be setup to automatically repeat after an interval. */ class PLT_SsdpDeviceAnnounceTask : public PLT_ThreadTask { public: PLT_SsdpDeviceAnnounceTask(PLT_DeviceHost* device, NPT_TimeInterval repeat, bool is_byebye_first = false, bool extra_broadcast = false) : m_Device(device), m_Repeat(repeat), m_IsByeByeFirst(is_byebye_first), m_ExtraBroadcast(extra_broadcast) {} protected: virtual ~PLT_SsdpDeviceAnnounceTask() {} // PLT_ThreadTask methods virtual void DoRun(); protected: PLT_DeviceHost* m_Device; NPT_TimeInterval m_Repeat; bool m_IsByeByeFirst; bool m_ExtraBroadcast; }; /*---------------------------------------------------------------------- | PLT_NetworkInterfaceAddressSearchIterator class +---------------------------------------------------------------------*/ /** The PLT_NetworkInterfaceAddressSearchIterator class returns the network interface given an IP address. */ class PLT_NetworkInterfaceAddressSearchIterator { public: PLT_NetworkInterfaceAddressSearchIterator(NPT_String ip) : m_Ip(ip) {} virtual ~PLT_NetworkInterfaceAddressSearchIterator() {} NPT_Result operator()(NPT_NetworkInterface*& addr) const { NPT_List<NPT_NetworkInterfaceAddress>::Iterator niaddr = addr->GetAddresses().GetFirstItem(); if (!niaddr) return NPT_FAILURE; return (m_Ip.Compare((*niaddr).GetPrimaryAddress().ToString(), true) == 0) ? NPT_SUCCESS : NPT_FAILURE; } private: NPT_String m_Ip; }; /*---------------------------------------------------------------------- | PLT_SsdpPacketListenerIterator class +---------------------------------------------------------------------*/ /** The PLT_SsdpPacketListenerIterator class iterates through a list of PLT_SsdpPacketListener instances to notify of a new SSDP incoming packet. */ class PLT_SsdpPacketListenerIterator { public: PLT_SsdpPacketListenerIterator(NPT_HttpRequest& request, const NPT_HttpRequestContext& context) : m_Request(request), m_Context(context) {} NPT_Result operator()(PLT_SsdpPacketListener*& listener) const { return listener->OnSsdpPacket(m_Request, m_Context); } private: NPT_HttpRequest& m_Request; const NPT_HttpRequestContext& m_Context; }; /*---------------------------------------------------------------------- | PLT_SsdpListenTask class +---------------------------------------------------------------------*/ /** The PLT_SsdpListenTask class is used to listen for incoming SSDP packets and keep track of a list of PLT_SsdpPacketListener listeners to notify when a new SSDP packet has arrived. */ class PLT_SsdpListenTask : public PLT_HttpServerSocketTask { public: PLT_SsdpListenTask(NPT_Socket* socket) : PLT_HttpServerSocketTask(socket, true) { // Change read time out for UDP because iPhone 3.0 seems to hang // after reading everything from the socket even though // more stuff arrived #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE m_Socket->SetReadTimeout(10000); #endif } NPT_Result AddListener(PLT_SsdpPacketListener* listener) { NPT_AutoLock lock(m_Mutex); m_Listeners.Add(listener); return NPT_SUCCESS; } NPT_Result RemoveListener(PLT_SsdpPacketListener* listener) { NPT_AutoLock lock(m_Mutex); m_Listeners.Remove(listener); return NPT_SUCCESS; } // PLT_Task methods void DoAbort(); protected: virtual ~PLT_SsdpListenTask() {} // PLT_HttpServerSocketTask methods NPT_Result GetInputStream(NPT_InputStreamReference& stream); NPT_Result GetInfo(NPT_SocketInfo& info); NPT_Result SetupResponse(NPT_HttpRequest& request, const NPT_HttpRequestContext& context, NPT_HttpResponse& response); protected: PLT_InputDatagramStreamReference m_Datagram; NPT_List<PLT_SsdpPacketListener*> m_Listeners; NPT_Mutex m_Mutex; }; /*---------------------------------------------------------------------- | PLT_SsdpSearchTask class +---------------------------------------------------------------------*/ /** The PLT_SsdpSearchTask class is a task used by a PLT_CtrlPoint to issue a SSDP M-SEARCH request. It can be set to repeat at a certain frequencey. */ class PLT_SsdpSearchTask : public PLT_ThreadTask { public: PLT_SsdpSearchTask(NPT_UdpSocket* socket, PLT_SsdpSearchResponseListener* listener, NPT_HttpRequest* request, NPT_TimeInterval frequency = NPT_TimeInterval(0.)); // pass 0 for one time protected: virtual ~PLT_SsdpSearchTask(); // PLT_ThreadTask methods virtual void DoAbort(); virtual void DoRun(); virtual NPT_Result ProcessResponse(NPT_Result res, const NPT_HttpRequest& request, const NPT_HttpRequestContext& context, NPT_HttpResponse* response); private: PLT_SsdpSearchResponseListener* m_Listener; NPT_HttpRequest* m_Request; NPT_TimeInterval m_Frequency; bool m_Repeat; NPT_UdpSocket* m_Socket; }; #endif /* _PLT_SSDP_H_ */