2014-03-28 10:04:48 +00:00
|
|
|
package mc
|
|
|
|
|
|
|
|
import (
|
|
|
|
"log"
|
|
|
|
"net"
|
|
|
|
)
|
|
|
|
|
|
|
|
type recv struct {
|
|
|
|
data []byte
|
|
|
|
src net.Addr
|
|
|
|
}
|
|
|
|
|
|
|
|
type Beacon struct {
|
|
|
|
group string
|
|
|
|
port int
|
|
|
|
conns []*net.UDPConn
|
|
|
|
inbox chan []byte
|
|
|
|
outbox chan recv
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewBeacon(group string, port int) *Beacon {
|
|
|
|
b := &Beacon{
|
|
|
|
group: group,
|
|
|
|
port: port,
|
|
|
|
inbox: make(chan []byte),
|
|
|
|
outbox: make(chan recv),
|
|
|
|
}
|
|
|
|
go b.run()
|
|
|
|
return b
|
|
|
|
}
|
|
|
|
|
|
|
|
func (b *Beacon) Send(data []byte) {
|
|
|
|
b.inbox <- data
|
|
|
|
}
|
|
|
|
|
|
|
|
func (b *Beacon) Recv() ([]byte, net.Addr) {
|
|
|
|
recv := <-b.outbox
|
|
|
|
return recv.data, recv.src
|
|
|
|
}
|
|
|
|
|
|
|
|
func (b *Beacon) run() {
|
|
|
|
group := &net.UDPAddr{IP: net.ParseIP(b.group), Port: b.port}
|
|
|
|
|
|
|
|
intfs, err := net.Interfaces()
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
2014-04-30 13:13:54 +00:00
|
|
|
if debug {
|
|
|
|
dlog.Printf("trying %d interfaces", len(intfs))
|
|
|
|
}
|
2014-03-28 10:04:48 +00:00
|
|
|
|
|
|
|
for _, intf := range intfs {
|
|
|
|
intf := intf
|
|
|
|
|
|
|
|
if debug {
|
|
|
|
dlog.Printf("trying interface %q", intf.Name)
|
|
|
|
}
|
|
|
|
conn, err := net.ListenMulticastUDP("udp4", &intf, group)
|
|
|
|
if err != nil {
|
|
|
|
if debug {
|
2014-04-30 13:13:54 +00:00
|
|
|
dlog.Printf("failed to listen for multicast group on %q: %v", intf.Name, err)
|
2014-03-28 10:04:48 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
b.conns = append(b.conns, conn)
|
2014-04-30 13:13:54 +00:00
|
|
|
if debug {
|
|
|
|
dlog.Printf("listening for multicast group on %q", intf.Name)
|
|
|
|
}
|
2014-03-28 10:04:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, conn := range b.conns {
|
|
|
|
conn := conn
|
|
|
|
go func() {
|
|
|
|
for {
|
|
|
|
var bs = make([]byte, 1500)
|
|
|
|
n, addr, err := conn.ReadFrom(bs)
|
|
|
|
if err != nil {
|
|
|
|
dlog.Println(err)
|
|
|
|
return
|
|
|
|
}
|
2014-04-30 13:13:54 +00:00
|
|
|
if debug {
|
|
|
|
dlog.Printf("recv %d bytes from %s on %v", n, addr, conn)
|
|
|
|
}
|
2014-03-28 10:04:48 +00:00
|
|
|
b.outbox <- recv{bs[:n], addr}
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
for bs := range b.inbox {
|
|
|
|
for _, conn := range b.conns {
|
|
|
|
_, err := conn.WriteTo(bs, group)
|
|
|
|
if err != nil {
|
|
|
|
dlog.Println(err)
|
|
|
|
return
|
|
|
|
}
|
2014-04-30 13:13:54 +00:00
|
|
|
if debug {
|
|
|
|
dlog.Printf("sent %d bytes to %s on %v", len(bs), group, conn)
|
|
|
|
}
|
2014-03-28 10:04:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
}
|