goupnp/goupnp.go

123 lines
2.5 KiB
Go
Raw Normal View History

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)
}