]> Sergey Matveev's repositories - btrtrc.git/blob - tracker/udp/conn-client.go
a91cacba86cbe2ecd1b92ecee8b61462d3255aa9
[btrtrc.git] / tracker / udp / conn-client.go
1 package udp
2
3 import (
4         "context"
5         "net"
6
7         "github.com/anacrolix/dht/v2/krpc"
8         "github.com/anacrolix/missinggo/v2"
9 )
10
11 type NewConnClientOpts struct {
12         Network string
13         Host    string
14         Ipv6    *bool
15 }
16
17 type ConnClient struct {
18         cl      Client
19         conn    net.Conn
20         d       Dispatcher
21         readErr error
22         ipv6    bool
23 }
24
25 func (cc *ConnClient) reader() {
26         for {
27                 b := make([]byte, 0x800)
28                 n, err := cc.conn.Read(b)
29                 if err != nil {
30                         // TODO: Do bad things to the dispatcher, and incoming calls to the client if we have a
31                         // read error.
32                         cc.readErr = err
33                         break
34                 }
35                 err = cc.d.Dispatch(b[:n])
36                 if err != nil {
37                         //log.Printf("dispatching packet received on %v (%q): %v", cc.conn, string(b[:n]), err)
38                 }
39         }
40 }
41
42 func ipv6(opt *bool, network string, conn net.Conn) bool {
43         if opt != nil {
44                 return *opt
45         }
46         switch network {
47         case "udp4":
48                 return false
49         case "udp6":
50                 return true
51         }
52         rip := missinggo.AddrIP(conn.RemoteAddr())
53         return rip.To16() != nil && rip.To4() == nil
54 }
55
56 func NewConnClient(opts NewConnClientOpts) (cc *ConnClient, err error) {
57         conn, err := net.Dial(opts.Network, opts.Host)
58         if err != nil {
59                 return
60         }
61         cc = &ConnClient{
62                 cl: Client{
63                         Writer: conn,
64                 },
65                 conn: conn,
66                 ipv6: ipv6(opts.Ipv6, opts.Network, conn),
67         }
68         cc.cl.Dispatcher = &cc.d
69         go cc.reader()
70         return
71 }
72
73 func (c *ConnClient) Close() error {
74         return c.conn.Close()
75 }
76
77 func (c *ConnClient) Announce(
78         ctx context.Context, req AnnounceRequest, opts Options,
79 ) (
80         h AnnounceResponseHeader, nas AnnounceResponsePeers, err error,
81 ) {
82         nas = func() AnnounceResponsePeers {
83                 if c.ipv6 {
84                         return &krpc.CompactIPv6NodeAddrs{}
85                 } else {
86                         return &krpc.CompactIPv4NodeAddrs{}
87                 }
88         }()
89         h, err = c.cl.Announce(ctx, req, nas, opts)
90         return
91 }