summaryrefslogtreecommitdiffstats
path: root/beacon
diff options
context:
space:
mode:
authorJakob Borg <jakob@nym.se>2014-05-15 00:29:18 -0300
committerJakob Borg <jakob@nym.se>2014-05-15 00:33:40 -0300
commitadbd0b1834861d84552fb3f2843c9fb559f268a5 (patch)
tree9a78a56e2d80dec854874a843585c26902204ac6 /beacon
parent3e34fc66e639f96087829ab7980c24fe5441a115 (diff)
Rename mc -> beacon
Diffstat (limited to 'beacon')
-rw-r--r--beacon/beacon.go127
-rw-r--r--beacon/cmd/mctest/main.go34
-rw-r--r--beacon/debug.go13
3 files changed, 174 insertions, 0 deletions
diff --git a/beacon/beacon.go b/beacon/beacon.go
new file mode 100644
index 0000000000..e8ab78bdd9
--- /dev/null
+++ b/beacon/beacon.go
@@ -0,0 +1,127 @@
+package beacon
+
+import "net"
+
+type recv struct {
+ data []byte
+ src net.Addr
+}
+
+type dst struct {
+ intf string
+ conn *net.UDPConn
+}
+
+type Beacon struct {
+ conn *net.UDPConn
+ port int
+ conns []dst
+ inbox chan []byte
+ outbox chan recv
+}
+
+func New(port int) (*Beacon, error) {
+ conn, err := net.ListenUDP("udp", &net.UDPAddr{Port: port})
+ if err != nil {
+ return nil, err
+ }
+ b := &Beacon{
+ conn: conn,
+ port: port,
+ inbox: make(chan []byte),
+ outbox: make(chan recv, 16),
+ }
+
+ go b.reader()
+ go b.writer()
+
+ return b, nil
+}
+
+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) reader() {
+ var bs = make([]byte, 65536)
+ for {
+ n, addr, err := b.conn.ReadFrom(bs)
+ if err != nil {
+ l.Warnln("Beacon read:", err)
+ return
+ }
+ if debug {
+ l.Debugf("recv %d bytes from %s", n, addr)
+ }
+ select {
+ case b.outbox <- recv{bs[:n], addr}:
+ default:
+ if debug {
+ l.Debugln("dropping message")
+ }
+ }
+ }
+}
+
+func (b *Beacon) writer() {
+ for bs := range b.inbox {
+
+ addrs, err := net.InterfaceAddrs()
+ if err != nil {
+ l.Warnln("Beacon: interface addresses:", err)
+ continue
+ }
+
+ var dsts []net.IP
+ for _, addr := range addrs {
+ if iaddr, ok := addr.(*net.IPNet); ok && iaddr.IP.IsGlobalUnicast() {
+ baddr := bcast(iaddr)
+ dsts = append(dsts, baddr.IP)
+ }
+ }
+
+ if len(dsts) == 0 {
+ // Fall back to the general IPv4 broadcast address
+ dsts = append(dsts, net.IP{0xff, 0xff, 0xff, 0xff})
+ }
+
+ if debug {
+ l.Debugln("addresses:", dsts)
+ }
+
+ for _, ip := range dsts {
+ dst := &net.UDPAddr{IP: ip, Port: b.port}
+
+ _, err := b.conn.WriteTo(bs, dst)
+ if err != nil {
+ if debug {
+ l.Debugln(err)
+ }
+ return
+ }
+ if debug {
+ l.Debugf("sent %d bytes to %s", len(bs), dst)
+ }
+ }
+ }
+}
+
+func bcast(ip *net.IPNet) *net.IPNet {
+ var bc = &net.IPNet{}
+ bc.IP = make([]byte, len(ip.IP))
+ copy(bc.IP, ip.IP)
+ bc.Mask = ip.Mask
+
+ offset := len(bc.IP) - len(bc.Mask)
+ for i := range bc.IP {
+ if i-offset > 0 {
+ bc.IP[i] = ip.IP[i] | ^ip.Mask[i-offset]
+ }
+ }
+ return bc
+}
diff --git a/beacon/cmd/mctest/main.go b/beacon/cmd/mctest/main.go
new file mode 100644
index 0000000000..d334b4929a
--- /dev/null
+++ b/beacon/cmd/mctest/main.go
@@ -0,0 +1,34 @@
+package main
+
+import (
+ "encoding/binary"
+ "log"
+ "time"
+
+ "github.com/calmh/syncthing/mc"
+)
+
+func main() {
+ b, err := mc.NewBeacon(21025)
+ if err != nil {
+ log.Fatal(err)
+ }
+ go func() {
+ for {
+ bs, addr := b.Recv()
+ log.Printf("Received %d bytes from %s: %x %x", len(bs), addr, bs[:8], bs[8:])
+ }
+ }()
+ go func() {
+ bs := [16]byte{}
+ binary.BigEndian.PutUint64(bs[:], uint64(time.Now().UnixNano()))
+ log.Printf("My ID: %x", bs[:8])
+ for {
+ binary.BigEndian.PutUint64(bs[8:], uint64(time.Now().UnixNano()))
+ b.Send(bs[:])
+ log.Printf("Sent %d bytes", len(bs[:]))
+ time.Sleep(10 * time.Second)
+ }
+ }()
+ select {}
+}
diff --git a/beacon/debug.go b/beacon/debug.go
new file mode 100644
index 0000000000..07c7c4be6b
--- /dev/null
+++ b/beacon/debug.go
@@ -0,0 +1,13 @@
+package beacon
+
+import (
+ "os"
+ "strings"
+
+ "github.com/calmh/syncthing/logger"
+)
+
+var (
+ debug = strings.Contains(os.Getenv("STTRACE"), "beacon") || os.Getenv("STTRACE") == "all"
+ l = logger.DefaultLogger
+)