SSDP Search
Overview
This tutorial demonstrates how to use Mongoose Library for UDP communication, by performing an SSDP search.
SSDP (Simple Service Discovery Protocol) is used for advertisement and discovery of network services; serving as the lowest layer of the discovery protocol stack for the UPnP (Universal Plug and Play) architecture.
- We send an UDP datagram to the multicast address
239.255.255.250
on port1900
; this datagram contains an SSDP M-SEARCH request - UPnP devices and control points listen to that address and port, so any one of these having the requested capabilities will answer. Responses are unicast
- We receive those responses as UDP datagrams
- Since SSDP is based on HTTP/1.1 (RFC2616), we can parse those responses and print some contents
Build and run
- Follow the Build Tools tutorial to setup your development environment.
- Start a terminal in the project directory; if you've not already done so, clone the Mongoose Library repo
git clone https://github.com/cesanta/mongoose
- Build the example, this will also start the example:
cd mongoose/tutorials/udp/ssdp-search make clean all
- Observe the log
The example searches for media renderers, if you have one, it should show up. (Windows users: see below)181baf18d6d 2 main.c:40:tfn Sending M-SEARCH 181baf18dcf 2 main.c:16:fn Got a response Server -> DLNADOC/1.50 Linux/3.10.104 UPnP/1.0 RKDLNALib/2.0 Location -> http://192.168.69.246:38388/deviceDescription/MediaRenderer
How it works
- The event manager is in charge of processing network communications and timing, calling the event handler functions accordingly. It is called repeatedly at the main loop.
int main(void) {
struct mg_mgr mgr;
mg_mgr_init(&mgr);
...
while (true) mg_mgr_poll(&mgr, 200);
mg_mgr_free(&mgr);
return 0;
}
- We create a connection by calling mg_connect(). This function will process the URL and return a connection handler or NULL on failure. The function
fn
will be our event handler function.
static const char *s_ssdp_url = "udp://239.255.255.250:1900";
int main(void) {
...
c = mg_connect(&mgr, s_ssdp_url, fn, NULL);
- We start a repeatable timer, so we can perform the search every 2 seconds. The function
tfn
will be our event handler function, and we pass a pointer to our connection,c
, as its argument.
mg_timer_add(&mgr, 2000, MG_TIMER_REPEAT | MG_TIMER_RUN_NOW, tfn, c);
- When the URL is resolved to an address and port, the connection event handler will receive an
MG_EV_RESOLVE
event. We save this information.
- The timer event handler sends the request to the connection using
mg_printf()
. We search for media renderers, but we could search for example for root devices:ST: upnp:rootdevice
or any SSDP-capable device:ST: ssdp:all
- UPnP devices and control points listen to that address and port. If there is one having the requested capabilities, it will answer with a unicast UDP datagram. The connection event handler will then receive an
MG_EV_READ
event. Since the protocol is based on HTTP/1.1 (RFC2616), we can parse those responses and print relevant information.
- Each response will fill
c->rem
with the sender information, so we can be able to send something back. Since we need to send the next query to the multicast address, we recover the information we saved before
Windows users
If the multicast UDP datagrams are sent to the loopback interface, you will only see responses if you actually have a renderer on your machine listening on that interface. In that case, to reach other hosts in your newtwork, configure the socket to use your physical interface by adding these lines to the MG_EV_RESOLVE
handler:
uint32_t ifip = inet_addr("192.168.69.16"); // use your network interface address
setsockopt((MG_SOCKET_TYPE) (size_t) c->fd, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&ifip, sizeof(ifip));