import (
"bytes"
+ "encoding"
"encoding/binary"
"errors"
"fmt"
connectionId int64
socket net.Conn
url url.URL
+ a *Announce
}
func (c *udpAnnounce) Close() error {
return nil
}
+func (c *udpAnnounce) ipv6() bool {
+ if c.a.UdpNetwork == "udp6" {
+ return true
+ }
+ rip := missinggo.AddrIP(c.socket.RemoteAddr())
+ return rip.To16() != nil && rip.To4() == nil
+}
+
func (c *udpAnnounce) Do(req *AnnounceRequest) (res AnnounceResponse, err error) {
err = c.connect()
if err != nil {
res.Interval = h.Interval
res.Leechers = h.Leechers
res.Seeders = h.Seeders
- var cps krpc.CompactIPv4NodeAddrs
- err = cps.UnmarshalBinary(b.Bytes())
+ nas := func() interface {
+ encoding.BinaryUnmarshaler
+ NodeAddrs() []krpc.NodeAddr
+ } {
+ if c.ipv6() {
+ return &krpc.CompactIPv6NodeAddrs{}
+ } else {
+ return &krpc.CompactIPv4NodeAddrs{}
+ }
+ }()
+ err = nas.UnmarshalBinary(b.Bytes())
if err != nil {
return
}
- for _, cp := range cps {
- res.Peers = append(res.Peers, Peer{
- IP: cp.IP[:],
- Port: int(cp.Port),
- })
+ for _, cp := range nas.NodeAddrs() {
+ res.Peers = append(res.Peers, Peer{}.FromNodeAddr(cp))
}
return
}
return !c.connectionIdReceived.IsZero() && time.Now().Before(c.connectionIdReceived.Add(time.Minute))
}
+func (c *udpAnnounce) dialNetwork() string {
+ if c.a.UdpNetwork != "" {
+ return c.a.UdpNetwork
+ }
+ return "udp"
+}
+
func (c *udpAnnounce) connect() (err error) {
if c.connected() {
return nil
hmp.NoPort = false
hmp.Port = 80
}
- c.socket, err = net.Dial("udp", hmp.String())
+ c.socket, err = net.Dial(c.dialNetwork(), hmp.String())
if err != nil {
return
}
// TODO: Split on IPv6, as BEP 15 says response peer decoding depends on
// network in use.
-func announceUDP(ar *AnnounceRequest, _url *url.URL) (AnnounceResponse, error) {
+func announceUDP(opt Announce, _url *url.URL) (AnnounceResponse, error) {
ua := udpAnnounce{
url: *_url,
+ a: &opt,
}
defer ua.Close()
- return ua.Do(ar)
+ return ua.Do(&opt.Request)
}