Browse Source

External discover

Jakob Borg 12 years ago
parent
commit
f2d8b68278
5 changed files with 157 additions and 94 deletions
  1. 1 0
      discover/cmd/discosrv/.gitignore
  2. 74 0
      discover/cmd/discosrv/main.go
  3. 40 52
      discover/discover.go
  4. 26 26
      discover/encoding.go
  5. 16 16
      discover/encoding_test.go

+ 1 - 0
discover/cmd/discosrv/.gitignore

@@ -0,0 +1 @@
+discosrv

+ 74 - 0
discover/cmd/discosrv/main.go

@@ -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)
+				}
+			}
+		}
+
+	}
+}

+ 40 - 52
discover/discover.go

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

+ 26 - 26
discover/encoding.go

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

+ 16 - 16
discover/encoding_test.go

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