UPnP/SSDP: Worker, ping Manager URLs in parallel

Ping all Manager URLs at once, and wait until they've all responded (or
caused an error), instead of pinging them one by one sequentially.
This commit is contained in:
Sybren A. Stüvel 2022-03-08 14:25:44 +01:00
parent 9761786982
commit 8e05024267

View File

@ -11,6 +11,7 @@ import (
"os" "os"
"os/signal" "os/signal"
"runtime" "runtime"
"sync"
"syscall" "syscall"
"time" "time"
@ -226,29 +227,53 @@ func autodiscoverManager(ctx context.Context) (string, error) {
} }
// Try out the URLs to see which one responds. // Try out the URLs to see which one responds.
// TODO: parallelise this. startTime := time.Now()
usableURLs := make([]string, 0) numUsableURLs := 0
for _, url := range urls { wg := new(sync.WaitGroup)
if pingManager(ctx, url) { wg.Add(len(urls))
usableURLs = append(usableURLs, url) mutex := new(sync.Mutex)
} for idx, url := range urls {
} go func(idx int, url string) {
defer wg.Done()
ok := pingManager(ctx, url)
switch len(usableURLs) { mutex.Lock()
case 0: defer mutex.Unlock()
if ok {
numUsableURLs++
} else {
// Erase the URL from the usable list.
urls[idx] = ""
}
}(idx, url)
}
wg.Wait()
log.Debug().Str("pingTime", time.Since(startTime).String()).Msg("pinging all Manager URLs done")
if numUsableURLs == 0 {
return "", fmt.Errorf("autodetected %d URLs, but none were usable", len(urls)) return "", fmt.Errorf("autodetected %d URLs, but none were usable", len(urls))
case 1:
log.Info().Str("url", usableURLs[0]).Msg("found Manager")
return usableURLs[0], nil
default:
log.Info().
Strs("urls", usableURLs).
Str("url", usableURLs[0]).
Msg("found multiple usable URLs, using the first one")
return usableURLs[0], nil
} }
// Find the first usable URL.
var firstURL string
for _, url := range urls {
if url != "" {
firstURL = url
break
}
}
if numUsableURLs == 1 {
log.Info().Str("url", firstURL).Msg("found Manager")
} else {
log.Info().
Strs("urls", urls).
Str("url", firstURL).
Msg("found multiple usable URLs, using the first one")
}
return firstURL, nil
} }
// pingManager connects to a Manager and returns true if it responds. // pingManager connects to a Manager and returns true if it responds.