]> Sergey Matveev's repositories - btrtrc.git/commitdiff
Support HTTP tracker server
authorMatt Joiner <anacrolix@gmail.com>
Mon, 5 Dec 2022 06:52:03 +0000 (17:52 +1100)
committerMatt Joiner <anacrolix@gmail.com>
Tue, 6 Dec 2022 23:45:12 +0000 (10:45 +1100)
tracker/http/server/server.go [new file with mode: 0644]
tracker/server.go [new file with mode: 0644]
tracker/udp/server/server.go

diff --git a/tracker/http/server/server.go b/tracker/http/server/server.go
new file mode 100644 (file)
index 0000000..8845782
--- /dev/null
@@ -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 (file)
index 0000000..077d324
--- /dev/null
@@ -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 {
+//
+//}
index 815002147223177265625ac29639ae4280a4d7af..68abb1061aca1b8b9a6e882bf74057b8dd8ac723 100644 (file)
@@ -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 {