From: Matt Joiner Date: Mon, 5 Dec 2022 06:52:03 +0000 (+1100) Subject: Support HTTP tracker server X-Git-Tag: v1.49.0~7^2~30 X-Git-Url: http://www.git.stargrave.org/?a=commitdiff_plain;h=6b5c2fa1b0d5ab4da419e6d085f00ae06bf2ead1;p=btrtrc.git Support HTTP tracker server --- diff --git a/tracker/http/server/server.go b/tracker/http/server/server.go new file mode 100644 index 00000000..88457826 --- /dev/null +++ b/tracker/http/server/server.go @@ -0,0 +1,94 @@ +package httpTrackerServer + +import ( + "fmt" + "net" + "net/http" + "net/netip" + "net/url" + + "github.com/anacrolix/dht/v2/krpc" + "github.com/anacrolix/log" + + "github.com/anacrolix/torrent/bencode" + "github.com/anacrolix/torrent/tracker" + httpTracker "github.com/anacrolix/torrent/tracker/http" + udpTrackerServer "github.com/anacrolix/torrent/tracker/udp/server" +) + +type Handler struct { + AnnounceTracker udpTrackerServer.AnnounceTracker +} + +func unmarshalQueryKeyToArray(w http.ResponseWriter, key string, query url.Values) (ret [20]byte, ok bool) { + str := query.Get(key) + if len(str) != len(ret) { + http.Error(w, fmt.Sprintf("%v has wrong length", key), http.StatusBadRequest) + return + } + copy(ret[:], str) + ok = true + return +} + +func (me Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + vs := r.URL.Query() + var event tracker.AnnounceEvent + err := event.UnmarshalText([]byte(vs.Get("event"))) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + infoHash, ok := unmarshalQueryKeyToArray(w, "info_hash", vs) + if !ok { + return + } + peerId, ok := unmarshalQueryKeyToArray(w, "peer_id", vs) + if !ok { + return + } + host, _, err := net.SplitHostPort(r.RemoteAddr) + if err != nil { + log.Printf("error splitting remote port: %v", err) + http.Error(w, "error determining your IP", http.StatusInternalServerError) + return + } + addrPort, err := netip.ParseAddrPort(net.JoinHostPort(host, vs.Get("port"))) + err = me.AnnounceTracker.TrackAnnounce(r.Context(), tracker.AnnounceRequest{ + InfoHash: infoHash, + PeerId: peerId, + Event: event, + Port: addrPort.Port(), + }, addrPort) + if err != nil { + log.Printf("error tracking announce: %v", err) + http.Error(w, "error tracking announce", http.StatusInternalServerError) + return + } + peers, err := me.AnnounceTracker.GetPeers(r.Context(), infoHash, tracker.GetPeersOpts{}) + if err != nil { + log.Printf("error getting peers: %v", err) + http.Error(w, "error getting peers", http.StatusInternalServerError) + return + } + var resp httpTracker.HttpResponse + resp.Interval = 5 * 60 + resp.Peers.Compact = true + for _, peer := range peers { + if peer.Addr().Is4() { + resp.Peers.List = append(resp.Peers.List, tracker.Peer{ + IP: peer.Addr().AsSlice(), + Port: int(peer.Port()), + }) + } else if peer.Addr().Is6() { + resp.Peers6 = append(resp.Peers6, krpc.NodeAddr{ + IP: peer.Addr().AsSlice(), + Port: int(peer.Port()), + }) + } + } + err = bencode.NewEncoder(w).Encode(resp) + if err != nil { + log.Printf("error encoding and writing response body: %v", err) + } +} diff --git a/tracker/server.go b/tracker/server.go new file mode 100644 index 00000000..077d3244 --- /dev/null +++ b/tracker/server.go @@ -0,0 +1,35 @@ +package tracker + +import ( + "context" + "net/netip" + + "github.com/anacrolix/torrent/tracker/udp" +) + +// This is reserved for stuff like filtering by IP version, avoiding an announcer's IP or key, +// limiting return count, etc. +type GetPeersOpts struct{} + +type InfoHash = [20]byte + +type PeerInfo struct { + AnnounceAddr +} + +type AnnounceAddr = netip.AddrPort + +type AnnounceTracker interface { + TrackAnnounce(ctx context.Context, req udp.AnnounceRequest, addr AnnounceAddr) error + Scrape(ctx context.Context, infoHashes []InfoHash) ([]udp.ScrapeInfohashResult, error) + GetPeers(ctx context.Context, infoHash InfoHash, opts GetPeersOpts) ([]PeerInfo, error) +} + +// +//type Server struct { +// AnnounceTracker AnnounceTracker +//} +// +//func (me Server) HandleAnnounce(req udp.AnnounceRequest, sourceAddr AnnounceAddr) error { +// +//} diff --git a/tracker/udp/server/server.go b/tracker/udp/server/server.go index 81500214..68abb106 100644 --- a/tracker/udp/server/server.go +++ b/tracker/udp/server/server.go @@ -1,4 +1,4 @@ -package server +package udpTrackerServer import ( "bytes" @@ -12,6 +12,8 @@ import ( "github.com/anacrolix/dht/v2/krpc" "github.com/anacrolix/log" + + "github.com/anacrolix/torrent/tracker" "github.com/anacrolix/torrent/tracker/udp" ) @@ -24,19 +26,7 @@ type ConnectionTracker interface { type InfoHash = [20]byte -// This is reserved for stuff like filtering by IP version, avoiding an announcer's IP or key, -// limiting return count, etc. -type GetPeersOpts struct{} - -type PeerInfo struct { - netip.AddrPort -} - -type AnnounceTracker interface { - TrackAnnounce(ctx context.Context, req udp.AnnounceRequest, addr RequestSourceAddr) error - Scrape(ctx context.Context, infoHashes []InfoHash) ([]udp.ScrapeInfohashResult, error) - GetPeers(ctx context.Context, infoHash InfoHash, opts GetPeersOpts) ([]PeerInfo, error) -} +type AnnounceTracker = tracker.AnnounceTracker type Server struct { ConnTracker ConnectionTracker @@ -46,7 +36,12 @@ type Server struct { type RequestSourceAddr = net.Addr -func (me *Server) HandleRequest(ctx context.Context, family udp.AddrFamily, source RequestSourceAddr, body []byte) error { +func (me *Server) HandleRequest( + ctx context.Context, + family udp.AddrFamily, + source RequestSourceAddr, + body []byte, +) error { var h udp.RequestHeader var r bytes.Reader r.Reset(body) @@ -91,11 +86,16 @@ func (me *Server) handleAnnounce( return err } // TODO: This should be done asynchronously to responding to the announce. - err = me.AnnounceTracker.TrackAnnounce(ctx, req, source) + announceAddr, err := netip.ParseAddrPort(source.String()) + if err != nil { + err = fmt.Errorf("converting source net.Addr to AnnounceAddr: %w", err) + return err + } + err = me.AnnounceTracker.TrackAnnounce(ctx, req, announceAddr) if err != nil { return err } - peers, err := me.AnnounceTracker.GetPeers(ctx, req.InfoHash, GetPeersOpts{}) + peers, err := me.AnnounceTracker.GetPeers(ctx, req.InfoHash, tracker.GetPeersOpts{}) if err != nil { return err } @@ -137,7 +137,6 @@ func (me *Server) handleAnnounce( err = fmt.Errorf("marshalling compact node addrs: %w", err) return err } - log.Print(nodeAddrs) buf.Write(b) n, err := me.SendResponse(buf.Bytes(), source) if err != nil { @@ -181,7 +180,7 @@ func randomConnectionId() udp.ConnectionId { return int64(binary.BigEndian.Uint64(b[:])) } -func RunServer(ctx context.Context, s *Server, pc net.PacketConn, family udp.AddrFamily) error { +func RunSimple(ctx context.Context, s *Server, pc net.PacketConn, family udp.AddrFamily) error { ctx, cancel := context.WithCancel(ctx) defer cancel() for {