commit
96289f42b7
|
@ -727,7 +727,7 @@ func setupUPnP() {
|
||||||
} else {
|
} else {
|
||||||
// Set up incoming port forwarding, if necessary and possible
|
// Set up incoming port forwarding, if necessary and possible
|
||||||
port, _ := strconv.Atoi(portStr)
|
port, _ := strconv.Atoi(portStr)
|
||||||
igds := upnp.Discover()
|
igds := upnp.Discover(time.Duration(cfg.Options().UPnPTimeoutS) * time.Second)
|
||||||
if len(igds) > 0 {
|
if len(igds) > 0 {
|
||||||
// Configure the first discovered IGD only. This is a work-around until we have a better mechanism
|
// Configure the first discovered IGD only. This is a work-around until we have a better mechanism
|
||||||
// for handling multiple IGDs, which will require changes to the global discovery service
|
// for handling multiple IGDs, which will require changes to the global discovery service
|
||||||
|
@ -739,7 +739,7 @@ func setupUPnP() {
|
||||||
} else {
|
} else {
|
||||||
l.Infof("Created UPnP port mapping for external port %d on UPnP device %s.", externalPort, igd.FriendlyIdentifier())
|
l.Infof("Created UPnP port mapping for external port %d on UPnP device %s.", externalPort, igd.FriendlyIdentifier())
|
||||||
|
|
||||||
if opts.UPnPRenewal > 0 {
|
if opts.UPnPRenewalM > 0 {
|
||||||
go renewUPnP(port)
|
go renewUPnP(port)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -757,7 +757,7 @@ func setupExternalPort(igd *upnp.IGD, port int) int {
|
||||||
|
|
||||||
for i := 0; i < 10; i++ {
|
for i := 0; i < 10; i++ {
|
||||||
r := 1024 + predictableRandom.Intn(65535-1024)
|
r := 1024 + predictableRandom.Intn(65535-1024)
|
||||||
err := igd.AddPortMapping(upnp.TCP, r, port, fmt.Sprintf("syncthing-%d", r), cfg.Options().UPnPLease*60)
|
err := igd.AddPortMapping(upnp.TCP, r, port, fmt.Sprintf("syncthing-%d", r), cfg.Options().UPnPLeaseM*60)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
@ -768,14 +768,16 @@ func setupExternalPort(igd *upnp.IGD, port int) int {
|
||||||
func renewUPnP(port int) {
|
func renewUPnP(port int) {
|
||||||
for {
|
for {
|
||||||
opts := cfg.Options()
|
opts := cfg.Options()
|
||||||
time.Sleep(time.Duration(opts.UPnPRenewal) * time.Minute)
|
time.Sleep(time.Duration(opts.UPnPRenewalM) * time.Minute)
|
||||||
|
// Some values might have changed while we were sleeping
|
||||||
|
opts = cfg.Options()
|
||||||
|
|
||||||
// Make sure our IGD reference isn't nil
|
// Make sure our IGD reference isn't nil
|
||||||
if igd == nil {
|
if igd == nil {
|
||||||
if debugNet {
|
if debugNet {
|
||||||
l.Debugln("Undefined IGD during UPnP port renewal. Re-discovering...")
|
l.Debugln("Undefined IGD during UPnP port renewal. Re-discovering...")
|
||||||
}
|
}
|
||||||
igds := upnp.Discover()
|
igds := upnp.Discover(time.Duration(opts.UPnPTimeoutS) * time.Second)
|
||||||
if len(igds) > 0 {
|
if len(igds) > 0 {
|
||||||
// Configure the first discovered IGD only. This is a work-around until we have a better mechanism
|
// Configure the first discovered IGD only. This is a work-around until we have a better mechanism
|
||||||
// for handling multiple IGDs, which will require changes to the global discovery service
|
// for handling multiple IGDs, which will require changes to the global discovery service
|
||||||
|
@ -790,7 +792,7 @@ func renewUPnP(port int) {
|
||||||
|
|
||||||
// Just renew the same port that we already have
|
// Just renew the same port that we already have
|
||||||
if externalPort != 0 {
|
if externalPort != 0 {
|
||||||
err := igd.AddPortMapping(upnp.TCP, externalPort, port, "syncthing", opts.UPnPLease*60)
|
err := igd.AddPortMapping(upnp.TCP, externalPort, port, "syncthing", opts.UPnPLeaseM*60)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.Warnf("Error renewing UPnP port mapping for external port %d on device %s: %s", externalPort, igd.FriendlyIdentifier(), err.Error())
|
l.Warnf("Error renewing UPnP port mapping for external port %d on device %s: %s", externalPort, igd.FriendlyIdentifier(), err.Error())
|
||||||
} else if debugNet {
|
} else if debugNet {
|
||||||
|
|
|
@ -227,8 +227,9 @@ type OptionsConfiguration struct {
|
||||||
ReconnectIntervalS int `xml:"reconnectionIntervalS" json:"reconnectionIntervalS" default:"60"`
|
ReconnectIntervalS int `xml:"reconnectionIntervalS" json:"reconnectionIntervalS" default:"60"`
|
||||||
StartBrowser bool `xml:"startBrowser" json:"startBrowser" default:"true"`
|
StartBrowser bool `xml:"startBrowser" json:"startBrowser" default:"true"`
|
||||||
UPnPEnabled bool `xml:"upnpEnabled" json:"upnpEnabled" default:"true"`
|
UPnPEnabled bool `xml:"upnpEnabled" json:"upnpEnabled" default:"true"`
|
||||||
UPnPLease int `xml:"upnpLeaseMinutes" json:"upnpLeaseMinutes" default:"0"`
|
UPnPLeaseM int `xml:"upnpLeaseMinutes" json:"upnpLeaseMinutes" default:"0"`
|
||||||
UPnPRenewal int `xml:"upnpRenewalMinutes" json:"upnpRenewalMinutes" default:"30"`
|
UPnPRenewalM int `xml:"upnpRenewalMinutes" json:"upnpRenewalMinutes" default:"30"`
|
||||||
|
UPnPTimeoutS int `xml:"upnpTimeoutSeconds" json:"upnpTimeoutSeconds" default:"3"`
|
||||||
URAccepted int `xml:"urAccepted" json:"urAccepted"` // Accepted usage reporting version; 0 for off (undecided), -1 for off (permanently)
|
URAccepted int `xml:"urAccepted" json:"urAccepted"` // Accepted usage reporting version; 0 for off (undecided), -1 for off (permanently)
|
||||||
URUniqueID string `xml:"urUniqueID" json:"urUniqueId"` // Unique ID for reporting purposes, regenerated when UR is turned on.
|
URUniqueID string `xml:"urUniqueID" json:"urUniqueId"` // Unique ID for reporting purposes, regenerated when UR is turned on.
|
||||||
RestartOnWakeup bool `xml:"restartOnWakeup" json:"restartOnWakeup" default:"true"`
|
RestartOnWakeup bool `xml:"restartOnWakeup" json:"restartOnWakeup" default:"true"`
|
||||||
|
|
|
@ -42,8 +42,9 @@ func TestDefaultValues(t *testing.T) {
|
||||||
ReconnectIntervalS: 60,
|
ReconnectIntervalS: 60,
|
||||||
StartBrowser: true,
|
StartBrowser: true,
|
||||||
UPnPEnabled: true,
|
UPnPEnabled: true,
|
||||||
UPnPLease: 0,
|
UPnPLeaseM: 0,
|
||||||
UPnPRenewal: 30,
|
UPnPRenewalM: 30,
|
||||||
|
UPnPTimeoutS: 3,
|
||||||
RestartOnWakeup: true,
|
RestartOnWakeup: true,
|
||||||
AutoUpgradeIntervalH: 12,
|
AutoUpgradeIntervalH: 12,
|
||||||
KeepTemporariesH: 24,
|
KeepTemporariesH: 24,
|
||||||
|
@ -147,8 +148,9 @@ func TestOverriddenValues(t *testing.T) {
|
||||||
ReconnectIntervalS: 6000,
|
ReconnectIntervalS: 6000,
|
||||||
StartBrowser: false,
|
StartBrowser: false,
|
||||||
UPnPEnabled: false,
|
UPnPEnabled: false,
|
||||||
UPnPLease: 60,
|
UPnPLeaseM: 60,
|
||||||
UPnPRenewal: 15,
|
UPnPRenewalM: 15,
|
||||||
|
UPnPTimeoutS: 15,
|
||||||
RestartOnWakeup: false,
|
RestartOnWakeup: false,
|
||||||
AutoUpgradeIntervalH: 24,
|
AutoUpgradeIntervalH: 24,
|
||||||
KeepTemporariesH: 48,
|
KeepTemporariesH: 48,
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
<upnpEnabled>false</upnpEnabled>
|
<upnpEnabled>false</upnpEnabled>
|
||||||
<upnpLeaseMinutes>60</upnpLeaseMinutes>
|
<upnpLeaseMinutes>60</upnpLeaseMinutes>
|
||||||
<upnpRenewalMinutes>15</upnpRenewalMinutes>
|
<upnpRenewalMinutes>15</upnpRenewalMinutes>
|
||||||
|
<upnpTimeoutSeconds>15</upnpTimeoutSeconds>
|
||||||
<restartOnWakeup>false</restartOnWakeup>
|
<restartOnWakeup>false</restartOnWakeup>
|
||||||
<autoUpgradeIntervalH>24</autoUpgradeIntervalH>
|
<autoUpgradeIntervalH>24</autoUpgradeIntervalH>
|
||||||
<keepTemporariesH>48</keepTemporariesH>
|
<keepTemporariesH>48</keepTemporariesH>
|
||||||
|
|
|
@ -91,44 +91,71 @@ type upnpRoot struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Discover discovers UPnP InternetGatewayDevices.
|
// Discover discovers UPnP InternetGatewayDevices.
|
||||||
// The order in which the devices appear in the result list is not deterministic.
|
// The order in which the devices appear in the results list is not deterministic.
|
||||||
func Discover() []IGD {
|
func Discover(timeout time.Duration) []IGD {
|
||||||
var result []IGD
|
var results []IGD
|
||||||
l.Infoln("Starting UPnP discovery...")
|
l.Infoln("Starting UPnP discovery...")
|
||||||
|
|
||||||
timeout := 3
|
interfaces, err := net.Interfaces()
|
||||||
|
if err != nil {
|
||||||
|
l.Infoln("Listing network interfaces:", err)
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
|
||||||
// Search for InternetGatewayDevice:2 devices
|
resultChan := make(chan IGD, 16)
|
||||||
result = append(result, discover("urn:schemas-upnp-org:device:InternetGatewayDevice:2", timeout, result)...)
|
|
||||||
|
|
||||||
// Search for InternetGatewayDevice:1 devices
|
// Aggregator
|
||||||
// InternetGatewayDevice:2 devices that correctly respond to the IGD:1 request as well will not be re-added to the result list
|
go func() {
|
||||||
result = append(result, discover("urn:schemas-upnp-org:device:InternetGatewayDevice:1", timeout, result)...)
|
next:
|
||||||
|
for result := range resultChan {
|
||||||
if len(result) > 0 && debug {
|
for _, existingResult := range results {
|
||||||
l.Debugln("UPnP discovery result:")
|
if existingResult.uuid == result.uuid {
|
||||||
for _, resultDevice := range result {
|
if debug {
|
||||||
l.Debugln("[" + resultDevice.uuid + "]")
|
l.Debugf("Skipping duplicate result %s with services:", result.uuid)
|
||||||
|
for _, svc := range result.services {
|
||||||
for _, resultService := range resultDevice.services {
|
l.Debugf("* [%s] %s", svc.serviceID, svc.serviceURL)
|
||||||
l.Debugln("* [" + resultService.serviceID + "] " + resultService.serviceURL)
|
}
|
||||||
|
}
|
||||||
|
goto next
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
results = append(results, result)
|
||||||
|
if debug {
|
||||||
|
l.Debugf("UPnP discovery result %s with services:", result.uuid)
|
||||||
|
for _, svc := range result.services {
|
||||||
|
l.Debugf("* [%s] %s", svc.serviceID, svc.serviceURL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
for _, intf := range interfaces {
|
||||||
|
for _, deviceType := range []string{"urn:schemas-upnp-org:device:InternetGatewayDevice:1", "urn:schemas-upnp-org:device:InternetGatewayDevice:2"} {
|
||||||
|
wg.Add(1)
|
||||||
|
go func(intf net.Interface, deviceType string) {
|
||||||
|
discover(&intf, deviceType, timeout, resultChan)
|
||||||
|
wg.Done()
|
||||||
|
}(intf, deviceType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
close(resultChan)
|
||||||
|
|
||||||
suffix := "devices"
|
suffix := "devices"
|
||||||
if len(result) == 1 {
|
if len(results) == 1 {
|
||||||
suffix = "device"
|
suffix = "device"
|
||||||
}
|
}
|
||||||
|
|
||||||
l.Infof("UPnP discovery complete (found %d %s).", len(result), suffix)
|
l.Infof("UPnP discovery complete (found %d %s).", len(results), suffix)
|
||||||
|
|
||||||
return result
|
return results
|
||||||
}
|
}
|
||||||
|
|
||||||
// Search for UPnP InternetGatewayDevices for <timeout> seconds, ignoring responses from any devices listed in knownDevices.
|
// Search for UPnP InternetGatewayDevices for <timeout> seconds, ignoring responses from any devices listed in knownDevices.
|
||||||
// The order in which the devices appear in the result list is not deterministic
|
// The order in which the devices appear in the result list is not deterministic
|
||||||
func discover(deviceType string, timeout int, knownDevices []IGD) []IGD {
|
func discover(intf *net.Interface, deviceType string, timeout time.Duration, results chan<- IGD) {
|
||||||
ssdp := &net.UDPAddr{IP: []byte{239, 255, 255, 250}, Port: 1900}
|
ssdp := &net.UDPAddr{IP: []byte{239, 255, 255, 250}, Port: 1900}
|
||||||
|
|
||||||
tpl := `M-SEARCH * HTTP/1.1
|
tpl := `M-SEARCH * HTTP/1.1
|
||||||
|
@ -138,44 +165,39 @@ Man: "ssdp:discover"
|
||||||
Mx: %d
|
Mx: %d
|
||||||
|
|
||||||
`
|
`
|
||||||
searchStr := fmt.Sprintf(tpl, deviceType, timeout)
|
searchStr := fmt.Sprintf(tpl, deviceType, timeout/time.Second)
|
||||||
|
|
||||||
search := []byte(strings.Replace(searchStr, "\n", "\r\n", -1))
|
search := []byte(strings.Replace(searchStr, "\n", "\r\n", -1))
|
||||||
|
|
||||||
if debug {
|
if debug {
|
||||||
l.Debugln("Starting discovery of device type " + deviceType + "...")
|
l.Debugln("Starting discovery of device type " + deviceType + " on " + intf.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
var results []IGD
|
socket, err := net.ListenMulticastUDP("udp4", intf, &net.UDPAddr{IP: ssdp.IP})
|
||||||
resultChannel := make(chan IGD, 8)
|
|
||||||
|
|
||||||
socket, err := net.ListenMulticastUDP("udp4", nil, &net.UDPAddr{IP: ssdp.IP})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.Infoln(err)
|
l.Infoln(err)
|
||||||
return results
|
return
|
||||||
}
|
}
|
||||||
defer socket.Close() // Make sure our socket gets closed
|
defer socket.Close() // Make sure our socket gets closed
|
||||||
|
|
||||||
err = socket.SetDeadline(time.Now().Add(time.Duration(timeout) * time.Second))
|
err = socket.SetDeadline(time.Now().Add(timeout))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.Infoln(err)
|
l.Infoln(err)
|
||||||
return results
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if debug {
|
if debug {
|
||||||
l.Debugln("Sending search request for device type " + deviceType + "...")
|
l.Debugln("Sending search request for device type " + deviceType + " on " + intf.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
var resultWaitGroup sync.WaitGroup
|
|
||||||
|
|
||||||
_, err = socket.WriteTo(search, ssdp)
|
_, err = socket.WriteTo(search, ssdp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.Infoln(err)
|
l.Infoln(err)
|
||||||
return results
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if debug {
|
if debug {
|
||||||
l.Debugln("Listening for UPnP response for device type " + deviceType + "...")
|
l.Debugln("Listening for UPnP response for device type " + deviceType + " on " + intf.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Listen for responses until a timeout is reached
|
// Listen for responses until a timeout is reached
|
||||||
|
@ -186,67 +208,40 @@ Mx: %d
|
||||||
if e, ok := err.(net.Error); !ok || !e.Timeout() {
|
if e, ok := err.(net.Error); !ok || !e.Timeout() {
|
||||||
l.Infoln(err) //legitimate error, not a timeout.
|
l.Infoln(err) //legitimate error, not a timeout.
|
||||||
}
|
}
|
||||||
|
|
||||||
break
|
break
|
||||||
} else {
|
|
||||||
// Process results in a separate go routine so we can immediately return to listening for more responses
|
|
||||||
resultWaitGroup.Add(1)
|
|
||||||
go handleSearchResponse(deviceType, knownDevices, resp, n, resultChannel, &resultWaitGroup)
|
|
||||||
}
|
}
|
||||||
}
|
igd, err := parseResponse(deviceType, resp[:n])
|
||||||
|
if err != nil {
|
||||||
// Wait for all result handlers to finish processing, then close result channel
|
l.Infoln(err)
|
||||||
resultWaitGroup.Wait()
|
continue
|
||||||
close(resultChannel)
|
|
||||||
|
|
||||||
// Collect our results from the result handlers using the result channel
|
|
||||||
for result := range resultChannel {
|
|
||||||
// Check for existing results (some routers send multiple response packets)
|
|
||||||
for _, existingResult := range results {
|
|
||||||
if existingResult.uuid == result.uuid {
|
|
||||||
if debug {
|
|
||||||
l.Debugln("Already processed device with UUID", existingResult.uuid, "continuing...")
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
results <- igd
|
||||||
// No existing results, okay to append
|
|
||||||
results = append(results, result)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if debug {
|
if debug {
|
||||||
l.Debugln("Discovery for device type " + deviceType + " finished.")
|
l.Debugln("Discovery for device type " + deviceType + " on " + intf.Name + " finished.")
|
||||||
}
|
}
|
||||||
|
|
||||||
return results
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleSearchResponse(deviceType string, knownDevices []IGD, resp []byte, length int, resultChannel chan<- IGD, resultWaitGroup *sync.WaitGroup) {
|
func parseResponse(deviceType string, resp []byte) (IGD, error) {
|
||||||
defer resultWaitGroup.Done() // Signal when we've finished processing
|
|
||||||
|
|
||||||
if debug {
|
if debug {
|
||||||
l.Debugln("Handling UPnP response:\n\n" + string(resp[:length]))
|
l.Debugln("Handling UPnP response:\n\n" + string(resp))
|
||||||
}
|
}
|
||||||
|
|
||||||
reader := bufio.NewReader(bytes.NewBuffer(resp[:length]))
|
reader := bufio.NewReader(bytes.NewBuffer(resp))
|
||||||
request := &http.Request{}
|
request := &http.Request{}
|
||||||
response, err := http.ReadResponse(reader, request)
|
response, err := http.ReadResponse(reader, request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.Infoln(err)
|
return IGD{}, err
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
respondingDeviceType := response.Header.Get("St")
|
respondingDeviceType := response.Header.Get("St")
|
||||||
if respondingDeviceType != deviceType {
|
if respondingDeviceType != deviceType {
|
||||||
l.Infoln("Unrecognized UPnP device of type " + respondingDeviceType)
|
return IGD{}, errors.New("unrecognized UPnP device of type " + respondingDeviceType)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
deviceDescriptionLocation := response.Header.Get("Location")
|
deviceDescriptionLocation := response.Header.Get("Location")
|
||||||
if deviceDescriptionLocation == "" {
|
if deviceDescriptionLocation == "" {
|
||||||
l.Infoln("Invalid IGD response: no location specified.")
|
return IGD{}, errors.New("invalid IGD response: no location specified.")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
deviceDescriptionURL, err := url.Parse(deviceDescriptionLocation)
|
deviceDescriptionURL, err := url.Parse(deviceDescriptionLocation)
|
||||||
|
@ -257,8 +252,7 @@ func handleSearchResponse(deviceType string, knownDevices []IGD, resp []byte, le
|
||||||
|
|
||||||
deviceUSN := response.Header.Get("USN")
|
deviceUSN := response.Header.Get("USN")
|
||||||
if deviceUSN == "" {
|
if deviceUSN == "" {
|
||||||
l.Infoln("Invalid IGD response: USN not specified.")
|
return IGD{}, errors.New("invalid IGD response: USN not specified.")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
deviceUUID := strings.TrimLeft(strings.Split(deviceUSN, "::")[0], "uuid:")
|
deviceUUID := strings.TrimLeft(strings.Split(deviceUSN, "::")[0], "uuid:")
|
||||||
|
@ -267,39 +261,25 @@ func handleSearchResponse(deviceType string, knownDevices []IGD, resp []byte, le
|
||||||
l.Infoln("Invalid IGD response: invalid device UUID", deviceUUID, "(continuing anyway)")
|
l.Infoln("Invalid IGD response: invalid device UUID", deviceUUID, "(continuing anyway)")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't re-add devices that are already known
|
|
||||||
for _, knownDevice := range knownDevices {
|
|
||||||
if deviceUUID == knownDevice.uuid {
|
|
||||||
if debug {
|
|
||||||
l.Debugln("Ignoring known device with UUID " + deviceUUID)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
response, err = http.Get(deviceDescriptionLocation)
|
response, err = http.Get(deviceDescriptionLocation)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.Infoln(err)
|
return IGD{}, err
|
||||||
return
|
|
||||||
}
|
}
|
||||||
defer response.Body.Close()
|
defer response.Body.Close()
|
||||||
|
|
||||||
if response.StatusCode >= 400 {
|
if response.StatusCode >= 400 {
|
||||||
l.Infoln(errors.New(response.Status))
|
return IGD{}, errors.New("bad status code:" + response.Status)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var upnpRoot upnpRoot
|
var upnpRoot upnpRoot
|
||||||
err = xml.NewDecoder(response.Body).Decode(&upnpRoot)
|
err = xml.NewDecoder(response.Body).Decode(&upnpRoot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.Infoln(err)
|
return IGD{}, err
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
services, err := getServiceDescriptions(deviceDescriptionLocation, upnpRoot.Device)
|
services, err := getServiceDescriptions(deviceDescriptionLocation, upnpRoot.Device)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.Infoln(err)
|
return IGD{}, err
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Figure out our IP number, on the network used to reach the IGD.
|
// Figure out our IP number, on the network used to reach the IGD.
|
||||||
|
@ -308,23 +288,16 @@ func handleSearchResponse(deviceType string, knownDevices []IGD, resp []byte, le
|
||||||
// suggestions on a better way to do this...
|
// suggestions on a better way to do this...
|
||||||
localIPAddress, err := localIP(deviceDescriptionURL)
|
localIPAddress, err := localIP(deviceDescriptionURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.Infoln(err)
|
return IGD{}, err
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
igd := IGD{
|
return IGD{
|
||||||
uuid: deviceUUID,
|
uuid: deviceUUID,
|
||||||
friendlyName: upnpRoot.Device.FriendlyName,
|
friendlyName: upnpRoot.Device.FriendlyName,
|
||||||
url: deviceDescriptionURL,
|
url: deviceDescriptionURL,
|
||||||
services: services,
|
services: services,
|
||||||
localIPAddress: localIPAddress,
|
localIPAddress: localIPAddress,
|
||||||
}
|
}, nil
|
||||||
|
|
||||||
resultChannel <- igd
|
|
||||||
|
|
||||||
if debug {
|
|
||||||
l.Debugln("Finished handling of UPnP response.")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func localIP(url *url.URL) (string, error) {
|
func localIP(url *url.URL) (string, error) {
|
||||||
|
|
Loading…
Reference in New Issue