X-Git-Url: https://git.r.bdr.sh/rbdr/mobius/blobdiff_plain/22c599abc18895f73e96095f35b71cf3357d41b4..270abe9a991a57084650424a0238ef4f062b0b64:/hotline/tracker.go?ds=sidebyside diff --git a/hotline/tracker.go b/hotline/tracker.go index 97ca108..63fb279 100644 --- a/hotline/tracker.go +++ b/hotline/tracker.go @@ -3,6 +3,7 @@ package hotline import ( "bytes" "encoding/binary" + "errors" "fmt" "github.com/jhalter/mobius/concat" "net" @@ -11,11 +12,11 @@ import ( ) type TrackerRegistration struct { - Port []byte // Server’s listening UDP port number TODO: wat? - UserCount int // Number of users connected to this particular server - PassID []byte // Random number generated by the server - Name string // Server’s name - Description string // Description of the server + Port [2]byte // Server listening port number + UserCount int // Number of users connected to this particular server + PassID []byte // Random number generated by the server + Name string // Server name + Description string // Description of the server } func (tr *TrackerRegistration) Payload() []byte { @@ -24,7 +25,7 @@ func (tr *TrackerRegistration) Payload() []byte { return concat.Slices( []byte{0x00, 0x01}, - tr.Port, + tr.Port[:], userCount, []byte{0x00, 0x00}, tr.PassID, @@ -35,7 +36,7 @@ func (tr *TrackerRegistration) Payload() []byte { ) } -func register(tracker string, tr TrackerRegistration) error { +func register(tracker string, tr *TrackerRegistration) error { conn, err := net.Dial("udp", tracker) if err != nil { return err @@ -48,9 +49,6 @@ func register(tracker string, tr TrackerRegistration) error { return nil } -type ServerListing struct { -} - const trackerTimeout = 5 * time.Second // All string values use 8-bit ASCII character set encoding. @@ -61,17 +59,15 @@ const trackerTimeout = 5 * time.Second // Version 2 1 or 2 Old protocol (1) or new (2) // Reply received from the tracker starts with a header: -// - type TrackerHeader struct { Protocol [4]byte // "HTRK" 0x4854524B Version [2]byte // Old protocol (1) or new (2) } -//Message type 2 1 Sending list of servers -//Message data size 2 Remaining size of this request -//Number of servers 2 Number of servers in the server list -//Number of servers 2 Same as previous field +// Message type 2 1 Sending list of servers +// Message data size 2 Remaining size of this request +// Number of servers 2 Number of servers in the server list +// Number of servers 2 Same as previous field type ServerInfoHeader struct { MsgType [2]byte // always has value of 1 MsgDataSize [2]byte // Remaining size of request @@ -80,12 +76,12 @@ type ServerInfoHeader struct { } type ServerRecord struct { - IPAddr []byte - Port []byte - NumUsers []byte // Number of users connected to this particular server - Unused []byte + IPAddr [4]byte + Port [2]byte + NumUsers [2]byte // Number of users connected to this particular server + Unused [2]byte NameSize byte // Length of name string - Name []byte // Server’s name + Name []byte // Server name DescriptionSize byte Description []byte } @@ -93,9 +89,10 @@ type ServerRecord struct { func GetListing(addr string) ([]ServerRecord, error) { conn, err := net.DialTimeout("tcp", addr, trackerTimeout) if err != nil { - return nil, err + return []ServerRecord{}, err } - //spew.Dump(conn) + defer func() { _ = conn.Close() }() + _, err = conn.Write( []byte{ 0x48, 0x54, 0x52, 0x4B, // HTRK @@ -108,12 +105,12 @@ func GetListing(addr string) ([]ServerRecord, error) { totalRead := 0 - buf := make([]byte, 4096) // handshakes are always 12 bytes in length + buf := make([]byte, 4096) var readLen int if readLen, err = conn.Read(buf); err != nil { return nil, err } - totalRead += readLen + totalRead += readLen // 1514 var th TrackerHeader if err := binary.Read(bytes.NewReader(buf[:6]), binary.BigEndian, &th); err != nil { @@ -127,57 +124,49 @@ func GetListing(addr string) ([]ServerRecord, error) { payloadSize := int(binary.BigEndian.Uint16(info.MsgDataSize[:])) + buf = buf[:readLen] if totalRead < payloadSize { for { - //fmt.Printf("totalRead: %v", totalRead) - //fmt.Printf("readLen: %v Payload size: %v, Server count: %x\n", readLen, payloadSize, info.SrvCount) - - if readLen, err = conn.Read(buf); err != nil { + tmpBuf := make([]byte, 4096) + if readLen, err = conn.Read(tmpBuf); err != nil { return nil, err } + buf = append(buf, tmpBuf[:readLen]...) totalRead += readLen if totalRead >= payloadSize { break } } } - //fmt.Println("passed read") totalSrv := int(binary.BigEndian.Uint16(info.SrvCount[:])) - //fmt.Printf("readLen: %v Payload size: %v, Server count: %x\n", readLen, payloadSize, info.SrvCount) srvBuf := buf[14:totalRead] - totalRead += readLen - var servers []ServerRecord + for { var srv ServerRecord n, _ := srv.Read(srvBuf) servers = append(servers, srv) srvBuf = srvBuf[n:] - // fmt.Printf("srvBuf len: %v\n", len(srvBuf)) + if len(servers) == totalSrv { return servers, nil } if len(srvBuf) == 0 { - if readLen, err = conn.Read(buf); err != nil { - return nil, err - } - srvBuf = buf[8:readLen] + return servers, errors.New("tracker sent too few bytes for server count") } } - - return servers, nil } func (s *ServerRecord) Read(b []byte) (n int, err error) { - s.IPAddr = b[0:4] - s.Port = b[4:6] - s.NumUsers = b[6:8] - s.NameSize = b[10] + copy(s.IPAddr[:], b[0:4]) + copy(s.Port[:], b[4:6]) + copy(s.NumUsers[:], b[6:8]) nameLen := int(b[10]) + s.Name = b[11 : 11+nameLen] s.DescriptionSize = b[11+nameLen] s.Description = b[12+nameLen : 12+nameLen+int(s.DescriptionSize)] @@ -186,13 +175,13 @@ func (s *ServerRecord) Read(b []byte) (n int, err error) { } func (s *ServerRecord) PortInt() int { - data := binary.BigEndian.Uint16(s.Port) + data := binary.BigEndian.Uint16(s.Port[:]) return int(data) } func (s *ServerRecord) Addr() string { return fmt.Sprintf("%s:%s", - net.IP(s.IPAddr), - strconv.Itoa(int(binary.BigEndian.Uint16(s.Port))), + net.IP(s.IPAddr[:]), + strconv.Itoa(int(binary.BigEndian.Uint16(s.Port[:]))), ) }