http://en.wikipedia.org/wiki/Simple_Service_Discovery_Protocol%|%From Wikipedia%|%: ''The Simple Service Discovery Protocol (SSDP) is a network protocol based on the Internet Protocol Suite for advertisement and discovery of network services and presence information. It accomplishes this without assistance of server-based configuration mechanisms, such as the Dynamic Host Configuration Protocol (DHCP) or the Domain Name System (DNS), and without special static configuration of a network host. SSDP is the basis of the discovery protocol of Universal Plug and Play and is intended for use in residential or small office environments. It was formally described in an IETF Internet draft by Microsoft and Hewlett-Packard in 1999. Although the IETF proposal has since expired, SSDP was incorporated into the UPnP protocol stack, and a description of the final implementation is included in UPnP standards documents.'' ---- [FB] Here is a small SSDP package that I wrote for a UPnP media server of mine ("Mediatheque", just change the `ssdp::Server` variable to whatever you choose). The code is quite simple: it creates a UDP multicast socket on the well known SSDP address and port 239.255.255.250:1900, posts periodic alive messages and listens to incoming discovery requests on its advertised services: ====== # # ssdp.tcl -- # # SSDP handling. Note that only features needed by this application are # supported, this is not a generic SSDP package although it can serve as # a basis for implementing one. # # SSDP uses HTTPU messages on the multicast UDP address 239.255.255.250:1900 # UPNP uses SSDP for service announcement and discovery. # # This package uses a single UDP socket provided by the Tcl udp extension. # Minimal version is 1.0.9 for address reuse support (SO_REUSEADDR) because # several applications (clients or servers) may open this address on the same # machine. # # TODO: at present the udp package doesn't support binding to specific # interfaces, so we have to specify the advertised device addresses manually. # package require udp 1.0.9 namespace eval ssdp { variable Server "Mediatheque" # Refresh interval. variable Refresh 1800 # # log -- # # Simple logging. # proc log {sock message} { puts "\[[clock format [clock seconds] -format %Y%m%d\ %H:%M:%S]\] ($sock) $message" } # # start -- # # Starts SSDP listening and announcement. This creates the socket and # a fileevent for incoming message handling. # # Parameters: # - addresses: List of HTTP device addresses to advertise. # - port: HTTP port of device. # - path: Path of the device description file. # - udn: UDN of the provided device. # - services: List of provided service types. # proc start {addresses port path udn services} { # Remember parameters. variable Addresses $addresses variable Port $port variable Path $path variable Udn $udn variable Services $services # Open SSDP socket. This will stay open until a call to stop. variable Sock [udp_open 1900 reuse] fconfigure $Sock -translation crlf -buffering none fconfigure $Sock -mcastadd 239.255.255.250 fileevent $Sock readable [namespace code incoming] # Send announcement periodically. announce } # # stop -- # # Stops SSDP listening and announcement. # proc stop {} { variable Services # Cancel the announcement event. after cancel [namespace code announce] # Send byebye messages. byebye upnp:rootdevice byebye {} foreach serviceType $Services { byebye $serviceType } } # # announce -- # # Send alive messages periodically. # proc announce {} { variable Services variable Refresh # Send alive messages. alive upnp:rootdevice alive {} foreach serviceType $Services { alive $serviceType } # Reschedule event. after [expr {$Refresh*1000}] [namespace code announce] } # # incoming -- # # Handle incoming HTTPU messages. Respond to discovery requests for one # of the provided services. # proc incoming {} { variable Sock variable Services # Read UDP datagram. set message [read $Sock] set peer [fconfigure $Sock -peer] log $Sock "SSDP message from [join $peer :] <= 0} { log $Sock "Scheduling response to [join $peer :] for service $serviceType" # Randomize response delay between 0 and MX seconds. if {[catch {set mx [dict get $headers mx]}]} {set mx 0} after [expr {int(rand()*1000*$mx)}] [namespace code [list respond $peer $serviceType]] } } } } } # # respond - # # Respond to incoming discovery requests. # # Parameters: # - peer: Request sender. # - serviceType: Service type from the discovery request. # proc respond {peer serviceType} { variable Sock variable Server variable Refresh variable Port variable Path variable Udn # Get device address to advertise. set s [socket -async [lindex $peer 0] 0] set address [lindex [fconfigure $s -sockname] 0] close $s log $Sock "Responding to [join $peer :] for service $serviceType on interface $address" fconfigure $Sock -remote $peer puts -nonewline $Sock \ "HTTP/1.1 200 OK CACHE-CONTROL: max-age=$Refresh SERVER: $Server EXT: LOCATION: http://$address:$Port$Path ST: $serviceType USN: ${Udn}::$serviceType Content-Length: 0 " } # # notify -- # # Send SSDP notification for a given service type. # # Parameters: # - nts: Message type (e.g. ssdp:alive or ssdp:byebye) # - serviceType: Service type. If empty, notifies device. # proc notify {nts serviceType} { variable Sock variable Refresh variable Addresses variable Port variable Path variable Udn if {$serviceType eq ""} { # Notify device. set nt $Udn set usn $Udn } else { # Notify service. set nt $serviceType set usn ${Udn}::$serviceType } # Send over multicast channel. fconfigure $Sock -remote {239.255.255.250 1900} foreach address $Addresses { # Advertise all device addresses. puts -nonewline $Sock \ "NOTIFY * HTTP/1.1 HOST: 239.255.255.250:1900 CACHE-CONTROL: max-age=$Refresh LOCATION: http://$address:$Port$Path NTS: $nts NT: $nt USN: $usn " } } # Shortcuts for common message types. proc alive {serviceType} {notify ssdp:alive $serviceType} proc byebye {serviceType} {notify ssdp:byebye $serviceType} } ====== Example: ====== package require uuid set udn "uuid:[::uuid::uuid generate]" set addresses [list 192.168.0.1] set port 12345 set path /description.xml set services { urn:schemas-upnp-org:device:MediaServer:1 urn:schemas-upnp-org:service:ContentDirectory:1 urn:schemas-upnp-org:service:ConnectionManager:1 } ssdp::start $addresses $port $path $udn $services ====== This advertises services for a typical UPnP media server, using description file `http://192.168.0.1:12345/description.xml`. You'll also need a HTTP server somewhere to serve this file, especially the description file given by the SSDP LOCATION header (here `http://192.168.0.1:12345/description.xml` but you can use anything as long as it follows the UPnP standard). For my project I use a mini HTTP server adapted from [Embedded TCL Web Server], but any server software will do the job ([TclHttpd], [Apache], http://en.wikipedia.org/wiki/Lighttpd%|%lighttpd%|%, whatever), so if you have your own HTTP server already up & running somewhere, just use its address here. ---- !!!!!! %| [Category Networking] |%