SSDP Server - working version provides SSDP based network discovery, and with a companion web server, may provide other functionalities.
Dependents: X10Svr SSDP_Server
SSDP.cpp
- Committer:
- WiredHome
- Date:
- 2018-07-03
- Revision:
- 0:f782e7bc66ad
- Child:
- 1:def15d0b2fae
File content as of revision 0:f782e7bc66ad:
// // 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); }