75 lines
2.2 KiB
Racket
75 lines
2.2 KiB
Racket
#lang racket/base
|
|
|
|
;; Network helpers used by UPnP and SSDP.
|
|
|
|
(require racket/list
|
|
racket/string
|
|
racket/udp
|
|
simple-log)
|
|
|
|
(provide upnp-default-ipv4-address)
|
|
|
|
(sl-def-log upnp-network)
|
|
|
|
;; These destinations are only used to make the operating system select its
|
|
;; normal outbound IPv4 route. UDP connect does not transmit a datagram.
|
|
(define route-probes
|
|
'(("1.1.1.1" 53)
|
|
("8.8.8.8" 53)))
|
|
|
|
(define (loopback-ipv4-address? address)
|
|
(string-prefix? address "127."))
|
|
|
|
(define (usable-ipv4-address? address)
|
|
(and (string? address)
|
|
(not (string=? address "0.0.0.0"))
|
|
(not (loopback-ipv4-address? address))))
|
|
|
|
(define (local-address-for destination port)
|
|
(let ([socket (udp-open-socket destination port)])
|
|
(dynamic-wind
|
|
void
|
|
(lambda ()
|
|
(udp-connect! socket destination port)
|
|
(define-values (local-address local-port remote-address remote-port)
|
|
(udp-addresses socket #t))
|
|
local-address)
|
|
(lambda ()
|
|
(udp-close socket)))))
|
|
|
|
;; Return the local non-loopback IPv4 address selected by the operating system
|
|
;; for normal outbound traffic. This is also the interface normally suitable
|
|
;; for SSDP multicast. No datagram is transmitted.
|
|
(define (upnp-default-ipv4-address)
|
|
(or
|
|
(for/or ([probe (in-list route-probes)])
|
|
(define destination (first probe))
|
|
(define port (second probe))
|
|
(with-handlers
|
|
([exn:fail?
|
|
(lambda (exception)
|
|
(dbg-upnp-network
|
|
"Could not determine local IPv4 address using route to ~a:~a: ~a"
|
|
destination
|
|
port
|
|
(exn-message exception))
|
|
#f)])
|
|
(define address (local-address-for destination port))
|
|
(cond
|
|
[(usable-ipv4-address? address)
|
|
(dbg-upnp-network
|
|
"Selected UPnP IPv4 address ~a using route to ~a:~a"
|
|
address
|
|
destination
|
|
port)
|
|
address]
|
|
[else
|
|
(dbg-upnp-network
|
|
"Rejected unusable local IPv4 address ~a selected for route to ~a:~a"
|
|
address
|
|
destination
|
|
port)
|
|
#f])))
|
|
(error 'upnp-default-ipv4-address
|
|
"could not determine a non-loopback IPv4 address")))
|