MiniUPnP Project

Home | Downloads | Compatibility list | libnatpmp | MiniSSDPd | xchat upnp patch | Forum

MiniSSDPd

Introduction

Every UPnP device and UPnP client (or control point in UPnP terminology) needs to listen to SSDP packets broadcasted to the multicast group 239.255.255.250 (or FF02::C / FF05::C in IPv6) port 1900. So when several UPnP devices are running on the same computer, or several UPnP control points are trying a discovery process on the same computer, there is concurence to open a socket for listening on the UDP port 1900. Also from the point of view of a control point software, it is usefull to get history of the SSDP NOTIFY packets sent on the network during a few past minutes.

I first coded MiniSSDPd as a small daemon used by MiniUPnPc (a UPnP control point for IGD devices) to speed up device discoveries. MiniSSDPd keep memory of all UPnP devices that announced themselves on the network through SSDP NOTIFY packets.
More recently, some MiniUPnPd (an implementation of a UPnP IDG) users complained about the non-possibility to run MiniUPnPd and MediaTomb (an implementation of a UPnP Media Server) on the same computer because these two piece of software needed to open UDP port 1900. I then added to MiniSSDPd the ability to handle all SSDP traffic recieved on a computer via the multicast group 239.255.255.250:1900. You may be interested in reading this forum thread about all this.

MiniSSDPd receive NOTIFY packets and store information contained for later use by UPnP Control Points on the machine.
MiniSSDPd receive M-SEARCH packets and answer on behalf of the UPnP devices running on the machine.

Running and using MiniSSDPd

Recent versions of MiniUPnPd and MiniUPnPc are designed to take automaticaly advantage of MiniSSDPd running on the same computer. Juste make sure that MiniSSDPd is started before any other UPnP program on the computer.
Other software must be patched in order to take advantage of MiniSSDPd. I made a pach for MediaTomb which add the Device in MiniSSDPd : mediatomb_minissdp-20081006.patch. More recently I made a patch for MiniDLNA : minidlna_1.0.18_minissdp1.patch.

Using MiniSSDPd in your program

Communication with a running MiniSSDPd process is done through a Unix socket. The path of this socket is usually /var/run/minissdpd.sock. Here is some sample code to open a unix socket :
  struct sockaddr_un addr;
  int s;
  const char * minissdpdsocketpath = "/var/run/minissdpd.sock";

  s = socket(AF_UNIX, SOCK_STREAM, 0);
  if(s < 0) {
    // ERROR
  }
  addr.sun_family = AF_UNIX;
  strncpy(addr.sun_path, minissdpdsocketpath, sizeof(addr.sun_path));
  if(connect(s, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0) {
    // ERROR
  }

  [...]

  close(s);

Request are sent to the Unix socket. The first byte of the request is the request type.
Strings sent or recieved are not zero-terminated but prefixed by their length in a variable length format. Use following macros to encode and decode to this format :

/* Encode length by using 7bit per Byte :
 * Most significant bit of each byte specifies that the
 * following byte is part of the code */
#define DECODELENGTH(n, p) n = 0; \
                           do { n = (n << 7) | (*p & 0x7f); } \
                           while(*(p++)&0x80);

#define CODELENGTH(n, p) if(n>=268435456) *(p++) = (n >> 28) | 0x80; \
                         if(n>=2097152) *(p++) = (n >> 21) | 0x80; \
                         if(n>=16384) *(p++) = (n >> 14) | 0x80; \
                         if(n>=128) *(p++) = (n >> 7) | 0x80; \
                         *(p++) = n & 0x7f;

Control Points request (request type 1, 2 and 3)

A control point sends one of these requests to MiniSSDPd in order to receive a list of UPnP devices and services meeting the requirements. The request type byte is followed by a string (an empty string for type 3). Request types :

  1. request by device/service type
  2. request by USN (unique id)
  3. request all services/devices
  unsigned char buffer[2048];
  unsigned char * p;
  const char * device = "urn:schemas-upnp-org:device:InternetGatewayDevice:1";
  int device_len = (int)strlen(device);

  buffer[0] = 1; /* request type 1 : request devices/services by type */
  p = buffer + 1;
  CODELENGTH(device_len, p);
  memcpy(p, device, device_len);
  p += device_len;
  write(socket, buffer, p - buffer);

For these three request types, the responses is as following :

UPnP Device submit (request type 4)

These "request" type is used by UPnP devices that declare themselves and their services that way. The first byte is 4 and is followed by four Strings :

  1. Service/device type
  2. USN
  3. Server string (as found in SSDP packets)
  4. Location

There is no response.

Thomas Bernard
Use the forum or contact me by email: miniupnp _AT_ free _DOT_ fr

Valid XHTML 1.0 Transitional Valid CSS! freshmeat.net