syncthing/mc/beacon.go

115 lines
1.9 KiB
Go
Raw Normal View History

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