syncthing/mc/beacon.go
2014-05-11 18:43:25 -03:00

115 lines
1.9 KiB
Go

package mc
import (
"log"
"net"
)
type recv struct {
data []byte
src net.Addr
}
type dst struct {
intf string
conn *net.UDPConn
}
type Beacon struct {
group string
port int
conns []dst
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)
}
if debug {
dlog.Printf("trying %d interfaces", len(intfs))
}
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 {
dlog.Printf("failed to listen for multicast group on %q: %v", intf.Name, err)
}
} else {
b.conns = append(b.conns, dst{intf.Name, conn})
if debug {
dlog.Printf("listening for multicast group on %q", intf.Name)
}
}
}
for _, dst := range b.conns {
dst := dst
go func() {
for {
var bs = make([]byte, 1500)
n, addr, err := dst.conn.ReadFrom(bs)
if err != nil {
dlog.Println(err)
return
}
if debug {
dlog.Printf("recv %d bytes from %s on %s", n, addr, dst.intf)
}
select {
case b.outbox <- recv{bs[:n], addr}:
default:
if debug {
dlog.Println("Dropping message")
}
}
}
}()
}
go func() {
for bs := range b.inbox {
for _, dst := range b.conns {
_, err := dst.conn.WriteTo(bs, group)
if err != nil {
dlog.Println(err)
return
}
if debug {
dlog.Printf("sent %d bytes to %s on %s", len(bs), group, dst.intf)
}
}
}
}()
}