From 1df6589533ecff0b38a56a8092f7e2ef541634c1 Mon Sep 17 00:00:00 2001 From: Lode Hoste Date: Thu, 21 May 2015 09:54:39 +0200 Subject: [PATCH 1/2] Add status code to SOAP response --- internal/upnp/upnp.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/upnp/upnp.go b/internal/upnp/upnp.go index b8d9759f3..0d1cf1d9f 100644 --- a/internal/upnp/upnp.go +++ b/internal/upnp/upnp.go @@ -471,7 +471,7 @@ func soapRequest(url, service, function, message string) ([]byte, error) { resp, _ = ioutil.ReadAll(r.Body) if debug { - l.Debugln("SOAP Response:\n\n" + string(resp) + "\n") + l.Debugf("SOAP Response: %v\n\n%v\n\n", r.StatusCode, string(resp)) } r.Body.Close() From 50422482605d1ce9ca876c720662adc836a2eb69 Mon Sep 17 00:00:00 2001 From: Lode Hoste Date: Thu, 21 May 2015 09:55:55 +0200 Subject: [PATCH 2/2] Set permanent UPnP lease when required (fixes #1831) --- internal/upnp/upnp.go | 21 +++++++++++++++++---- internal/upnp/upnp_test.go | 27 +++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/internal/upnp/upnp.go b/internal/upnp/upnp.go index 0d1cf1d9f..731738468 100644 --- a/internal/upnp/upnp.go +++ b/internal/upnp/upnp.go @@ -527,6 +527,11 @@ type getExternalIPAddressResponse struct { NewExternalIPAddress string `xml:"NewExternalIPAddress"` } +type soapErrorResponse struct { + ErrorCode int `xml:"Body>Fault>detail>UPnPError>errorCode"` + ErrorDescription string `xml:"Body>Fault>detail>UPnPError>errorDescription"` +} + // AddPortMapping adds a port mapping to the specified IGD service. func (s *IGDService) AddPortMapping(localIPAddress string, protocol Protocol, externalPort, internalPort int, description string, timeout int) error { tpl := ` @@ -541,12 +546,20 @@ func (s *IGDService) AddPortMapping(localIPAddress string, protocol Protocol, ex ` body := fmt.Sprintf(tpl, s.serviceURN, externalPort, protocol, internalPort, localIPAddress, description, timeout) - _, err := soapRequest(s.serviceURL, s.serviceURN, "AddPortMapping", body) - if err != nil { - return err + response, err := soapRequest(s.serviceURL, s.serviceURN, "AddPortMapping", body) + if err != nil && timeout > 0 { + // Try to repair error code 725 - OnlyPermanentLeasesSupported + envelope := &soapErrorResponse{} + err = xml.Unmarshal(response, envelope) + if err != nil { + return err + } + if envelope.ErrorCode == 725 { + return s.AddPortMapping(localIPAddress, protocol, externalPort, internalPort, description, 0) + } } - return nil + return err } // DeletePortMapping deletes a port mapping from the specified IGD service. diff --git a/internal/upnp/upnp_test.go b/internal/upnp/upnp_test.go index e5941dd44..4ce521151 100644 --- a/internal/upnp/upnp_test.go +++ b/internal/upnp/upnp_test.go @@ -33,6 +33,33 @@ func TestExternalIPParsing(t *testing.T) { } } +func TestSoapFaultParsing(t *testing.T) { + soapResponse := + []byte(` + + + s:Client + UPnPError + + + 725 + OnlyPermanentLeasesSupported + + + + `) + + envelope := &soapErrorResponse{} + err := xml.Unmarshal(soapResponse, envelope) + if err != nil { + t.Error(err) + } + + if envelope.ErrorCode != 725 { + t.Error("Parse of SOAP request failed.", envelope) + } +} + func TestControlURLParsing(t *testing.T) { rootURL := "http://192.168.243.1:80/igd.xml"