summaryrefslogtreecommitdiff
path: root/m4p/discover.go
diff options
context:
space:
mode:
Diffstat (limited to 'm4p/discover.go')
-rw-r--r--m4p/discover.go74
1 files changed, 74 insertions, 0 deletions
diff --git a/m4p/discover.go b/m4p/discover.go
new file mode 100644
index 0000000..a63dde2
--- /dev/null
+++ b/m4p/discover.go
@@ -0,0 +1,74 @@
+package m4p
+
+import (
+ "log"
+ "net"
+)
+
+// Discoverer magic4pc servers.
+type Discoverer struct {
+ ln *net.UDPConn
+ device chan DeviceInfo
+}
+
+// NewDiscover returns a new Discoverer that listens on the broadcast port.
+func NewDiscoverer(broadcastPort int) (*Discoverer, error) {
+ addr := net.UDPAddr{
+ Port: broadcastPort,
+ IP: net.ParseIP("0.0.0.0"),
+ }
+
+ ln, err := net.ListenUDP("udp", &addr)
+ if err != nil {
+ panic(err)
+ }
+
+ d := &Discoverer{
+ ln: ln,
+ device: make(chan DeviceInfo), // Unbuffered, discard when nobody is listening.
+ }
+ go d.discover()
+
+ return d, nil
+}
+
+func (d *Discoverer) discover() {
+ var buf [1024]byte
+ for {
+ n, addr, err := d.ln.ReadFromUDP(buf[:])
+ if err != nil {
+ log.Printf("m4p: Discoverer: discover: read udp packet failed: %v", err)
+ continue
+ }
+
+ m, err := decode(buf[:n])
+ if err != nil {
+ log.Printf("m4p: Discoverer: discover: decode failed: %v", err)
+ }
+
+ switch m.Type {
+ case Magic4PCAdMessage:
+ dev := m.DeviceInfo
+ dev.IPAddr = addr.IP.String()
+ log.Printf("m4p: Discoverer: discover: found device: %#v", dev)
+
+ select {
+ case d.device <- *dev:
+ default:
+ }
+
+ default:
+ log.Printf("m4p: Discoverer: discover: unknown message: %s", m.Type)
+ }
+ }
+}
+
+// NextDevice returns a newly discovered magic4pc server.
+func (d *Discoverer) NextDevice() <-chan DeviceInfo {
+ return d.device
+}
+
+// Close the Discoverer and stop listening for broadcasts.
+func (d *Discoverer) Close() error {
+ return d.ln.Close()
+}