| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160 |
- package discover
- import (
- "encoding/binary"
- "errors"
- "fmt"
- )
- type Packet struct {
- Magic uint32 // AnnouncementMagic or QueryMagic
- Port uint16 // unset if magic == QueryMagic
- ID string
- IP []byte // zero length in local announcements
- }
- var (
- errBadMagic = errors.New("bad magic")
- errFormat = errors.New("incorrect packet format")
- )
- 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 l = 4 + 4 + len(idbs) + pad(len(idbs))
- 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)
- offset += 4
- if pkt.Magic == AnnouncementMagic {
- binary.BigEndian.PutUint16(buf[offset:], uint16(pkt.Port))
- offset += 4
- }
- binary.BigEndian.PutUint32(buf[offset:], uint32(len(idbs)))
- offset += 4
- copy(buf[offset:], idbs)
- offset += len(idbs) + pad(len(idbs))
- if pkt.Magic == AnnouncementMagic {
- binary.BigEndian.PutUint32(buf[offset:], uint32(len(pkt.IP)))
- offset += 4
- copy(buf[offset:], pkt.IP)
- offset += len(pkt.IP)
- }
- return buf
- }
- 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:])
- offset += 4
- if p.Magic != AnnouncementMagic && p.Magic != QueryMagic {
- return nil, errBadMagic
- }
- if p.Magic == AnnouncementMagic {
- // Port Number
- if len(buf) < offset+4 {
- // short packet
- return nil, errFormat
- }
- p.Port = binary.BigEndian.Uint16(buf[offset:])
- offset += 2
- reserved := binary.BigEndian.Uint16(buf[offset:])
- if reserved != 0 {
- return nil, errFormat
- }
- offset += 2
- }
- // Node ID
- if len(buf) < offset+4 {
- // short packet
- return nil, errFormat
- }
- l := binary.BigEndian.Uint32(buf[offset:])
- offset += 4
- if len(buf) < offset+int(l)+pad(int(l)) {
- // short packet
- return nil, errFormat
- }
- idbs := buf[offset : offset+int(l)]
- p.ID = string(idbs)
- offset += int(l) + pad(int(l))
- if p.Magic == AnnouncementMagic {
- // IP
- if len(buf) < offset+4 {
- // short packet
- return nil, errFormat
- }
- l = binary.BigEndian.Uint32(buf[offset:])
- offset += 4
- if l != 0 && l != 4 && l != 16 {
- // weird ip length
- return nil, errFormat
- }
- if len(buf) < offset+int(l) {
- // short packet
- return nil, errFormat
- }
- if l > 0 {
- p.IP = buf[offset : offset+int(l)]
- offset += int(l)
- }
- }
- if len(buf[offset:]) > 0 {
- // extra data
- return nil, errFormat
- }
- return &p, nil
- }
- func pad(l int) int {
- d := l % 4
- if d == 0 {
- return 0
- }
- return 4 - d
- }
- func ipStr(ip []byte) string {
- switch len(ip) {
- case 4:
- return fmt.Sprintf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3])
- case 16:
- return fmt.Sprintf("%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
- ip[0], ip[1], ip[2], ip[3],
- ip[4], ip[5], ip[6], ip[7],
- ip[8], ip[9], ip[10], ip[11],
- ip[12], ip[13], ip[14], ip[15])
- default:
- return ""
- }
- }
|