import (
"bytes"
"encoding/binary"
+ "errors"
"fmt"
"github.com/jhalter/mobius/concat"
"net"
)
type TrackerRegistration struct {
- Port []byte // Server’s listening UDP port number TODO: wat?
+ Port []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’s name
+ Name string // Server name
Description string // Description of the server
}
)
}
-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
return nil
}
-type ServerListing struct {
-}
-
const trackerTimeout = 5 * time.Second
// All string values use 8-bit ASCII character set encoding.
// 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
}
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
}
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
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 {
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)]
}
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[:]))),
)
}