mirror of
https://github.com/go-i2p/go-i2p-bt.git
synced 2025-07-13 11:54:35 -04:00
update tracker interface
This commit is contained in:
@ -20,6 +20,7 @@
|
||||
package httptracker
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
@ -115,7 +116,7 @@ func (r AnnounceRequest) ToQuery() (vs url.Values) {
|
||||
if r.Port > 0 {
|
||||
vs.Set("port", strconv.FormatUint(uint64(r.Port), 10))
|
||||
}
|
||||
if r.NumWant > 0 {
|
||||
if r.NumWant != 0 {
|
||||
vs.Set("numwant", strconv.FormatUint(uint64(r.NumWant), 10))
|
||||
}
|
||||
if r.Key != 0 {
|
||||
@ -264,24 +265,28 @@ func (sr ScrapeResponse) EncodeTo(w io.Writer) (err error) {
|
||||
return bencode.NewEncoder(w).Encode(sr)
|
||||
}
|
||||
|
||||
// TrackerClient represents a tracker client based on HTTP/HTTPS.
|
||||
type TrackerClient struct {
|
||||
// Client represents a tracker client based on HTTP/HTTPS.
|
||||
type Client struct {
|
||||
AnnounceURL string
|
||||
ScrapeURL string
|
||||
}
|
||||
|
||||
// NewTrackerClient returns a new HTTPTrackerClient.
|
||||
// NewClient returns a new HTTPClient.
|
||||
//
|
||||
// scrapeURL may be empty, which will replace the "announce" in announceURL
|
||||
// with "scrape" to generate the scrapeURL.
|
||||
func NewTrackerClient(announceURL, scrapeURL string) *TrackerClient {
|
||||
func NewClient(announceURL, scrapeURL string) *Client {
|
||||
if scrapeURL == "" {
|
||||
scrapeURL = strings.Replace(announceURL, "announce", "scrape", -1)
|
||||
}
|
||||
return &TrackerClient{AnnounceURL: announceURL, ScrapeURL: scrapeURL}
|
||||
return &Client{AnnounceURL: announceURL, ScrapeURL: scrapeURL}
|
||||
}
|
||||
|
||||
func (t *TrackerClient) send(u string, vs url.Values, r interface{}) (err error) {
|
||||
// Close closes the client, which does nothing at present.
|
||||
func (t *Client) Close() error { return nil }
|
||||
func (t *Client) String() string { return t.AnnounceURL }
|
||||
|
||||
func (t *Client) send(c context.Context, u string, vs url.Values, r interface{}) (err error) {
|
||||
sym := "?"
|
||||
if strings.IndexByte(u, '?') > 0 {
|
||||
sym = "&"
|
||||
@ -296,17 +301,19 @@ func (t *TrackerClient) send(u string, vs url.Values, r interface{}) (err error)
|
||||
}
|
||||
|
||||
// Announce sends a Announce request to the tracker.
|
||||
func (t *TrackerClient) Announce(req AnnounceRequest) (resp AnnounceResponse, err error) {
|
||||
err = t.send(t.AnnounceURL, req.ToQuery(), &resp)
|
||||
func (t *Client) Announce(c context.Context, req AnnounceRequest) (
|
||||
resp AnnounceResponse, err error) {
|
||||
err = t.send(c, t.AnnounceURL, req.ToQuery(), &resp)
|
||||
return
|
||||
}
|
||||
|
||||
// Scrape sends a Scrape request to the tracker.
|
||||
func (t *TrackerClient) Scrape(infohashes []metainfo.Hash) (resp ScrapeResponse, err error) {
|
||||
func (t *Client) Scrape(c context.Context, infohashes []metainfo.Hash) (
|
||||
resp ScrapeResponse, err error) {
|
||||
hs := make([]string, len(infohashes))
|
||||
for i, h := range infohashes {
|
||||
hs[i] = h.BytesString()
|
||||
}
|
||||
err = t.send(t.ScrapeURL, url.Values{"info_hash": hs}, &resp)
|
||||
err = t.send(c, t.ScrapeURL, url.Values{"info_hash": hs}, &resp)
|
||||
return
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ package tracker
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
@ -43,18 +44,18 @@ const (
|
||||
//
|
||||
// BEP 3, 15
|
||||
type AnnounceRequest struct {
|
||||
InfoHash metainfo.Hash
|
||||
PeerID metainfo.Hash
|
||||
InfoHash metainfo.Hash // Required
|
||||
PeerID metainfo.Hash // Required
|
||||
|
||||
Uploaded int64
|
||||
Downloaded int64
|
||||
Left int64
|
||||
Event uint32
|
||||
Uploaded int64 // Required, but default: 0, which should be only used for test or first.
|
||||
Downloaded int64 // Required, but default: 0, which should be only used for test or first.
|
||||
Left int64 // Required, but default: 0, which should be only used for test or last.
|
||||
Event uint32 // Required, but default: 0
|
||||
|
||||
IP net.IP
|
||||
Key int32
|
||||
NumWant int32 // -1 for default
|
||||
Port uint16
|
||||
IP net.IP // Optional
|
||||
Key int32 // Optional
|
||||
NumWant int32 // Optional, BEP 15: -1 for default. But we use 0 as default.
|
||||
Port uint16 // Optional
|
||||
}
|
||||
|
||||
// ToHTTPAnnounceRequest creates a new httptracker.AnnounceRequest from itself.
|
||||
@ -187,8 +188,10 @@ func (sr ScrapeResponse) FromUDPScrapeResponse(hs []metainfo.Hash,
|
||||
|
||||
// Client is the interface of BT tracker client.
|
||||
type Client interface {
|
||||
Announce(AnnounceRequest) (AnnounceResponse, error)
|
||||
Scrape([]metainfo.Hash) (ScrapeResponse, error)
|
||||
Announce(context.Context, AnnounceRequest) (AnnounceResponse, error)
|
||||
Scrape(context.Context, []metainfo.Hash) (ScrapeResponse, error)
|
||||
String() string
|
||||
Close() error
|
||||
}
|
||||
|
||||
// NewClient returns a new Client.
|
||||
@ -197,16 +200,16 @@ func NewClient(connURL string) (c Client, err error) {
|
||||
if err == nil {
|
||||
switch u.Scheme {
|
||||
case "http", "https":
|
||||
c = &tclient{http: httptracker.NewTrackerClient(connURL, "")}
|
||||
c = &tclient{url: connURL, http: httptracker.NewClient(connURL, "")}
|
||||
case "udp", "udp4", "udp6":
|
||||
var utc *udptracker.TrackerClient
|
||||
utc, err = udptracker.NewTrackerClientByDial(u.Scheme, u.Host)
|
||||
var utc *udptracker.Client
|
||||
utc, err = udptracker.NewClientByDial(u.Scheme, u.Host)
|
||||
if err == nil {
|
||||
var e []udptracker.Extension
|
||||
if p := u.RequestURI(); p != "" {
|
||||
e = []udptracker.Extension{udptracker.NewURLData([]byte(p))}
|
||||
}
|
||||
c = &tclient{exts: e, udp: utc}
|
||||
c = &tclient{url: connURL, exts: e, udp: utc}
|
||||
}
|
||||
default:
|
||||
err = fmt.Errorf("unknown url scheme '%s'", u.Scheme)
|
||||
@ -216,15 +219,25 @@ func NewClient(connURL string) (c Client, err error) {
|
||||
}
|
||||
|
||||
type tclient struct {
|
||||
http *httptracker.TrackerClient // BEP 3
|
||||
udp *udptracker.TrackerClient // BEP 15
|
||||
exts []udptracker.Extension // BEP 41
|
||||
url string
|
||||
http *httptracker.Client // BEP 3
|
||||
udp *udptracker.Client // BEP 15
|
||||
exts []udptracker.Extension // BEP 41
|
||||
}
|
||||
|
||||
func (c *tclient) Announce(req AnnounceRequest) (resp AnnounceResponse, err error) {
|
||||
func (c *tclient) String() string { return c.url }
|
||||
|
||||
func (c *tclient) Close() error {
|
||||
if c.http != nil {
|
||||
return c.http.Close()
|
||||
}
|
||||
return c.udp.Close()
|
||||
}
|
||||
|
||||
func (c *tclient) Announce(ctx context.Context, req AnnounceRequest) (resp AnnounceResponse, err error) {
|
||||
if c.http != nil {
|
||||
var r httptracker.AnnounceResponse
|
||||
if r, err = c.http.Announce(req.ToHTTPAnnounceRequest()); err != nil {
|
||||
if r, err = c.http.Announce(ctx, req.ToHTTPAnnounceRequest()); err != nil {
|
||||
return
|
||||
} else if r.FailureReason != "" {
|
||||
err = errors.New(r.FailureReason)
|
||||
@ -236,17 +249,17 @@ func (c *tclient) Announce(req AnnounceRequest) (resp AnnounceResponse, err erro
|
||||
|
||||
r := req.ToUDPAnnounceRequest()
|
||||
r.Exts = c.exts
|
||||
rs, err := c.udp.Announce(r)
|
||||
rs, err := c.udp.Announce(ctx, r)
|
||||
if err == nil {
|
||||
resp.FromUDPAnnounceResponse(rs)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (c *tclient) Scrape(hs []metainfo.Hash) (resp ScrapeResponse, err error) {
|
||||
func (c *tclient) Scrape(ctx context.Context, hs []metainfo.Hash) (resp ScrapeResponse, err error) {
|
||||
if c.http != nil {
|
||||
var r httptracker.ScrapeResponse
|
||||
if r, err = c.http.Scrape(hs); err != nil {
|
||||
if r, err = c.http.Scrape(ctx, hs); err != nil {
|
||||
return
|
||||
} else if r.FailureReason != "" {
|
||||
err = errors.New(r.FailureReason)
|
||||
@ -257,7 +270,7 @@ func (c *tclient) Scrape(hs []metainfo.Hash) (resp ScrapeResponse, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
r, err := c.udp.Scrape(hs)
|
||||
r, err := c.udp.Scrape(ctx, hs)
|
||||
if err == nil {
|
||||
resp = make(ScrapeResponse, len(r))
|
||||
resp.FromUDPScrapeResponse(hs, r)
|
||||
|
@ -15,6 +15,7 @@
|
||||
package tracker
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
@ -73,7 +74,7 @@ func ExampleClient() {
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
server := udptracker.NewTrackerServer(sconn, testHandler{})
|
||||
server := udptracker.NewServer(sconn, testHandler{})
|
||||
defer server.Close()
|
||||
go server.Run()
|
||||
|
||||
@ -89,7 +90,7 @@ func ExampleClient() {
|
||||
// Send the ANNOUNCE request to the UDP tracker server,
|
||||
// and get the ANNOUNCE response.
|
||||
req := AnnounceRequest{IP: net.ParseIP("127.0.0.1"), Port: 80}
|
||||
resp, err := client.Announce(req)
|
||||
resp, err := client.Announce(context.Background(), req)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
@ -106,7 +107,7 @@ func ExampleClient() {
|
||||
// and get the SCRAPE respsone.
|
||||
h1 := metainfo.Hash{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
|
||||
h2 := metainfo.Hash{2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}
|
||||
rs, err := client.Scrape([]metainfo.Hash{h1, h2})
|
||||
rs, err := client.Scrape(context.Background(), []metainfo.Hash{h1, h2})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
} else if len(rs) != 2 {
|
||||
|
@ -16,6 +16,7 @@ package udptracker
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"io"
|
||||
@ -27,33 +28,30 @@ import (
|
||||
"github.com/xgfone/bt/metainfo"
|
||||
)
|
||||
|
||||
// NewTrackerClientByDial returns a new TrackerClient by dialing.
|
||||
func NewTrackerClientByDial(network, address string, c ...TrackerClientConfig) (
|
||||
*TrackerClient, error) {
|
||||
// NewClientByDial returns a new Client by dialing.
|
||||
func NewClientByDial(network, address string, c ...ClientConfig) (*Client, error) {
|
||||
conn, err := net.Dial(network, address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return NewTrackerClient(conn.(*net.UDPConn), c...), nil
|
||||
return NewClient(conn.(*net.UDPConn), c...), nil
|
||||
}
|
||||
|
||||
// NewTrackerClient returns a new TrackerClient.
|
||||
func NewTrackerClient(conn *net.UDPConn, c ...TrackerClientConfig) *TrackerClient {
|
||||
var conf TrackerClientConfig
|
||||
// NewClient returns a new Client.
|
||||
func NewClient(conn *net.UDPConn, c ...ClientConfig) *Client {
|
||||
var conf ClientConfig
|
||||
conf.set(c...)
|
||||
ipv4 := strings.Contains(conn.LocalAddr().String(), ".")
|
||||
return &TrackerClient{conn: conn, conf: conf, ipv4: ipv4}
|
||||
return &Client{conn: conn, conf: conf, ipv4: ipv4}
|
||||
}
|
||||
|
||||
// TrackerClientConfig is used to configure the TrackerClient.
|
||||
type TrackerClientConfig struct {
|
||||
// ReadTimeout is used to receive the response.
|
||||
ReadTimeout time.Duration // Default: 5s
|
||||
MaxBufSize int // Default: 2048
|
||||
// ClientConfig is used to configure the Client.
|
||||
type ClientConfig struct {
|
||||
MaxBufSize int // Default: 2048
|
||||
}
|
||||
|
||||
func (c *TrackerClientConfig) set(conf ...TrackerClientConfig) {
|
||||
func (c *ClientConfig) set(conf ...ClientConfig) {
|
||||
if len(conf) > 0 {
|
||||
*c = conf[0]
|
||||
}
|
||||
@ -61,20 +59,17 @@ func (c *TrackerClientConfig) set(conf ...TrackerClientConfig) {
|
||||
if c.MaxBufSize <= 0 {
|
||||
c.MaxBufSize = 2048
|
||||
}
|
||||
if c.ReadTimeout <= 0 {
|
||||
c.ReadTimeout = time.Second * 5
|
||||
}
|
||||
}
|
||||
|
||||
// TrackerClient is a tracker client based on UDP.
|
||||
// Client is a tracker client based on UDP.
|
||||
//
|
||||
// Notice: the request is synchronized, that's, the last request is not returned,
|
||||
// the next request must not be sent.
|
||||
//
|
||||
// BEP 15
|
||||
type TrackerClient struct {
|
||||
type Client struct {
|
||||
ipv4 bool
|
||||
conf TrackerClientConfig
|
||||
conf ClientConfig
|
||||
conn *net.UDPConn
|
||||
last time.Time
|
||||
cid uint64
|
||||
@ -82,24 +77,39 @@ type TrackerClient struct {
|
||||
}
|
||||
|
||||
// Close closes the UDP tracker client.
|
||||
func (utc *TrackerClient) Close() { utc.conn.Close() }
|
||||
func (utc *Client) Close() error { return utc.conn.Close() }
|
||||
func (utc *Client) String() string { return utc.conn.RemoteAddr().String() }
|
||||
|
||||
func (utc *TrackerClient) readResp(b []byte) (int, error) {
|
||||
utc.conn.SetReadDeadline(time.Now().Add(utc.conf.ReadTimeout))
|
||||
return utc.conn.Read(b)
|
||||
func (utc *Client) readResp(ctx context.Context, b []byte) (int, error) {
|
||||
done := make(chan struct{})
|
||||
|
||||
var n int
|
||||
var err error
|
||||
go func() {
|
||||
n, err = utc.conn.Read(b)
|
||||
close(done)
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
utc.conn.SetReadDeadline(time.Now())
|
||||
return n, ctx.Err()
|
||||
case <-done:
|
||||
return n, err
|
||||
}
|
||||
}
|
||||
|
||||
func (utc *TrackerClient) getTranID() uint32 {
|
||||
func (utc *Client) getTranID() uint32 {
|
||||
return atomic.AddUint32(&utc.tid, 1)
|
||||
}
|
||||
|
||||
func (utc *TrackerClient) parseError(b []byte) (tid uint32, reason string) {
|
||||
func (utc *Client) parseError(b []byte) (tid uint32, reason string) {
|
||||
tid = binary.BigEndian.Uint32(b[:4])
|
||||
reason = string(b[4:])
|
||||
return
|
||||
}
|
||||
|
||||
func (utc *TrackerClient) send(b []byte) (err error) {
|
||||
func (utc *Client) send(b []byte) (err error) {
|
||||
n, err := utc.conn.Write(b)
|
||||
if err == nil && n < len(b) {
|
||||
err = io.ErrShortWrite
|
||||
@ -107,7 +117,7 @@ func (utc *TrackerClient) send(b []byte) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (utc *TrackerClient) connect() (err error) {
|
||||
func (utc *Client) connect(ctx context.Context) (err error) {
|
||||
tid := utc.getTranID()
|
||||
buf := bytes.NewBuffer(make([]byte, 0, 16))
|
||||
binary.Write(buf, binary.BigEndian, ProtocolID)
|
||||
@ -118,7 +128,7 @@ func (utc *TrackerClient) connect() (err error) {
|
||||
}
|
||||
|
||||
data := make([]byte, 32)
|
||||
n, err := utc.readResp(data)
|
||||
n, err := utc.readResp(ctx, data)
|
||||
if err != nil {
|
||||
return
|
||||
} else if n < 8 {
|
||||
@ -148,18 +158,19 @@ func (utc *TrackerClient) connect() (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (utc *TrackerClient) getConnectionID() (cid uint64, err error) {
|
||||
func (utc *Client) getConnectionID(ctx context.Context) (cid uint64, err error) {
|
||||
cid = utc.cid
|
||||
if time.Now().Sub(utc.last) > time.Minute {
|
||||
if err = utc.connect(); err == nil {
|
||||
if err = utc.connect(ctx); err == nil {
|
||||
cid = utc.cid
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (utc *TrackerClient) announce(req AnnounceRequest) (r AnnounceResponse, err error) {
|
||||
cid, err := utc.getConnectionID()
|
||||
func (utc *Client) announce(ctx context.Context, req AnnounceRequest) (
|
||||
r AnnounceResponse, err error) {
|
||||
cid, err := utc.getConnectionID(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@ -176,7 +187,7 @@ func (utc *TrackerClient) announce(req AnnounceRequest) (r AnnounceResponse, err
|
||||
}
|
||||
|
||||
data := make([]byte, utc.conf.MaxBufSize)
|
||||
n, err := utc.readResp(data)
|
||||
n, err := utc.readResp(ctx, data)
|
||||
if err != nil {
|
||||
return
|
||||
} else if n < 8 {
|
||||
@ -217,22 +228,23 @@ func (utc *TrackerClient) announce(req AnnounceRequest) (r AnnounceResponse, err
|
||||
// then send the ANNOUNCE request.
|
||||
// 2. If returning an error, you should retry it.
|
||||
// See http://www.bittorrent.org/beps/bep_0015.html#time-outs
|
||||
func (utc *TrackerClient) Announce(r AnnounceRequest) (AnnounceResponse, error) {
|
||||
return utc.announce(r)
|
||||
func (utc *Client) Announce(c context.Context, r AnnounceRequest) (AnnounceResponse, error) {
|
||||
return utc.announce(c, r)
|
||||
}
|
||||
|
||||
func (utc *TrackerClient) scrape(infohashes []metainfo.Hash) (rs []ScrapeResponse, err error) {
|
||||
cid, err := utc.getConnectionID()
|
||||
func (utc *Client) scrape(c context.Context, ihs []metainfo.Hash) (
|
||||
rs []ScrapeResponse, err error) {
|
||||
cid, err := utc.getConnectionID(c)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
tid := utc.getTranID()
|
||||
buf := bytes.NewBuffer(make([]byte, 0, 16+len(infohashes)*20))
|
||||
buf := bytes.NewBuffer(make([]byte, 0, 16+len(ihs)*20))
|
||||
binary.Write(buf, binary.BigEndian, cid)
|
||||
binary.Write(buf, binary.BigEndian, ActionScrape)
|
||||
binary.Write(buf, binary.BigEndian, tid)
|
||||
for _, h := range infohashes {
|
||||
for _, h := range ihs {
|
||||
buf.Write(h[:])
|
||||
}
|
||||
if err = utc.send(buf.Bytes()); err != nil {
|
||||
@ -240,7 +252,7 @@ func (utc *TrackerClient) scrape(infohashes []metainfo.Hash) (rs []ScrapeRespons
|
||||
}
|
||||
|
||||
data := make([]byte, utc.conf.MaxBufSize)
|
||||
n, err := utc.readResp(data)
|
||||
n, err := utc.readResp(c, data)
|
||||
if err != nil {
|
||||
return
|
||||
} else if n < 8 {
|
||||
@ -284,6 +296,6 @@ func (utc *TrackerClient) scrape(infohashes []metainfo.Hash) (rs []ScrapeRespons
|
||||
// then send the ANNOUNCE request.
|
||||
// 2. If returning an error, you should retry it.
|
||||
// See http://www.bittorrent.org/beps/bep_0015.html#time-outs
|
||||
func (utc *TrackerClient) Scrape(hs []metainfo.Hash) ([]ScrapeResponse, error) {
|
||||
return utc.scrape(hs)
|
||||
func (utc *Client) Scrape(c context.Context, hs []metainfo.Hash) ([]ScrapeResponse, error) {
|
||||
return utc.scrape(c, hs)
|
||||
}
|
||||
|
@ -27,8 +27,8 @@ import (
|
||||
"github.com/xgfone/bt/metainfo"
|
||||
)
|
||||
|
||||
// TrackerServerHandler is used to handle the request from the client.
|
||||
type TrackerServerHandler interface {
|
||||
// ServerHandler is used to handle the request from the client.
|
||||
type ServerHandler interface {
|
||||
// OnConnect is used to check whether to make the connection or not.
|
||||
OnConnect(raddr *net.UDPAddr) (err error)
|
||||
OnAnnounce(raddr *net.UDPAddr, req AnnounceRequest) (AnnounceResponse, error)
|
||||
@ -45,13 +45,13 @@ type wrappedPeerAddr struct {
|
||||
Time time.Time
|
||||
}
|
||||
|
||||
// TrackerServerConfig is used to configure the TrackerServer.
|
||||
type TrackerServerConfig struct {
|
||||
// ServerConfig is used to configure the Server.
|
||||
type ServerConfig struct {
|
||||
MaxBufSize int // Default: 2048
|
||||
ErrorLog func(format string, args ...interface{}) // Default: log.Printf
|
||||
}
|
||||
|
||||
func (c *TrackerServerConfig) setDefault() {
|
||||
func (c *ServerConfig) setDefault() {
|
||||
if c.MaxBufSize <= 0 {
|
||||
c.MaxBufSize = 2048
|
||||
}
|
||||
@ -60,11 +60,11 @@ func (c *TrackerServerConfig) setDefault() {
|
||||
}
|
||||
}
|
||||
|
||||
// TrackerServer is a tracker server based on UDP.
|
||||
type TrackerServer struct {
|
||||
// Server is a tracker server based on UDP.
|
||||
type Server struct {
|
||||
conn net.PacketConn
|
||||
conf TrackerServerConfig
|
||||
handler TrackerServerHandler
|
||||
conf ServerConfig
|
||||
handler ServerHandler
|
||||
bufpool sync.Pool
|
||||
|
||||
cid uint64
|
||||
@ -73,16 +73,15 @@ type TrackerServer struct {
|
||||
conns map[uint64]wrappedPeerAddr
|
||||
}
|
||||
|
||||
// NewTrackerServer returns a new TrackerServer.
|
||||
func NewTrackerServer(c net.PacketConn, h TrackerServerHandler,
|
||||
config ...TrackerServerConfig) *TrackerServer {
|
||||
var conf TrackerServerConfig
|
||||
if len(config) > 0 {
|
||||
conf = config[0]
|
||||
// NewServer returns a new Server.
|
||||
func NewServer(c net.PacketConn, h ServerHandler, sc ...ServerConfig) *Server {
|
||||
var conf ServerConfig
|
||||
if len(sc) > 0 {
|
||||
conf = sc[0]
|
||||
}
|
||||
conf.setDefault()
|
||||
|
||||
s := &TrackerServer{
|
||||
s := &Server{
|
||||
conf: conf,
|
||||
conn: c,
|
||||
handler: h,
|
||||
@ -95,7 +94,7 @@ func NewTrackerServer(c net.PacketConn, h TrackerServerHandler,
|
||||
}
|
||||
|
||||
// Close closes the tracker server.
|
||||
func (uts *TrackerServer) Close() {
|
||||
func (uts *Server) Close() {
|
||||
select {
|
||||
case <-uts.exit:
|
||||
default:
|
||||
@ -104,7 +103,7 @@ func (uts *TrackerServer) Close() {
|
||||
}
|
||||
}
|
||||
|
||||
func (uts *TrackerServer) cleanConnectionID(interval time.Duration) {
|
||||
func (uts *Server) cleanConnectionID(interval time.Duration) {
|
||||
tick := time.NewTicker(interval)
|
||||
defer tick.Stop()
|
||||
for {
|
||||
@ -124,7 +123,7 @@ func (uts *TrackerServer) cleanConnectionID(interval time.Duration) {
|
||||
}
|
||||
|
||||
// Run starts the tracker server.
|
||||
func (uts *TrackerServer) Run() {
|
||||
func (uts *Server) Run() {
|
||||
go uts.cleanConnectionID(time.Minute * 2)
|
||||
for {
|
||||
buf := uts.bufpool.Get().([]byte)
|
||||
@ -141,12 +140,12 @@ func (uts *TrackerServer) Run() {
|
||||
}
|
||||
}
|
||||
|
||||
func (uts *TrackerServer) handleRequest(raddr *net.UDPAddr, buf []byte, n int) {
|
||||
func (uts *Server) handleRequest(raddr *net.UDPAddr, buf []byte, n int) {
|
||||
defer uts.bufpool.Put(buf)
|
||||
uts.handlePacket(raddr, buf[:n])
|
||||
}
|
||||
|
||||
func (uts *TrackerServer) send(raddr *net.UDPAddr, b []byte) {
|
||||
func (uts *Server) send(raddr *net.UDPAddr, b []byte) {
|
||||
n, err := uts.conn.WriteTo(b, raddr)
|
||||
if err != nil {
|
||||
uts.conf.ErrorLog("fail to send the udp tracker response to '%s': %s",
|
||||
@ -156,18 +155,18 @@ func (uts *TrackerServer) send(raddr *net.UDPAddr, b []byte) {
|
||||
}
|
||||
}
|
||||
|
||||
func (uts *TrackerServer) getConnectionID() uint64 {
|
||||
func (uts *Server) getConnectionID() uint64 {
|
||||
return atomic.AddUint64(&uts.cid, 1)
|
||||
}
|
||||
|
||||
func (uts *TrackerServer) addConnection(cid uint64, raddr *net.UDPAddr) {
|
||||
func (uts *Server) addConnection(cid uint64, raddr *net.UDPAddr) {
|
||||
now := time.Now()
|
||||
uts.lock.Lock()
|
||||
uts.conns[cid] = wrappedPeerAddr{Addr: raddr, Time: now}
|
||||
uts.lock.Unlock()
|
||||
}
|
||||
|
||||
func (uts *TrackerServer) checkConnection(cid uint64, raddr *net.UDPAddr) (ok bool) {
|
||||
func (uts *Server) checkConnection(cid uint64, raddr *net.UDPAddr) (ok bool) {
|
||||
uts.lock.RLock()
|
||||
if w, _ok := uts.conns[cid]; _ok && w.Addr.Port == raddr.Port &&
|
||||
bytes.Equal(w.Addr.IP, raddr.IP) {
|
||||
@ -177,21 +176,21 @@ func (uts *TrackerServer) checkConnection(cid uint64, raddr *net.UDPAddr) (ok bo
|
||||
return
|
||||
}
|
||||
|
||||
func (uts *TrackerServer) sendError(raddr *net.UDPAddr, tid uint32, reason string) {
|
||||
func (uts *Server) sendError(raddr *net.UDPAddr, tid uint32, reason string) {
|
||||
buf := bytes.NewBuffer(make([]byte, 0, 8+len(reason)))
|
||||
encodeResponseHeader(buf, ActionError, tid)
|
||||
buf.WriteString(reason)
|
||||
uts.send(raddr, buf.Bytes())
|
||||
}
|
||||
|
||||
func (uts *TrackerServer) sendConnResp(raddr *net.UDPAddr, tid uint32, cid uint64) {
|
||||
func (uts *Server) sendConnResp(raddr *net.UDPAddr, tid uint32, cid uint64) {
|
||||
buf := bytes.NewBuffer(make([]byte, 0, 16))
|
||||
encodeResponseHeader(buf, ActionConnect, tid)
|
||||
binary.Write(buf, binary.BigEndian, cid)
|
||||
uts.send(raddr, buf.Bytes())
|
||||
}
|
||||
|
||||
func (uts *TrackerServer) sendAnnounceResp(raddr *net.UDPAddr, tid uint32,
|
||||
func (uts *Server) sendAnnounceResp(raddr *net.UDPAddr, tid uint32,
|
||||
resp AnnounceResponse) {
|
||||
buf := bytes.NewBuffer(make([]byte, 0, 8+12+len(resp.Addresses)*18))
|
||||
encodeResponseHeader(buf, ActionAnnounce, tid)
|
||||
@ -199,7 +198,7 @@ func (uts *TrackerServer) sendAnnounceResp(raddr *net.UDPAddr, tid uint32,
|
||||
uts.send(raddr, buf.Bytes())
|
||||
}
|
||||
|
||||
func (uts *TrackerServer) sendScrapResp(raddr *net.UDPAddr, tid uint32,
|
||||
func (uts *Server) sendScrapResp(raddr *net.UDPAddr, tid uint32,
|
||||
rs []ScrapeResponse) {
|
||||
buf := bytes.NewBuffer(make([]byte, 0, 8+len(rs)*12))
|
||||
encodeResponseHeader(buf, ActionScrape, tid)
|
||||
@ -209,7 +208,7 @@ func (uts *TrackerServer) sendScrapResp(raddr *net.UDPAddr, tid uint32,
|
||||
uts.send(raddr, buf.Bytes())
|
||||
}
|
||||
|
||||
func (uts *TrackerServer) handlePacket(raddr *net.UDPAddr, b []byte) {
|
||||
func (uts *Server) handlePacket(raddr *net.UDPAddr, b []byte) {
|
||||
cid := binary.BigEndian.Uint64(b[:8])
|
||||
action := binary.BigEndian.Uint32(b[8:12])
|
||||
tid := binary.BigEndian.Uint32(b[12:16])
|
||||
|
@ -15,6 +15,7 @@
|
||||
package udptracker
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
@ -66,13 +67,13 @@ func (testHandler) OnScrap(raddr *net.UDPAddr, infohashes []metainfo.Hash) (
|
||||
return
|
||||
}
|
||||
|
||||
func ExampleTrackerClient() {
|
||||
func ExampleClient() {
|
||||
// Start the UDP tracker server
|
||||
sconn, err := net.ListenPacket("udp4", "127.0.0.1:8001")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
server := NewTrackerServer(sconn, testHandler{})
|
||||
server := NewServer(sconn, testHandler{})
|
||||
defer server.Close()
|
||||
go server.Run()
|
||||
|
||||
@ -80,7 +81,7 @@ func ExampleTrackerClient() {
|
||||
time.Sleep(time.Second)
|
||||
|
||||
// Create a client and dial to the UDP tracker server.
|
||||
client, err := NewTrackerClientByDial("udp4", "127.0.0.1:8001")
|
||||
client, err := NewClientByDial("udp4", "127.0.0.1:8001")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
@ -89,7 +90,7 @@ func ExampleTrackerClient() {
|
||||
// and get the ANNOUNCE response.
|
||||
exts := []Extension{NewURLData([]byte("data")), NewNop()}
|
||||
req := AnnounceRequest{IP: net.ParseIP("127.0.0.1"), Port: 80, Exts: exts}
|
||||
resp, err := client.Announce(req)
|
||||
resp, err := client.Announce(context.Background(), req)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
@ -105,7 +106,7 @@ func ExampleTrackerClient() {
|
||||
// Send the SCRAPE request to the UDP tracker server,
|
||||
// and get the SCRAPE respsone.
|
||||
hs := []metainfo.Hash{metainfo.NewRandomHash(), metainfo.NewRandomHash()}
|
||||
rs, err := client.Scrape(hs)
|
||||
rs, err := client.Scrape(context.Background(), hs)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
} else if len(rs) != 2 {
|
||||
|
Reference in New Issue
Block a user