github.com/kayoticsully/syncthing@v0.8.9-0.20140724133906-c45a2fdc03f8/beacon/beacon.go (about) 1 // Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file). 2 // All rights reserved. Use of this source code is governed by an MIT-style 3 // license that can be found in the LICENSE file. 4 5 package beacon 6 7 import "net" 8 9 type recv struct { 10 data []byte 11 src net.Addr 12 } 13 14 type dst struct { 15 intf string 16 conn *net.UDPConn 17 } 18 19 type Beacon struct { 20 conn *net.UDPConn 21 port int 22 conns []dst 23 inbox chan []byte 24 outbox chan recv 25 } 26 27 func New(port int) (*Beacon, error) { 28 conn, err := net.ListenUDP("udp", &net.UDPAddr{Port: port}) 29 if err != nil { 30 return nil, err 31 } 32 b := &Beacon{ 33 conn: conn, 34 port: port, 35 inbox: make(chan []byte), 36 outbox: make(chan recv, 16), 37 } 38 39 go b.reader() 40 go b.writer() 41 42 return b, nil 43 } 44 45 func (b *Beacon) Send(data []byte) { 46 b.inbox <- data 47 } 48 49 func (b *Beacon) Recv() ([]byte, net.Addr) { 50 recv := <-b.outbox 51 return recv.data, recv.src 52 } 53 54 func (b *Beacon) reader() { 55 bs := make([]byte, 65536) 56 for { 57 n, addr, err := b.conn.ReadFrom(bs) 58 if err != nil { 59 l.Warnln("Beacon read:", err) 60 return 61 } 62 if debug { 63 l.Debugf("recv %d bytes from %s", n, addr) 64 } 65 66 c := make([]byte, n) 67 copy(c, bs) 68 select { 69 case b.outbox <- recv{c, addr}: 70 default: 71 if debug { 72 l.Debugln("dropping message") 73 } 74 } 75 } 76 } 77 78 func (b *Beacon) writer() { 79 for bs := range b.inbox { 80 81 addrs, err := net.InterfaceAddrs() 82 if err != nil { 83 l.Warnln("Beacon: interface addresses:", err) 84 continue 85 } 86 87 var dsts []net.IP 88 for _, addr := range addrs { 89 if iaddr, ok := addr.(*net.IPNet); ok && iaddr.IP.IsGlobalUnicast() && iaddr.IP.To4() != nil { 90 baddr := bcast(iaddr) 91 dsts = append(dsts, baddr.IP) 92 } 93 } 94 95 if len(dsts) == 0 { 96 // Fall back to the general IPv4 broadcast address 97 dsts = append(dsts, net.IP{0xff, 0xff, 0xff, 0xff}) 98 } 99 100 if debug { 101 l.Debugln("addresses:", dsts) 102 } 103 104 for _, ip := range dsts { 105 dst := &net.UDPAddr{IP: ip, Port: b.port} 106 107 _, err := b.conn.WriteTo(bs, dst) 108 if err != nil { 109 if debug { 110 l.Debugln(err) 111 } 112 } else if debug { 113 l.Debugf("sent %d bytes to %s", len(bs), dst) 114 } 115 } 116 } 117 } 118 119 func bcast(ip *net.IPNet) *net.IPNet { 120 var bc = &net.IPNet{} 121 bc.IP = make([]byte, len(ip.IP)) 122 copy(bc.IP, ip.IP) 123 bc.Mask = ip.Mask 124 125 offset := len(bc.IP) - len(bc.Mask) 126 for i := range bc.IP { 127 if i-offset > 0 { 128 bc.IP[i] = ip.IP[i] | ^ip.Mask[i-offset] 129 } 130 } 131 return bc 132 }