diff options
author | Felix Lange <fjl@twurst.com> | 2015-02-17 20:10:11 +0800 |
---|---|---|
committer | Felix Lange <fjl@twurst.com> | 2015-02-17 20:10:11 +0800 |
commit | f965f41b6e8d177f4f06a8421ee071350813a1ac (patch) | |
tree | 1ca45238447aecf08ae50f322a42526a1302e759 /Godeps/_workspace/src/github.com/huin/goupnp/goupnp.go | |
parent | 119bea22aaf061d5b3e6a9abee9b1b95655b9fbe (diff) | |
download | go-tangerine-f965f41b6e8d177f4f06a8421ee071350813a1ac.tar go-tangerine-f965f41b6e8d177f4f06a8421ee071350813a1ac.tar.gz go-tangerine-f965f41b6e8d177f4f06a8421ee071350813a1ac.tar.bz2 go-tangerine-f965f41b6e8d177f4f06a8421ee071350813a1ac.tar.lz go-tangerine-f965f41b6e8d177f4f06a8421ee071350813a1ac.tar.xz go-tangerine-f965f41b6e8d177f4f06a8421ee071350813a1ac.tar.zst go-tangerine-f965f41b6e8d177f4f06a8421ee071350813a1ac.zip |
p2p/nat: switch to github.com/huin/goupnp
My temporary fix was merged upstream.
Diffstat (limited to 'Godeps/_workspace/src/github.com/huin/goupnp/goupnp.go')
-rw-r--r-- | Godeps/_workspace/src/github.com/huin/goupnp/goupnp.go | 109 |
1 files changed, 109 insertions, 0 deletions
diff --git a/Godeps/_workspace/src/github.com/huin/goupnp/goupnp.go b/Godeps/_workspace/src/github.com/huin/goupnp/goupnp.go new file mode 100644 index 000000000..120b92444 --- /dev/null +++ b/Godeps/_workspace/src/github.com/huin/goupnp/goupnp.go @@ -0,0 +1,109 @@ +// goupnp is an implementation of a client for various UPnP services. +// +// For most uses, it is recommended to use the code-generated packages under +// github.com/huin/goupnp/dcps. Example use is shown at +// http://godoc.org/github.com/huin/goupnp/example +// +// A commonly used client is internetgateway1.WANPPPConnection1: +// http://godoc.org/github.com/huin/goupnp/dcps/internetgateway1#WANPPPConnection1 +// +// Currently only a couple of schemas have code generated for them from the +// UPnP example XML specifications. Not all methods will work on these clients, +// because the generated stubs contain the full set of specified methods from +// the XML specifications, and the discovered services will likely support a +// subset of those methods. +package goupnp + +import ( + "encoding/xml" + "fmt" + "net/http" + "net/url" + + "github.com/huin/goupnp/httpu" + "github.com/huin/goupnp/ssdp" +) + +// ContextError is an error that wraps an error with some context information. +type ContextError struct { + Context string + Err error +} + +func (err ContextError) Error() string { + return fmt.Sprintf("%s: %v", err.Context, err.Err) +} + +// MaybeRootDevice contains either a RootDevice or an error. +type MaybeRootDevice struct { + Root *RootDevice + Err error +} + +// DiscoverDevices attempts to find targets of the given type. This is +// typically the entry-point for this package. searchTarget is typically a URN +// in the form "urn:schemas-upnp-org:device:..." or +// "urn:schemas-upnp-org:service:...". A single error is returned for errors +// while attempting to send the query. An error or RootDevice is returned for +// each discovered RootDevice. +func DiscoverDevices(searchTarget string) ([]MaybeRootDevice, error) { + httpu, err := httpu.NewHTTPUClient() + if err != nil { + return nil, err + } + defer httpu.Close() + responses, err := ssdp.SSDPRawSearch(httpu, string(searchTarget), 2, 3) + if err != nil { + return nil, err + } + + results := make([]MaybeRootDevice, len(responses)) + for i, response := range responses { + maybe := &results[i] + loc, err := response.Location() + if err != nil { + + maybe.Err = ContextError{"unexpected bad location from search", err} + continue + } + locStr := loc.String() + root := new(RootDevice) + if err := requestXml(locStr, DeviceXMLNamespace, root); err != nil { + maybe.Err = ContextError{fmt.Sprintf("error requesting root device details from %q", locStr), err} + continue + } + var urlBaseStr string + if root.URLBaseStr != "" { + urlBaseStr = root.URLBaseStr + } else { + urlBaseStr = locStr + } + urlBase, err := url.Parse(urlBaseStr) + if err != nil { + maybe.Err = ContextError{fmt.Sprintf("error parsing location URL %q", locStr), err} + continue + } + root.SetURLBase(urlBase) + maybe.Root = root + } + + return results, nil +} + +func requestXml(url string, defaultSpace string, doc interface{}) error { + resp, err := http.Get(url) + if err != nil { + return err + } + defer resp.Body.Close() + + if resp.StatusCode != 200 { + return fmt.Errorf("goupnp: got response status %s from %q", + resp.Status, url) + } + + decoder := xml.NewDecoder(resp.Body) + decoder.DefaultSpace = defaultSpace + + return decoder.Decode(doc) +} |