#lang scribble/manual @(require (for-label racket/base racket/contract (file "../main.rkt"))) @title{UPnP Devices and Services} @defmodule[racket-upnp] The main module provides general UPnP device discovery and a generic service interface. @section{Discovering devices} @defproc[(upnp-default-ipv4-address) string?]{ Returns a non-loopback local IPv4 address selected by the operating system for normal outbound IPv4 traffic. No datagram is sent. The selected address is normally also the interface through which SSDP multicast should be sent. Loopback and wildcard addresses are rejected. } @defproc[(query-upnp-devices [kinds (or/c 'all symbol? (listof symbol?)) 'all] [#:interface interface (or/c #f string?) #f] [#:dns? dns? boolean? #f] [#:mx mx (integer-in 1 5) 3] [#:timeout timeout (or/c #f positive-real?) #f] [#:repeat repeat exact-positive-integer? 3]) (listof upnp-device?)]{ Discovers and describes matching UPnP devices. @racket['all] returns all described devices. A symbol such as @racket['media-renderer] selects one known kind, and a list selects several kinds. When @racket[interface] is a local IPv4 address, SSDP multicast is sent through that interface. When it is @racket[#f], @racket[upnp-default-ipv4-address] is used automatically. If automatic detection fails, discovery falls back to the interface selected by the operating system. Reverse DNS lookup is only attempted when @racket[dns?] is true. @racket[mx] is the SSDP response delay advertised in the M-SEARCH request. The default receive window is @racket[mx] plus one second. An explicit @racket[timeout] overrides that receive window and must be at least @racket[mx]. @racket[repeat] controls how many M-SEARCH requests are sent; the requests are spaced 250 milliseconds apart. } @defproc[(upnp-device-kinds) (listof (cons/c symbol? string?))]{ Returns the friendly device kinds understood by @racket[query-upnp-devices], together with short descriptions. Devices with an unrecognised device type are classified as @racket['unknown] and retain their original UPnP type. } @section{Device values} @defproc[(upnp-device? [value any/c]) boolean?]{Recognises a described UPnP device.} @defproc[(upnp-device-kind [device upnp-device?]) symbol?]{Returns a friendly kind such as @racket['media-renderer], @racket['scanner], or @racket['unknown].} @defproc[(upnp-device-name [device upnp-device?]) string?]{Returns the friendly name, with model name and address as fallbacks.} @defproc[(upnp-device-udn [device upnp-device?]) (or/c #f string?)]{Returns the Unique Device Name from the device description.} @defproc[(upnp-device-address [device upnp-device?]) string?]{Returns the address from which the SSDP response was received.} @defproc[(upnp-device-dns-name [device upnp-device?]) (or/c #f string?)]{Returns the optional reverse-DNS name.} @defproc[(upnp-device-manufacturer [device upnp-device?]) (or/c #f string?)]{Returns the advertised manufacturer.} @defproc[(upnp-device-model [device upnp-device?]) (or/c #f string?)]{Returns a combined model name and model number.} @defproc[(upnp-device-type [device upnp-device?]) (or/c #f string?)]{Returns the original device-type URN.} @defproc[(upnp-device-services [device upnp-device?]) (listof upnp-service?)]{Returns the services belonging directly to the device.} @section{Generic services} @defproc[(upnp-service? [value any/c]) boolean?]{Recognises a UPnP service.} @defproc[(upnp-service-kind [service upnp-service?]) symbol?]{Returns a friendly service kind or @racket['unknown].} @defproc[(upnp-service-type [service upnp-service?]) (or/c #f string?)]{Returns the original service-type URN.} @defproc[(upnp-service-id [service upnp-service?]) (or/c #f string?)]{Returns the advertised service identifier.} @defproc[(upnp-service-kinds) (listof (cons/c symbol? string?))]{Returns the known friendly service kinds and descriptions.} @defproc[(upnp-device-service [device upnp-device?] [kind symbol?]) (or/c #f upnp-service?)]{ Returns the highest advertised version of the requested service kind belonging to @racket[device], or @racket[#f] when the service is absent. } @defproc[(upnp-service-actions [service upnp-service?]) (listof string?)]{ Downloads the service's SCPD document and returns its advertised action names. The result is cached for the service value. } @defproc[(upnp-service-supports-action? [service upnp-service?] [action (or/c string? symbol?)]) boolean?]{ Reports whether the SCPD advertises @racket[action]. } @defproc[(upnp-service-call [service upnp-service?] [action (or/c string? symbol?)] [arguments list? '()]) hash?]{ Invokes a SOAP action. @racket[arguments] is an association list containing UPnP argument names and values. The immutable result hash uses the exact output argument names as string keys. This function is intended for vendor-specific services and standard services for which no typed module has been written. A failed SOAP request raises @racket[exn:fail:upnp?]. } @defproc[(exn:fail:upnp? [value any/c]) boolean?]{Recognises a UPnP SOAP error.} @defproc[(exn:fail:upnp-code [error exn:fail:upnp?]) (or/c #f exact-integer?)]{Returns the numeric UPnP error code, when supplied by the device.} @defproc[(exn:fail:upnp-description [error exn:fail:upnp?]) (or/c #f string?)]{Returns the UPnP error description, when supplied by the device.} @section[#:tag "device-discovery-example"]{Example} @racketblock[ (define renderers (query-upnp-devices 'media-renderer #:interface "10.7.3.118" #:dns? #t)) (for ([device (in-list renderers)]) (printf "~a (~a)\n" (upnp-device-name device) (upnp-device-address device))) ]