External discover

This commit is contained in:
Jakob Borg 2013-12-22 21:35:05 -05:00
parent 31ea72dbb3
commit f2d8b68278
5 changed files with 162 additions and 99 deletions

1
discover/cmd/discosrv/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
discosrv

View File

@ -0,0 +1,74 @@
package main
import (
"log"
"net"
"sync"
"github.com/calmh/syncthing/discover"
)
type Node struct {
IP []byte
Port uint16
}
var (
nodes = make(map[string]Node)
lock sync.Mutex
)
func main() {
addr, _ := net.ResolveUDPAddr("udp", ":22025")
conn, err := net.ListenUDP("udp", addr)
if err != nil {
panic(err)
}
var buf = make([]byte, 1024)
for {
n, addr, err := conn.ReadFromUDP(buf)
if err != nil {
panic(err)
}
pkt, err := discover.DecodePacket(buf[:n])
if err != nil {
log.Println("Warning:", err)
continue
}
switch pkt.Magic {
case 0x20121025:
// Announcement
//lock.Lock()
ip := addr.IP.To4()
if ip == nil {
ip = addr.IP.To16()
}
node := Node{ip, uint16(pkt.Port)}
log.Println("<-", pkt.ID, node)
nodes[pkt.ID] = node
//lock.Unlock()
case 0x19760309:
// Query
//lock.Lock()
node, ok := nodes[pkt.ID]
//lock.Unlock()
if ok {
pkt := discover.Packet{
Magic: 0x20121025,
ID: pkt.ID,
Port: node.Port,
IP: node.IP,
}
_, _, err = conn.WriteMsgUDP(discover.EncodePacket(pkt), nil, addr)
if err != nil {
log.Println("Warning:", err)
} else {
log.Println("->", pkt.ID, node)
}
}
}
}
}

View File

@ -146,22 +146,19 @@ func NewDiscoverer(id string, port int, extPort int, extServer string) (*Discove
func (d *Discoverer) sendAnnouncements() { func (d *Discoverer) sendAnnouncements() {
remote4 := &net.UDPAddr{IP: net.IP{255, 255, 255, 255}, Port: AnnouncementPort} remote4 := &net.UDPAddr{IP: net.IP{255, 255, 255, 255}, Port: AnnouncementPort}
buf := encodePacket(packet{AnnouncementMagic, uint16(d.ListenPort), d.MyID, nil}) buf := EncodePacket(Packet{AnnouncementMagic, uint16(d.ListenPort), d.MyID, nil})
go d.writeAnnouncements(buf, remote4, d.BroadcastIntv) go d.writeAnnouncements(buf, remote4, d.BroadcastIntv)
} }
func (d *Discoverer) sendExtAnnouncements() { func (d *Discoverer) sendExtAnnouncements() {
extIPs, err := net.LookupIP(d.extServer) extIP, err := net.ResolveUDPAddr("udp", d.extServer+":22025")
if err != nil { if err != nil {
log.Printf("discover/external: %v; no external announcements", err) log.Printf("discover/external: %v; no external announcements", err)
return return
} }
buf := encodePacket(packet{AnnouncementMagic, uint16(d.ExtListenPort), d.MyID, nil}) buf := EncodePacket(Packet{AnnouncementMagic, uint16(d.ExtListenPort), d.MyID, nil})
for _, extIP := range extIPs { go d.writeAnnouncements(buf, extIP, d.ExtBroadcastIntv)
remote4 := &net.UDPAddr{IP: extIP, Port: AnnouncementPort}
go d.writeAnnouncements(buf, remote4, d.ExtBroadcastIntv)
}
} }
func (d *Discoverer) writeAnnouncements(buf []byte, remote *net.UDPAddr, intv time.Duration) { func (d *Discoverer) writeAnnouncements(buf []byte, remote *net.UDPAddr, intv time.Duration) {
@ -170,6 +167,7 @@ func (d *Discoverer) writeAnnouncements(buf []byte, remote *net.UDPAddr, intv ti
for errCounter < maxErrors { for errCounter < maxErrors {
_, _, err = d.conn.WriteMsgUDP(buf, nil, remote) _, _, err = d.conn.WriteMsgUDP(buf, nil, remote)
if err != nil { if err != nil {
log.Println("discover/write: warning:", err)
errCounter++ errCounter++
} else { } else {
errCounter = 0 errCounter = 0
@ -191,8 +189,8 @@ func (d *Discoverer) recvAnnouncements() {
continue continue
} }
pkt, err := decodePacket(buf[:n]) pkt, err := DecodePacket(buf[:n])
if err != nil || pkt.magic != AnnouncementMagic { if err != nil || pkt.Magic != AnnouncementMagic {
errCounter++ errCounter++
time.Sleep(time.Second) time.Sleep(time.Second)
continue continue
@ -200,11 +198,11 @@ func (d *Discoverer) recvAnnouncements() {
errCounter = 0 errCounter = 0
if pkt.id != d.MyID { if pkt.ID != d.MyID {
nodeAddr := fmt.Sprintf("%s:%d", addr.IP.String(), pkt.port) nodeAddr := fmt.Sprintf("%s:%d", addr.IP.String(), pkt.Port)
d.registryLock.Lock() d.registryLock.Lock()
if d.registry[pkt.id] != nodeAddr { if d.registry[pkt.ID] != nodeAddr {
d.registry[pkt.id] = nodeAddr d.registry[pkt.ID] = nodeAddr
} }
d.registryLock.Unlock() d.registryLock.Unlock()
} }
@ -213,58 +211,48 @@ func (d *Discoverer) recvAnnouncements() {
} }
func (d *Discoverer) externalLookup(node string) (string, bool) { func (d *Discoverer) externalLookup(node string) (string, bool) {
extIPs, err := net.LookupIP(d.extServer) extIP, err := net.ResolveUDPAddr("udp", d.extServer+":22025")
if err != nil { if err != nil {
log.Printf("discover/external: %v; no external lookup", err) log.Printf("discover/external: %v; no external lookup", err)
return "", false return "", false
} }
var res = make(chan string, len(extIPs)) var res = make(chan string, 1)
var failed = 0 conn, err := net.DialUDP("udp", nil, extIP)
for _, extIP := range extIPs { if err != nil {
remote := &net.UDPAddr{IP: extIP, Port: AnnouncementPort} log.Printf("discover/external: %v; no external lookup", err)
conn, err := net.DialUDP("udp", nil, remote)
if err != nil {
log.Printf("discover/external: %v; no external lookup", err)
failed++
continue
}
_, err = conn.Write(encodePacket(packet{QueryMagic, 0, node, nil}))
if err != nil {
log.Printf("discover/external: %v; no external lookup", err)
failed++
continue
}
go func() {
var buf = make([]byte, 1024)
_, err = conn.Read(buf)
if err != nil {
log.Printf("discover/external/read: %v; no external lookup", err)
return
}
pkt, err := decodePacket(buf)
if err != nil {
log.Printf("discover/external/read: %v; no external lookup", err)
return
}
if pkt.magic != AnnouncementMagic {
log.Printf("discover/external/read: bad magic; no external lookup", err)
return
}
res <- fmt.Sprintf("%s:%d", ipStr(pkt.ip), pkt.port)
}()
}
if failed == len(extIPs) {
// no point in waiting
return "", false return "", false
} }
_, err = conn.Write(EncodePacket(Packet{QueryMagic, 0, node, nil}))
if err != nil {
log.Printf("discover/external: %v; no external lookup", err)
return "", false
}
log.Println("query", extIP)
go func() {
var buf = make([]byte, 1024)
n, err := conn.Read(buf)
if err != nil {
log.Printf("discover/external/read: %v; no external lookup", err)
return
}
pkt, err := DecodePacket(buf[:n])
if err != nil {
log.Printf("discover/external/read: %v; no external lookup", err)
return
}
if pkt.Magic != AnnouncementMagic {
log.Printf("discover/external/read: bad magic; no external lookup", err)
return
}
res <- fmt.Sprintf("%s:%d", ipStr(pkt.IP), pkt.Port)
}()
select { select {
case r := <-res: case r := <-res:
return r, true return r, true

View File

@ -6,11 +6,11 @@ import (
"fmt" "fmt"
) )
type packet struct { type Packet struct {
magic uint32 // AnnouncementMagic or QueryMagic Magic uint32 // AnnouncementMagic or QueryMagic
port uint16 // unset if magic == QueryMagic Port uint16 // unset if magic == QueryMagic
id string ID string
ip []byte // zero length in local announcements IP []byte // zero length in local announcements
} }
var ( var (
@ -18,26 +18,26 @@ var (
errFormat = errors.New("incorrect packet format") errFormat = errors.New("incorrect packet format")
) )
func encodePacket(pkt packet) []byte { func EncodePacket(pkt Packet) []byte {
if l := len(pkt.ip); l != 0 && l != 4 && l != 16 { if l := len(pkt.IP); l != 0 && l != 4 && l != 16 {
// bad ip format // bad ip format
return nil return nil
} }
var idbs = []byte(pkt.id) var idbs = []byte(pkt.ID)
var l = 4 + 4 + len(idbs) + pad(len(idbs)) var l = 4 + 4 + len(idbs) + pad(len(idbs))
if pkt.magic == AnnouncementMagic { if pkt.Magic == AnnouncementMagic {
l += 4 + 4 + len(pkt.ip) l += 4 + 4 + len(pkt.IP)
} }
var buf = make([]byte, l) var buf = make([]byte, l)
var offset = 0 var offset = 0
binary.BigEndian.PutUint32(buf[offset:], pkt.magic) binary.BigEndian.PutUint32(buf[offset:], pkt.Magic)
offset += 4 offset += 4
if pkt.magic == AnnouncementMagic { if pkt.Magic == AnnouncementMagic {
binary.BigEndian.PutUint16(buf[offset:], uint16(pkt.port)) binary.BigEndian.PutUint16(buf[offset:], uint16(pkt.Port))
offset += 4 offset += 4
} }
@ -46,39 +46,39 @@ func encodePacket(pkt packet) []byte {
copy(buf[offset:], idbs) copy(buf[offset:], idbs)
offset += len(idbs) + pad(len(idbs)) offset += len(idbs) + pad(len(idbs))
if pkt.magic == AnnouncementMagic { if pkt.Magic == AnnouncementMagic {
binary.BigEndian.PutUint32(buf[offset:], uint32(len(pkt.ip))) binary.BigEndian.PutUint32(buf[offset:], uint32(len(pkt.IP)))
offset += 4 offset += 4
copy(buf[offset:], pkt.ip) copy(buf[offset:], pkt.IP)
offset += len(pkt.ip) offset += len(pkt.IP)
} }
return buf return buf
} }
func decodePacket(buf []byte) (*packet, error) { func DecodePacket(buf []byte) (*Packet, error) {
var p packet var p Packet
var offset int var offset int
if len(buf) < 4 { if len(buf) < 4 {
// short packet // short packet
return nil, errFormat return nil, errFormat
} }
p.magic = binary.BigEndian.Uint32(buf[offset:]) p.Magic = binary.BigEndian.Uint32(buf[offset:])
offset += 4 offset += 4
if p.magic != AnnouncementMagic && p.magic != QueryMagic { if p.Magic != AnnouncementMagic && p.Magic != QueryMagic {
return nil, errBadMagic return nil, errBadMagic
} }
if p.magic == AnnouncementMagic { if p.Magic == AnnouncementMagic {
// Port Number // Port Number
if len(buf) < offset+4 { if len(buf) < offset+4 {
// short packet // short packet
return nil, errFormat return nil, errFormat
} }
p.port = binary.BigEndian.Uint16(buf[offset:]) p.Port = binary.BigEndian.Uint16(buf[offset:])
offset += 2 offset += 2
reserved := binary.BigEndian.Uint16(buf[offset:]) reserved := binary.BigEndian.Uint16(buf[offset:])
if reserved != 0 { if reserved != 0 {
@ -101,10 +101,10 @@ func decodePacket(buf []byte) (*packet, error) {
return nil, errFormat return nil, errFormat
} }
idbs := buf[offset : offset+int(l)] idbs := buf[offset : offset+int(l)]
p.id = string(idbs) p.ID = string(idbs)
offset += int(l) + pad(int(l)) offset += int(l) + pad(int(l))
if p.magic == AnnouncementMagic { if p.Magic == AnnouncementMagic {
// IP // IP
if len(buf) < offset+4 { if len(buf) < offset+4 {
@ -123,7 +123,7 @@ func decodePacket(buf []byte) (*packet, error) {
return nil, errFormat return nil, errFormat
} }
if l > 0 { if l > 0 {
p.ip = buf[offset : offset+int(l)] p.IP = buf[offset : offset+int(l)]
offset += int(l) offset += int(l)
} }
} }

View File

@ -8,7 +8,7 @@ import (
var testdata = []struct { var testdata = []struct {
data []byte data []byte
packet *packet packet *Packet
err error err error
}{ }{
{ {
@ -17,10 +17,10 @@ var testdata = []struct {
0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05,
0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x00, 0x00, 0x00, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00}, 0x00, 0x00, 0x00, 0x00},
&packet{ &Packet{
magic: 0x20121025, Magic: 0x20121025,
port: 0x1234, Port: 0x1234,
id: "hello", ID: "hello",
}, },
nil, nil,
}, },
@ -31,11 +31,11 @@ var testdata = []struct {
0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x21, 0x21, 0x21, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x21, 0x21, 0x21,
0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04,
0x01, 0x02, 0x03, 0x04}, 0x01, 0x02, 0x03, 0x04},
&packet{ &Packet{
magic: 0x20121025, Magic: 0x20121025,
port: 0x3456, Port: 0x3456,
id: "hello!!!", ID: "hello!!!",
ip: []byte{1, 2, 3, 4}, IP: []byte{1, 2, 3, 4},
}, },
nil, nil,
}, },
@ -43,9 +43,9 @@ var testdata = []struct {
[]byte{0x19, 0x76, 0x03, 0x09, []byte{0x19, 0x76, 0x03, 0x09,
0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06,
0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x21, 0x00, 0x00}, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x21, 0x00, 0x00},
&packet{ &Packet{
magic: 0x19760309, Magic: 0x19760309,
id: "hello!", ID: "hello!",
}, },
nil, nil,
}, },
@ -68,7 +68,7 @@ var testdata = []struct {
errFormat, errFormat,
}, },
{ {
[]byte{0x19, 0x77, 0x03, 0x09, // incorrect magic []byte{0x19, 0x77, 0x03, 0x09, // incorrect Magic
0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06,
0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x21, 0x00, 0x00}, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x21, 0x00, 0x00},
nil, nil,
@ -93,7 +93,7 @@ var testdata = []struct {
func TestDecodePacket(t *testing.T) { func TestDecodePacket(t *testing.T) {
for i, test := range testdata { for i, test := range testdata {
p, err := decodePacket(test.data) p, err := DecodePacket(test.data)
if err != test.err { if err != test.err {
t.Errorf("%d: unexpected error %v", i, err) t.Errorf("%d: unexpected error %v", i, err)
} else { } else {
@ -109,7 +109,7 @@ func TestEncodePacket(t *testing.T) {
if test.err != nil { if test.err != nil {
continue continue
} }
buf := encodePacket(*test.packet) buf := EncodePacket(*test.packet)
if bytes.Compare(buf, test.data) != 0 { if bytes.Compare(buf, test.data) != 0 {
t.Errorf("%d: incorrect encoded packet\n% x\n% 0x", i, test.data, buf) t.Errorf("%d: incorrect encoded packet\n% x\n% 0x", i, test.data, buf)
} }