407136030e
Specifically: * HTTPU * SSDP * UPNP Also now supports multiple discoveries from a search.
123 lines
2.5 KiB
Go
123 lines
2.5 KiB
Go
package goupnp
|
|
|
|
import (
|
|
"encoding/xml"
|
|
"fmt"
|
|
"log"
|
|
"net/http"
|
|
)
|
|
|
|
const (
|
|
// Search Target for InternetGatewayDevice.
|
|
SearchTargetIGD = "urn:schemas-upnp-org:device:InternetGatewayDevice:1"
|
|
)
|
|
|
|
// DiscoverIGD attempts to find Internet Gateway Devices.
|
|
//
|
|
// TODO: Fix implementation to discover multiple. Currently it will find a
|
|
// maximum of one.
|
|
func DiscoverIGD() ([]*IGD, error) {
|
|
httpu, err := NewHTTPUClient()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
responses, err := SSDPRawSearch(httpu, SearchTargetIGD, 2, 3)
|
|
|
|
results := make([]*IGD, 0, len(responses))
|
|
for _, response := range responses {
|
|
loc, err := response.Location()
|
|
if err != nil {
|
|
log.Printf("goupnp: unexpected bad location from search: %v", err)
|
|
continue
|
|
}
|
|
igd, err := requestIgd(loc.String())
|
|
if err != nil {
|
|
log.Printf("goupnp: error requesting IGD: %v", err)
|
|
continue
|
|
}
|
|
results = append(results, igd)
|
|
}
|
|
|
|
return results, nil
|
|
}
|
|
|
|
// IGD defines the interface for an Internet Gateway Device.
|
|
type IGD struct {
|
|
xml xmlRootDevice
|
|
}
|
|
|
|
func requestIgd(serviceUrl string) (*IGD, error) {
|
|
resp, err := http.Get(serviceUrl)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != 200 {
|
|
return nil, fmt.Errorf("goupnp: got response status %s from IGD at %q",
|
|
resp.Status, serviceUrl)
|
|
}
|
|
|
|
decoder := xml.NewDecoder(resp.Body)
|
|
decoder.DefaultSpace = deviceXmlNs
|
|
var xml xmlRootDevice
|
|
if err = decoder.Decode(&xml); err != nil {
|
|
return nil, err
|
|
}
|
|
log.Printf("%+v", xml)
|
|
|
|
return &IGD{xml}, nil
|
|
}
|
|
|
|
func (igd *IGD) Device() *Device {
|
|
return &Device{
|
|
igd.xml.URLBase,
|
|
igd.xml.Device,
|
|
}
|
|
}
|
|
|
|
func (igd *IGD) String() string {
|
|
return fmt.Sprintf("IGD{UDN: %q friendlyName: %q}",
|
|
igd.xml.Device.UDN, igd.xml.Device.FriendlyName)
|
|
}
|
|
|
|
type Device struct {
|
|
urlBase string
|
|
xml xmlDevice
|
|
}
|
|
|
|
func (device *Device) String() string {
|
|
return fmt.Sprintf("Device{friendlyName: %q}", device.xml.FriendlyName)
|
|
}
|
|
|
|
func (device *Device) Devices() []*Device {
|
|
devices := make([]*Device, len(device.xml.Devices))
|
|
for i, childXml := range device.xml.Devices {
|
|
devices[i] = &Device{
|
|
device.urlBase,
|
|
childXml,
|
|
}
|
|
}
|
|
return devices
|
|
}
|
|
|
|
func (device *Device) Services() []*Service {
|
|
srvs := make([]*Service, len(device.xml.Services))
|
|
for i, childXml := range device.xml.Services {
|
|
srvs[i] = &Service{
|
|
device.urlBase,
|
|
childXml,
|
|
}
|
|
}
|
|
return srvs
|
|
}
|
|
|
|
type Service struct {
|
|
urlBase string
|
|
xml xmlService
|
|
}
|
|
|
|
func (srv *Service) String() string {
|
|
return fmt.Sprintf("Service{serviceType: %q}", srv.xml.ServiceType)
|
|
}
|