package tracker import ( "bytes" "encoding/binary" "fmt" "net" "net/url" "dim13.org/btget/bencode" ) type Peer struct { IP string `bencode:"ip"` ID []byte `bencode:"peer id"` // not present in compact mode Port int `bencode:"port"` } func (p Peer) String() string { return fmt.Sprintf("%v:%v %v", p.IP, p.Port, url.QueryEscape(string(p.ID))) } func (p Peer) Addr() string { return fmt.Sprintf("%v:%v", p.IP, p.Port) } type Peers []Peer func (p *Peers) UnmarshalBencode(b []byte) (int, error) { switch b[0] { case 'l': // XXX bencode.tokenList var tmp []Peer n, err := bencode.Unmarshal(b, &tmp) *p = Peers(tmp) return n, err default: var tmp []byte n, err := bencode.Unmarshal(b, &tmp) addr, err := peerAddr(tmp) *p = make(Peers, len(addr)) for i, v := range addr { (*p)[i] = Peer{ IP: v.IP.String(), Port: int(v.Port), } } return n, err } } func peerAddr(b []byte) ([]*net.TCPAddr, error) { n := len(b) / 6 a := make([]*net.TCPAddr, n) var port uint16 for i := 0; i < n; i++ { off := i * 6 buf := bytes.NewReader(b[off+4 : off+6]) err := binary.Read(buf, binary.BigEndian, &port) if err != nil { return nil, err } a[i] = &net.TCPAddr{ IP: net.IP(b[off : off+4]), Port: int(port), } } return a, nil }