diff --git a/goupnp.go b/goupnp.go index 36081aa..51963de 100644 --- a/goupnp.go +++ b/goupnp.go @@ -18,10 +18,12 @@ import ( "encoding/xml" "fmt" "io" + "net" "net/http" "net/url" "time" + "github.com/huin/goupnp/httpu" "github.com/huin/goupnp/ssdp" ) @@ -63,6 +65,9 @@ type MaybeRootDevice struct { // the discovery of a device, regardless of if there was an error probing it. Location *url.URL + // The address from which the device was discovered (if known - otherwise nil). + LocalAddr net.IP + // Any error encountered probing a discovered device. Err error } @@ -99,6 +104,9 @@ func DiscoverDevices(searchTarget string) ([]MaybeRootDevice, error) { } else { maybe.Root = root } + if i := response.Header.Get(httpu.LocalAddressHeader); len(i) > 0 { + maybe.LocalAddr = net.ParseIP(i) + } } return results, nil diff --git a/httpu/httpu.go b/httpu/httpu.go index 3367c86..808d600 100644 --- a/httpu/httpu.go +++ b/httpu/httpu.go @@ -143,9 +143,16 @@ func (httpu *HTTPUClient) Do( continue } + // Set the related local address used to discover the device. + if a, ok := httpu.conn.LocalAddr().(*net.UDPAddr); ok { + response.Header.Add(LocalAddressHeader, a.IP.String()) + } + responses = append(responses, response) } // Timeout reached - return discovered responses. return responses, nil } + +const LocalAddressHeader = "goupnp-local-address" diff --git a/service_client.go b/service_client.go index 9111c93..79a375d 100644 --- a/service_client.go +++ b/service_client.go @@ -2,6 +2,7 @@ package goupnp import ( "fmt" + "net" "net/url" "github.com/huin/goupnp/soap" @@ -17,6 +18,7 @@ type ServiceClient struct { RootDevice *RootDevice Location *url.URL Service *Service + localAddr net.IP } // NewServiceClients discovers services, and returns clients for them. err will @@ -36,7 +38,7 @@ func NewServiceClients(searchTarget string) (clients []ServiceClient, errors []e continue } - deviceClients, err := NewServiceClientsFromRootDevice(maybeRootDevice.Root, maybeRootDevice.Location, searchTarget) + deviceClients, err := newServiceClientsFromRootDevice(maybeRootDevice.Root, maybeRootDevice.Location, searchTarget, maybeRootDevice.LocalAddr) if err != nil { errors = append(errors, err) continue @@ -61,6 +63,15 @@ func NewServiceClientsByURL(loc *url.URL, searchTarget string) ([]ServiceClient, // a given root device. The loc parameter is simply assigned to the // Location attribute of the returned ServiceClient(s). func NewServiceClientsFromRootDevice(rootDevice *RootDevice, loc *url.URL, searchTarget string) ([]ServiceClient, error) { + return newServiceClientsFromRootDevice(rootDevice, loc, searchTarget, nil) +} + +func newServiceClientsFromRootDevice( + rootDevice *RootDevice, + loc *url.URL, + searchTarget string, + lAddr net.IP, +) ([]ServiceClient, error) { device := &rootDevice.Device srvs := device.FindService(searchTarget) if len(srvs) == 0 { @@ -75,6 +86,7 @@ func NewServiceClientsFromRootDevice(rootDevice *RootDevice, loc *url.URL, searc RootDevice: rootDevice, Location: loc, Service: srv, + localAddr: lAddr, }) } return clients, nil @@ -86,3 +98,8 @@ func NewServiceClientsFromRootDevice(rootDevice *RootDevice, loc *url.URL, searc func (client *ServiceClient) GetServiceClient() *ServiceClient { return client } + +// LocalAddr returns the address from which the device was discovered (if known - otherwise empty). +func (client *ServiceClient) LocalAddr() net.IP { + return client.localAddr +}