SSDP Server - working version provides SSDP based network discovery, and with a companion web server, may provide other functionalities.
Dependents: X10Svr SSDP_Server
Revision 0:f782e7bc66ad, committed 2018-07-03
- Comitter:
- WiredHome
- Date:
- Tue Jul 03 00:16:45 2018 +0000
- Child:
- 1:def15d0b2fae
- Commit message:
- Initial working version that seems to run well (only tested with a near zero-load main( ), which hosted only the web server.
Changed in this revision
SSDP.cpp | Show annotated file Show diff for this revision Revisions of this file |
SSDP.h | Show annotated file Show diff for this revision Revisions of this file |
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SSDP.cpp Tue Jul 03 00:16:45 2018 +0000 @@ -0,0 +1,210 @@ +// +// SSDP Server +// +// This is an SSDP server. It relies on a web server running on this same node. +// +// +#include "SSDP.h" +#include "EthernetInterface.h" + +extern DigitalOut led1; + + +static const char* MCAST_GRP = "239.255.255.250"; +static const int MCAST_PORT = 1900; + + +// sprintf(buffer, SSDP_HTTP, "myIPString", myPort, "myIdentity", "myIdentity"); +// Requires IP address as a string +static const char * SSDP_HTTP = + "HTTP/1.1 200 OK\r\n" + "CACHE-CONTROL: max-age=1800\r\n" + "DATE: Mon, 22 Jun 2015 17:24:01 GMT\r\n" + "EXT:\r\n" + "LOCATION: http://%s:%d/setup.xml\r\n" // "my.ip.string", portNum + "OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n" + "01-NLS: %s\r\n" // "Unique Identity" + "SERVER: Smartware, UPnP/1.0, Smartware\r\n" + "ST: upnp:rootdevice\r\n" + "USN: uuid:Node-1_0-%s::upnp:rootdevice\r\n" // "Unique Identity" + "X-User-Agent: Smartware\r\n" + "\r\n"; + +// Addr: "###.###.###.###" [15] +// Port: 12345 [5] +// Ident: "#########0#########0#########0" [30] x 2 +// +#define SSDP_HTTP_OVERHEAD 50 // Number of bytes to fill in the information + + +// sprintf(buffer, SSDP_NOTIFY, myIPasString, myPort); +// Requires IP address as a string +const char * SSDP_NOTIFY = + "NOTIFY * HTTP/1.1\r\n" + "HOST: 239.255.255.250:1900\r\n" + "CACHE-CONTROL: max-age=1800\r\n" + "LOCATION: http://%s:%u/setup.xml\r\n" + "NTS: ssdp:alive\r\n\r\n" + ""; + +// Addr: "###.###.###.###" [15] +// Port: 12345 [5] +// +#define SSDP_NOTIFY_OVERHEAD 20 // Number of bytes to fill in the information + + +static void SSDPListener(void const * args) { + UDPSocket server; + SSDP_Config_T * cfg = (SSDP_Config_T *)args; + + server.bind(MCAST_PORT); + if (server.join_multicast_group(MCAST_GRP) != 0) { + printf("Error joining the multicast group\n"); + while (true) {} + } + + Endpoint client; + char buffer[256]; + while (true) { + printf("Wait for packet...\n"); + int n = server.receiveFrom(client, buffer, sizeof(buffer)-1); + buffer[n] = '\0'; + led1 = true; + if (n) { + char * p = buffer; + volatile int delay = 1; + + while (*p) { + char * e = strstr(p, "\r\n"); + if (e && (e - buffer) < n) { + *e = '\0'; + if (strstr(p, "MX: ")) { + delay = atoi(p + 3); + } else if (strstr(p, "HOST: ")) { + char * pColon = strchr(p+6, ':'); + if (pColon) { + pColon = '\0'; + } + } + p = e + 1; + } + p++; + } + char * out_buffer = (char *)malloc(strlen(SSDP_HTTP) + SSDP_HTTP_OVERHEAD); + if (out_buffer) { + sprintf(out_buffer, SSDP_HTTP, cfg->ipAddr, cfg->port, cfg->ident, cfg->ident); + // It would be polite to delay, but the recommendation is from 1 to 2 seconds + // Thread::wait(delay * 1000); + server.sendTo(client, out_buffer, strlen(out_buffer)); + free(out_buffer); + } + } + led1 = false; + } +} + +SSDP::SSDP(const char * name, const char * ident, const char * ipAddr, int port) { + pThr = NULL; + _config.name = NULL; + SetFriendlyName(name); + _config.ident = NULL; + SetFriendlyName(ident); + _config.ipAddr = NULL; + SetIPAddress(ipAddr); + _config.port = port; + StartListener(); + printf("SSDP(......) constructor done. Listener Started.\n"); + SendNotify(); +} + +SSDP::SSDP(const SSDP_Config_T * config) { + pThr = NULL; + memcpy(&_config, config, sizeof(SSDP_Config_T)); + StartListener(); + printf("SSDP() constructor done. Listener Started.\n"); + SendNotify(); +} + +SSDP::~SSDP() { + if (pThr) + pThr->terminate(); + pThr = NULL; + DelFriendlyName(); + DelIdentity(); + DelIPAddress(); +} + +void SSDP::SendNotify() { + char * out_buffer = (char *)malloc(strlen(SSDP_NOTIFY) + SSDP_NOTIFY_OVERHEAD); + if (out_buffer) { + UDPSocket sock; + sock.init(); + sock.set_broadcasting(); + + Endpoint broadcast; + broadcast.set_address(MCAST_GRP, MCAST_PORT); + sprintf(out_buffer, SSDP_NOTIFY, _config.ipAddr, _config.port); + sock.sendTo(broadcast, out_buffer, strlen(out_buffer)); + free(out_buffer); + } +} + +bool SSDP::SetFriendlyName(const char * name) { + DelFriendlyName(); + _config.name = (char *)malloc(strlen(name) + 1); + if (_config.name) { + strcpy(_config.name, name); + return true; + } else { + return false; + } +} + +void SSDP::DelFriendlyName() { + if (_config.name) + free(_config.name); + _config.name = NULL; +} + +bool SSDP::SetIdentity(const char * ident) { + DelIdentity(); + _config.ident = (char *)malloc(strlen(ident) + 1); + if (_config.ident) { + strcpy(_config.ident, ident); + return true; + } else { + return false; + } +} + +void SSDP::DelIdentity() { + if (_config.ident) + free(_config.ident); + _config.ident = NULL; +} + +bool SSDP::SetIPAddress(const char * ipAddr) { + DelIPAddress(); + _config.ipAddr = (char *)malloc(strlen(ipAddr) + 1); + if (_config.ipAddr) { + strcpy(_config.ipAddr, ipAddr); + return true; + } else { + return false; + } +} + +void SSDP::DelIPAddress() { + if (_config.ipAddr) + free(_config.ipAddr); + _config.ipAddr = NULL; +} + +bool SSDP::SetPort(int port) { + _config.port = port; + return true; +} + +void SSDP::StartListener() { + pThr = new Thread(SSDPListener, (void *)&_config, osPriorityLow); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SSDP.h Tue Jul 03 00:16:45 2018 +0000 @@ -0,0 +1,126 @@ +// +// +// + +#include "mbed.h" +#include "rtos.h" + + +/// Configuration data for the SSDP server +/// +typedef struct { + char * name; ///< pointer to the friendly name, storage managed here + char * ident; ///< pointer to a unique identity number, like a mac address + char * ipAddr; ///< pointer to the node IP address + int port; ///< port number of the local server +} SSDP_Config_T; + + +/// +/// SSDP Server +/// +/// This file documents the SSDP Server, which can be implanted into a node +/// so that it is discoverable on Ethernet, and in Windows Network Explorer +/// view. +/// +/// Many basics are defined in order to satisfy the SSDP discovery process. +/// - the hosting node has a web server running, which will serve various responses. +/// - the hosting node shall provide a /setup.xml which satisfies the SSDP requirements. +/// - depending on the application, many additional files may need to be supported. +/// +/// @code +/// HTTPServer svr(Server_Port, Server_Root, 15, 30, 20, 50, &pc); +/// svr.RegisterHandler("/", RootPage); +/// svr.RegisterHandler("/setup.xml", Setup_xml); +/// SSDP ssdp("Friendly Node", eth.getMACAddress(), eth.getIPAddress(), Server_Port); +/// +/// while (1) { +/// led4 = !led4; +/// svr.Poll(); // non-blocking, but also not deterministic +/// Thread::yield(); +/// if (criteria) +/// ssdp.SetFriendlyName("New Node Name"); +/// } +/// @endcode +/// +class SSDP { +public: + /// Constructor for the SSDP server + /// + /// @param[in] name is a pointer to a string containing the name. + /// @param[in] ident is a pointer to an identity string of this node, e.g. a mac address. + /// @param[in] ipAddr is a pointer to an IP Address string of this node. + /// @param[in] port is an integer port number for the local web server. + /// + SSDP(const char * name, const char * ident, const char * ipAddr, int port); + + /// Constructor for the SSDP server, as an alternate to the parameter version. + /// + /// @param[in] config is a pointer to configuration structure which contains + /// the individual elements; + /// - pointer to the const char * friendly name + /// - pointer to the const char * identity + /// - pointer to the const char * IP Address of this node + /// - port number for the web server + /// + SSDP(const SSDP_Config_T * config); + + /// Destructor + /// + ~SSDP(); + + /// Set the friendly name for this node + /// + /// @param[in] name is a pointer to a string containing the name. + /// @returns true if the name was set (memory was available). + /// + bool SetFriendlyName(const char * name); + + /// Delete the friendly name that was assigned. + /// + /// This frees the memory that was previously allocated. + /// + void DelFriendlyName(); + + /// Set the identity for this node + /// + /// @param[in] ident is a pointer to a string containing the identity. + /// @returns true if the name was set (memory was available). + /// + bool SetIdentity(const char * ident); + + /// Delete the identity that was assigned. + /// + /// This frees the memory that was previously allocated. + /// + void DelIdentity(); + + /// Set the IP Address for this node + /// + /// @param[in] ipAddr is a pointer to a string containing the ipAddress. + /// @returns true if the IP Address was set (memory was available). + /// + bool SetIPAddress(const char * ipAddr); + + /// Delete the friendly IP Address that was assigned. + /// + /// This frees the memory that was previously allocated. + /// + void DelIPAddress(); + + /// Set the Port + /// + /// @param[in] port is the port number of the local web server. + /// @returns true if the port number was set. + /// + bool SetPort(int port); + +private: + + void StartListener(); + void SendNotify(); + + SSDP_Config_T _config; ///< the configuration + + Thread * pThr; +}; \ No newline at end of file