7 "github.com/anacrolix/log"
9 "github.com/anacrolix/missinggo/v2"
12 type NewConnClientOpts struct {
13 // The network to operate to use, such as "udp4", "udp", "udp6".
17 // If non-nil, forces either IPv4 or IPv6 in the UDP tracker wire protocol.
19 // Logger to use for internal errors.
23 // Manages a Client with a specific connection.
24 type ConnClient struct {
30 newOpts NewConnClientOpts
33 func (cc *ConnClient) reader() {
34 b := make([]byte, 0x800)
36 n, addr, err := cc.conn.ReadFrom(b)
38 // TODO: Do bad things to the dispatcher, and incoming calls to the client if we have a
46 err = cc.d.Dispatch(b[:n], addr)
48 cc.newOpts.Logger.Levelf(log.Debug, "dispatching packet received on %v: %v", cc.conn.LocalAddr(), err)
53 func ipv6(opt *bool, network string, remoteAddr net.Addr) bool {
63 rip := missinggo.AddrIP(remoteAddr)
64 return rip.To16() != nil && rip.To4() == nil
67 // Allows a UDP Client to write packets to an endpoint without knowing about the network specifics.
68 type clientWriter struct {
74 func (me clientWriter) Write(p []byte) (n int, err error) {
75 addr, err := net.ResolveUDPAddr(me.network, me.address)
79 return me.pc.WriteTo(p, addr)
82 func NewConnClient(opts NewConnClientOpts) (cc *ConnClient, err error) {
83 conn, err := net.ListenPacket(opts.Network, ":0")
87 if opts.Logger.IsZero() {
88 opts.Logger = log.Default
94 network: opts.Network,
101 cc.Client.Dispatcher = &cc.d
106 func (cc *ConnClient) Close() error {
108 return cc.conn.Close()
111 func (cc *ConnClient) Announce(
112 ctx context.Context, req AnnounceRequest, opts Options,
114 h AnnounceResponseHeader, nas AnnounceResponsePeers, err error,
116 return cc.Client.Announce(ctx, req, opts, func(addr net.Addr) bool {
117 return ipv6(cc.newOpts.Ipv6, cc.newOpts.Network, addr)
121 func (cc *ConnClient) LocalAddr() net.Addr {
122 return cc.conn.LocalAddr()