2020-05-10 11:36:36 +00:00
|
|
|
package goupnp
|
|
|
|
|
|
|
|
import (
|
|
|
|
"io"
|
|
|
|
"net"
|
|
|
|
|
2022-11-01 19:02:13 +00:00
|
|
|
"git.cyrilix.bzh/cyrilix/goupnp/httpu"
|
2020-05-10 11:36:36 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// httpuClient creates a HTTPU client that multiplexes to all multicast-capable
|
|
|
|
// IPv4 addresses on the host. Returns a function to clean up once the client is
|
|
|
|
// no longer required.
|
2023-08-22 01:38:33 +00:00
|
|
|
func httpuClient() (httpu.ClientInterfaceCtx, func(), error) {
|
2020-05-10 11:36:36 +00:00
|
|
|
addrs, err := localIPv4MCastAddrs()
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, ctxError(err, "requesting host IPv4 addresses")
|
|
|
|
}
|
|
|
|
|
|
|
|
closers := make([]io.Closer, 0, len(addrs))
|
2023-08-22 01:38:33 +00:00
|
|
|
delegates := make([]httpu.ClientInterfaceCtx, 0, len(addrs))
|
2020-05-10 11:36:36 +00:00
|
|
|
for _, addr := range addrs {
|
|
|
|
c, err := httpu.NewHTTPUClientAddr(addr)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, ctxErrorf(err,
|
|
|
|
"creating HTTPU client for address %s", addr)
|
|
|
|
}
|
|
|
|
closers = append(closers, c)
|
|
|
|
delegates = append(delegates, c)
|
|
|
|
}
|
|
|
|
|
|
|
|
closer := func() {
|
|
|
|
for _, c := range closers {
|
|
|
|
c.Close()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-22 01:38:33 +00:00
|
|
|
return httpu.NewMultiClientCtx(delegates), closer, nil
|
2020-05-10 11:36:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// localIPv2MCastAddrs returns the set of IPv4 addresses on multicast-able
|
|
|
|
// network interfaces.
|
|
|
|
func localIPv4MCastAddrs() ([]string, error) {
|
|
|
|
ifaces, err := net.Interfaces()
|
|
|
|
if err != nil {
|
|
|
|
return nil, ctxError(err, "requesting host interfaces")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find the set of addresses to listen on.
|
|
|
|
var addrs []string
|
|
|
|
for _, iface := range ifaces {
|
2021-03-10 07:20:16 +00:00
|
|
|
if iface.Flags&net.FlagMulticast == 0 || iface.Flags&net.FlagLoopback != 0 || iface.Flags&net.FlagUp == 0 {
|
2020-05-31 11:15:43 +00:00
|
|
|
// Does not support multicast or is a loopback address.
|
2020-05-10 11:36:36 +00:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
ifaceAddrs, err := iface.Addrs()
|
|
|
|
if err != nil {
|
|
|
|
return nil, ctxErrorf(err,
|
|
|
|
"finding addresses on interface %s", iface.Name)
|
|
|
|
}
|
|
|
|
for _, netAddr := range ifaceAddrs {
|
|
|
|
addr, ok := netAddr.(*net.IPNet)
|
|
|
|
if !ok {
|
|
|
|
// Not an IPNet address.
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if addr.IP.To4() == nil {
|
|
|
|
// Not IPv4.
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
addrs = append(addrs, addr.IP.String())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return addrs, nil
|
|
|
|
}
|