SSDP Server - working version provides SSDP based network discovery, and with a companion web server, may provide other functionalities.

Dependents:   X10Svr SSDP_Server

Committer:
WiredHome
Date:
Tue Jul 03 00:16:45 2018 +0000
Revision:
0:f782e7bc66ad
Child:
1:def15d0b2fae
Initial working version that seems to run well (only tested with a near zero-load main( ), which hosted only the web server.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
WiredHome 0:f782e7bc66ad 1 //
WiredHome 0:f782e7bc66ad 2 // SSDP Server
WiredHome 0:f782e7bc66ad 3 //
WiredHome 0:f782e7bc66ad 4 // This is an SSDP server. It relies on a web server running on this same node.
WiredHome 0:f782e7bc66ad 5 //
WiredHome 0:f782e7bc66ad 6 //
WiredHome 0:f782e7bc66ad 7 #include "SSDP.h"
WiredHome 0:f782e7bc66ad 8 #include "EthernetInterface.h"
WiredHome 0:f782e7bc66ad 9
WiredHome 0:f782e7bc66ad 10 extern DigitalOut led1;
WiredHome 0:f782e7bc66ad 11
WiredHome 0:f782e7bc66ad 12
WiredHome 0:f782e7bc66ad 13 static const char* MCAST_GRP = "239.255.255.250";
WiredHome 0:f782e7bc66ad 14 static const int MCAST_PORT = 1900;
WiredHome 0:f782e7bc66ad 15
WiredHome 0:f782e7bc66ad 16
WiredHome 0:f782e7bc66ad 17 // sprintf(buffer, SSDP_HTTP, "myIPString", myPort, "myIdentity", "myIdentity");
WiredHome 0:f782e7bc66ad 18 // Requires IP address as a string
WiredHome 0:f782e7bc66ad 19 static const char * SSDP_HTTP =
WiredHome 0:f782e7bc66ad 20 "HTTP/1.1 200 OK\r\n"
WiredHome 0:f782e7bc66ad 21 "CACHE-CONTROL: max-age=1800\r\n"
WiredHome 0:f782e7bc66ad 22 "DATE: Mon, 22 Jun 2015 17:24:01 GMT\r\n"
WiredHome 0:f782e7bc66ad 23 "EXT:\r\n"
WiredHome 0:f782e7bc66ad 24 "LOCATION: http://%s:%d/setup.xml\r\n" // "my.ip.string", portNum
WiredHome 0:f782e7bc66ad 25 "OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n"
WiredHome 0:f782e7bc66ad 26 "01-NLS: %s\r\n" // "Unique Identity"
WiredHome 0:f782e7bc66ad 27 "SERVER: Smartware, UPnP/1.0, Smartware\r\n"
WiredHome 0:f782e7bc66ad 28 "ST: upnp:rootdevice\r\n"
WiredHome 0:f782e7bc66ad 29 "USN: uuid:Node-1_0-%s::upnp:rootdevice\r\n" // "Unique Identity"
WiredHome 0:f782e7bc66ad 30 "X-User-Agent: Smartware\r\n"
WiredHome 0:f782e7bc66ad 31 "\r\n";
WiredHome 0:f782e7bc66ad 32
WiredHome 0:f782e7bc66ad 33 // Addr: "###.###.###.###" [15]
WiredHome 0:f782e7bc66ad 34 // Port: 12345 [5]
WiredHome 0:f782e7bc66ad 35 // Ident: "#########0#########0#########0" [30] x 2
WiredHome 0:f782e7bc66ad 36 //
WiredHome 0:f782e7bc66ad 37 #define SSDP_HTTP_OVERHEAD 50 // Number of bytes to fill in the information
WiredHome 0:f782e7bc66ad 38
WiredHome 0:f782e7bc66ad 39
WiredHome 0:f782e7bc66ad 40 // sprintf(buffer, SSDP_NOTIFY, myIPasString, myPort);
WiredHome 0:f782e7bc66ad 41 // Requires IP address as a string
WiredHome 0:f782e7bc66ad 42 const char * SSDP_NOTIFY =
WiredHome 0:f782e7bc66ad 43 "NOTIFY * HTTP/1.1\r\n"
WiredHome 0:f782e7bc66ad 44 "HOST: 239.255.255.250:1900\r\n"
WiredHome 0:f782e7bc66ad 45 "CACHE-CONTROL: max-age=1800\r\n"
WiredHome 0:f782e7bc66ad 46 "LOCATION: http://%s:%u/setup.xml\r\n"
WiredHome 0:f782e7bc66ad 47 "NTS: ssdp:alive\r\n\r\n"
WiredHome 0:f782e7bc66ad 48 "";
WiredHome 0:f782e7bc66ad 49
WiredHome 0:f782e7bc66ad 50 // Addr: "###.###.###.###" [15]
WiredHome 0:f782e7bc66ad 51 // Port: 12345 [5]
WiredHome 0:f782e7bc66ad 52 //
WiredHome 0:f782e7bc66ad 53 #define SSDP_NOTIFY_OVERHEAD 20 // Number of bytes to fill in the information
WiredHome 0:f782e7bc66ad 54
WiredHome 0:f782e7bc66ad 55
WiredHome 0:f782e7bc66ad 56 static void SSDPListener(void const * args) {
WiredHome 0:f782e7bc66ad 57 UDPSocket server;
WiredHome 0:f782e7bc66ad 58 SSDP_Config_T * cfg = (SSDP_Config_T *)args;
WiredHome 0:f782e7bc66ad 59
WiredHome 0:f782e7bc66ad 60 server.bind(MCAST_PORT);
WiredHome 0:f782e7bc66ad 61 if (server.join_multicast_group(MCAST_GRP) != 0) {
WiredHome 0:f782e7bc66ad 62 printf("Error joining the multicast group\n");
WiredHome 0:f782e7bc66ad 63 while (true) {}
WiredHome 0:f782e7bc66ad 64 }
WiredHome 0:f782e7bc66ad 65
WiredHome 0:f782e7bc66ad 66 Endpoint client;
WiredHome 0:f782e7bc66ad 67 char buffer[256];
WiredHome 0:f782e7bc66ad 68 while (true) {
WiredHome 0:f782e7bc66ad 69 printf("Wait for packet...\n");
WiredHome 0:f782e7bc66ad 70 int n = server.receiveFrom(client, buffer, sizeof(buffer)-1);
WiredHome 0:f782e7bc66ad 71 buffer[n] = '\0';
WiredHome 0:f782e7bc66ad 72 led1 = true;
WiredHome 0:f782e7bc66ad 73 if (n) {
WiredHome 0:f782e7bc66ad 74 char * p = buffer;
WiredHome 0:f782e7bc66ad 75 volatile int delay = 1;
WiredHome 0:f782e7bc66ad 76
WiredHome 0:f782e7bc66ad 77 while (*p) {
WiredHome 0:f782e7bc66ad 78 char * e = strstr(p, "\r\n");
WiredHome 0:f782e7bc66ad 79 if (e && (e - buffer) < n) {
WiredHome 0:f782e7bc66ad 80 *e = '\0';
WiredHome 0:f782e7bc66ad 81 if (strstr(p, "MX: ")) {
WiredHome 0:f782e7bc66ad 82 delay = atoi(p + 3);
WiredHome 0:f782e7bc66ad 83 } else if (strstr(p, "HOST: ")) {
WiredHome 0:f782e7bc66ad 84 char * pColon = strchr(p+6, ':');
WiredHome 0:f782e7bc66ad 85 if (pColon) {
WiredHome 0:f782e7bc66ad 86 pColon = '\0';
WiredHome 0:f782e7bc66ad 87 }
WiredHome 0:f782e7bc66ad 88 }
WiredHome 0:f782e7bc66ad 89 p = e + 1;
WiredHome 0:f782e7bc66ad 90 }
WiredHome 0:f782e7bc66ad 91 p++;
WiredHome 0:f782e7bc66ad 92 }
WiredHome 0:f782e7bc66ad 93 char * out_buffer = (char *)malloc(strlen(SSDP_HTTP) + SSDP_HTTP_OVERHEAD);
WiredHome 0:f782e7bc66ad 94 if (out_buffer) {
WiredHome 0:f782e7bc66ad 95 sprintf(out_buffer, SSDP_HTTP, cfg->ipAddr, cfg->port, cfg->ident, cfg->ident);
WiredHome 0:f782e7bc66ad 96 // It would be polite to delay, but the recommendation is from 1 to 2 seconds
WiredHome 0:f782e7bc66ad 97 // Thread::wait(delay * 1000);
WiredHome 0:f782e7bc66ad 98 server.sendTo(client, out_buffer, strlen(out_buffer));
WiredHome 0:f782e7bc66ad 99 free(out_buffer);
WiredHome 0:f782e7bc66ad 100 }
WiredHome 0:f782e7bc66ad 101 }
WiredHome 0:f782e7bc66ad 102 led1 = false;
WiredHome 0:f782e7bc66ad 103 }
WiredHome 0:f782e7bc66ad 104 }
WiredHome 0:f782e7bc66ad 105
WiredHome 0:f782e7bc66ad 106 SSDP::SSDP(const char * name, const char * ident, const char * ipAddr, int port) {
WiredHome 0:f782e7bc66ad 107 pThr = NULL;
WiredHome 0:f782e7bc66ad 108 _config.name = NULL;
WiredHome 0:f782e7bc66ad 109 SetFriendlyName(name);
WiredHome 0:f782e7bc66ad 110 _config.ident = NULL;
WiredHome 0:f782e7bc66ad 111 SetFriendlyName(ident);
WiredHome 0:f782e7bc66ad 112 _config.ipAddr = NULL;
WiredHome 0:f782e7bc66ad 113 SetIPAddress(ipAddr);
WiredHome 0:f782e7bc66ad 114 _config.port = port;
WiredHome 0:f782e7bc66ad 115 StartListener();
WiredHome 0:f782e7bc66ad 116 printf("SSDP(......) constructor done. Listener Started.\n");
WiredHome 0:f782e7bc66ad 117 SendNotify();
WiredHome 0:f782e7bc66ad 118 }
WiredHome 0:f782e7bc66ad 119
WiredHome 0:f782e7bc66ad 120 SSDP::SSDP(const SSDP_Config_T * config) {
WiredHome 0:f782e7bc66ad 121 pThr = NULL;
WiredHome 0:f782e7bc66ad 122 memcpy(&_config, config, sizeof(SSDP_Config_T));
WiredHome 0:f782e7bc66ad 123 StartListener();
WiredHome 0:f782e7bc66ad 124 printf("SSDP() constructor done. Listener Started.\n");
WiredHome 0:f782e7bc66ad 125 SendNotify();
WiredHome 0:f782e7bc66ad 126 }
WiredHome 0:f782e7bc66ad 127
WiredHome 0:f782e7bc66ad 128 SSDP::~SSDP() {
WiredHome 0:f782e7bc66ad 129 if (pThr)
WiredHome 0:f782e7bc66ad 130 pThr->terminate();
WiredHome 0:f782e7bc66ad 131 pThr = NULL;
WiredHome 0:f782e7bc66ad 132 DelFriendlyName();
WiredHome 0:f782e7bc66ad 133 DelIdentity();
WiredHome 0:f782e7bc66ad 134 DelIPAddress();
WiredHome 0:f782e7bc66ad 135 }
WiredHome 0:f782e7bc66ad 136
WiredHome 0:f782e7bc66ad 137 void SSDP::SendNotify() {
WiredHome 0:f782e7bc66ad 138 char * out_buffer = (char *)malloc(strlen(SSDP_NOTIFY) + SSDP_NOTIFY_OVERHEAD);
WiredHome 0:f782e7bc66ad 139 if (out_buffer) {
WiredHome 0:f782e7bc66ad 140 UDPSocket sock;
WiredHome 0:f782e7bc66ad 141 sock.init();
WiredHome 0:f782e7bc66ad 142 sock.set_broadcasting();
WiredHome 0:f782e7bc66ad 143
WiredHome 0:f782e7bc66ad 144 Endpoint broadcast;
WiredHome 0:f782e7bc66ad 145 broadcast.set_address(MCAST_GRP, MCAST_PORT);
WiredHome 0:f782e7bc66ad 146 sprintf(out_buffer, SSDP_NOTIFY, _config.ipAddr, _config.port);
WiredHome 0:f782e7bc66ad 147 sock.sendTo(broadcast, out_buffer, strlen(out_buffer));
WiredHome 0:f782e7bc66ad 148 free(out_buffer);
WiredHome 0:f782e7bc66ad 149 }
WiredHome 0:f782e7bc66ad 150 }
WiredHome 0:f782e7bc66ad 151
WiredHome 0:f782e7bc66ad 152 bool SSDP::SetFriendlyName(const char * name) {
WiredHome 0:f782e7bc66ad 153 DelFriendlyName();
WiredHome 0:f782e7bc66ad 154 _config.name = (char *)malloc(strlen(name) + 1);
WiredHome 0:f782e7bc66ad 155 if (_config.name) {
WiredHome 0:f782e7bc66ad 156 strcpy(_config.name, name);
WiredHome 0:f782e7bc66ad 157 return true;
WiredHome 0:f782e7bc66ad 158 } else {
WiredHome 0:f782e7bc66ad 159 return false;
WiredHome 0:f782e7bc66ad 160 }
WiredHome 0:f782e7bc66ad 161 }
WiredHome 0:f782e7bc66ad 162
WiredHome 0:f782e7bc66ad 163 void SSDP::DelFriendlyName() {
WiredHome 0:f782e7bc66ad 164 if (_config.name)
WiredHome 0:f782e7bc66ad 165 free(_config.name);
WiredHome 0:f782e7bc66ad 166 _config.name = NULL;
WiredHome 0:f782e7bc66ad 167 }
WiredHome 0:f782e7bc66ad 168
WiredHome 0:f782e7bc66ad 169 bool SSDP::SetIdentity(const char * ident) {
WiredHome 0:f782e7bc66ad 170 DelIdentity();
WiredHome 0:f782e7bc66ad 171 _config.ident = (char *)malloc(strlen(ident) + 1);
WiredHome 0:f782e7bc66ad 172 if (_config.ident) {
WiredHome 0:f782e7bc66ad 173 strcpy(_config.ident, ident);
WiredHome 0:f782e7bc66ad 174 return true;
WiredHome 0:f782e7bc66ad 175 } else {
WiredHome 0:f782e7bc66ad 176 return false;
WiredHome 0:f782e7bc66ad 177 }
WiredHome 0:f782e7bc66ad 178 }
WiredHome 0:f782e7bc66ad 179
WiredHome 0:f782e7bc66ad 180 void SSDP::DelIdentity() {
WiredHome 0:f782e7bc66ad 181 if (_config.ident)
WiredHome 0:f782e7bc66ad 182 free(_config.ident);
WiredHome 0:f782e7bc66ad 183 _config.ident = NULL;
WiredHome 0:f782e7bc66ad 184 }
WiredHome 0:f782e7bc66ad 185
WiredHome 0:f782e7bc66ad 186 bool SSDP::SetIPAddress(const char * ipAddr) {
WiredHome 0:f782e7bc66ad 187 DelIPAddress();
WiredHome 0:f782e7bc66ad 188 _config.ipAddr = (char *)malloc(strlen(ipAddr) + 1);
WiredHome 0:f782e7bc66ad 189 if (_config.ipAddr) {
WiredHome 0:f782e7bc66ad 190 strcpy(_config.ipAddr, ipAddr);
WiredHome 0:f782e7bc66ad 191 return true;
WiredHome 0:f782e7bc66ad 192 } else {
WiredHome 0:f782e7bc66ad 193 return false;
WiredHome 0:f782e7bc66ad 194 }
WiredHome 0:f782e7bc66ad 195 }
WiredHome 0:f782e7bc66ad 196
WiredHome 0:f782e7bc66ad 197 void SSDP::DelIPAddress() {
WiredHome 0:f782e7bc66ad 198 if (_config.ipAddr)
WiredHome 0:f782e7bc66ad 199 free(_config.ipAddr);
WiredHome 0:f782e7bc66ad 200 _config.ipAddr = NULL;
WiredHome 0:f782e7bc66ad 201 }
WiredHome 0:f782e7bc66ad 202
WiredHome 0:f782e7bc66ad 203 bool SSDP::SetPort(int port) {
WiredHome 0:f782e7bc66ad 204 _config.port = port;
WiredHome 0:f782e7bc66ad 205 return true;
WiredHome 0:f782e7bc66ad 206 }
WiredHome 0:f782e7bc66ad 207
WiredHome 0:f782e7bc66ad 208 void SSDP::StartListener() {
WiredHome 0:f782e7bc66ad 209 pThr = new Thread(SSDPListener, (void *)&_config, osPriorityLow);
WiredHome 0:f782e7bc66ad 210 }