s/Server/Tracker
This commit is contained in:
parent
dc25c8cab2
commit
0d054414ab
3 changed files with 67 additions and 66 deletions
|
@ -161,15 +161,16 @@ type ClientError string
|
|||
// Error implements the error interface for ClientError.
|
||||
func (c ClientError) Error() string { return string(c) }
|
||||
|
||||
// Server represents an implementation of the BitTorrent tracker protocol.
|
||||
type Server interface {
|
||||
// Tracker represents an implementation of the BitTorrent tracker protocol.
|
||||
type Tracker interface {
|
||||
ListenAndServe() error
|
||||
Stop()
|
||||
}
|
||||
|
||||
// ServerFuncs are the collection of protocol-agnostic functions used to handle
|
||||
// requests in a Server.
|
||||
type ServerFuncs struct {
|
||||
// TrackerFuncs is the collection of callback functions provided to a Tracker
|
||||
// to (1) generate a response from a parsed request, and (2) observe anything
|
||||
// after the response has been delivered to the client.
|
||||
type TrackerFuncs struct {
|
||||
HandleAnnounce AnnounceHandler
|
||||
HandleScrape ScrapeHandler
|
||||
AfterAnnounce AnnounceCallback
|
||||
|
|
|
@ -23,41 +23,41 @@ type Config struct {
|
|||
RealIPHeader string
|
||||
}
|
||||
|
||||
type Server struct {
|
||||
type Tracker struct {
|
||||
grace *graceful.Server
|
||||
|
||||
bittorrent.ServerFuncs
|
||||
bittorrent.TrackerFuncs
|
||||
Config
|
||||
}
|
||||
|
||||
func NewServer(funcs bittorrent.ServerFuncs, cfg Config) {
|
||||
func NewTracker(funcs bittorrent.TrackerFuncs, cfg Config) {
|
||||
return &Server{
|
||||
ServerFuncs: funcs,
|
||||
TrackerFuncs: funcs,
|
||||
Config: cfg,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) Stop() {
|
||||
s.grace.Stop(s.grace.Timeout)
|
||||
<-s.grace.StopChan()
|
||||
func (t *Tracker) Stop() {
|
||||
t.grace.Stop(t.grace.Timeout)
|
||||
<-t.grace.StopChan()
|
||||
}
|
||||
|
||||
func (s *Server) handler() {
|
||||
func (t *Tracker) handler() {
|
||||
router := httprouter.New()
|
||||
router.GET("/announce", s.announceRoute)
|
||||
router.GET("/scrape", s.scrapeRoute)
|
||||
router.GET("/announce", t.announceRoute)
|
||||
router.GET("/scrape", t.scrapeRoute)
|
||||
return server
|
||||
}
|
||||
|
||||
func (s *Server) ListenAndServe() error {
|
||||
s.grace = &graceful.Server{
|
||||
func (t *Tracker) ListenAndServe() error {
|
||||
t.grace = &graceful.Server{
|
||||
Server: &http.Server{
|
||||
Addr: s.Addr,
|
||||
Handler: s.handler(),
|
||||
ReadTimeout: s.ReadTimeout,
|
||||
WriteTimeout: s.WriteTimeout,
|
||||
Addr: t.Addr,
|
||||
Handler: t.handler(),
|
||||
ReadTimeout: t.ReadTimeout,
|
||||
WriteTimeout: t.WriteTimeout,
|
||||
},
|
||||
Timeout: s.RequestTimeout,
|
||||
Timeout: t.RequestTimeout,
|
||||
NoSignalHandling: true,
|
||||
ConnState: func(conn net.Conn, state http.ConnState) {
|
||||
switch state {
|
||||
|
@ -78,23 +78,23 @@ func (s *Server) ListenAndServe() error {
|
|||
}
|
||||
},
|
||||
}
|
||||
s.grace.SetKeepAlivesEnabled(false)
|
||||
t.grace.SetKeepAlivesEnabled(false)
|
||||
|
||||
if err := s.grace.ListenAndServe(); err != nil {
|
||||
if err := t.grace.ListenAndServe(); err != nil {
|
||||
if opErr, ok := err.(*net.OpError); !ok || (ok && opErr.Op != "accept") {
|
||||
panic("http: failed to gracefully run HTTP server: " + err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) announceRoute(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
req, err := ParseAnnounce(r, s.RealIPHeader, s.AllowIPSpoofing)
|
||||
func (t *Tracker) announceRoute(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
req, err := ParseAnnounce(r, t.RealIPHeader, t.AllowIPSpoofing)
|
||||
if err != nil {
|
||||
WriteError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := s.HandleAnnounce(req)
|
||||
resp, err := t.HandleAnnounce(req)
|
||||
if err != nil {
|
||||
WriteError(w, err)
|
||||
return
|
||||
|
@ -106,19 +106,19 @@ func (s *Server) announceRoute(w http.ResponseWriter, r *http.Request, _ httprou
|
|||
return
|
||||
}
|
||||
|
||||
if s.AfterAnnounce != nil {
|
||||
s.AfterAnnounce(req, resp)
|
||||
if t.AfterAnnounce != nil {
|
||||
t.AfterAnnounce(req, resp)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) scrapeRoute(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
func (t *Tracker) scrapeRoute(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
req, err := ParseScrape(r)
|
||||
if err != nil {
|
||||
WriteError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := s.HandleScrape(req)
|
||||
resp, err := t.HandleScrape(req)
|
||||
if err != nil {
|
||||
WriteError(w, err)
|
||||
return
|
||||
|
@ -130,7 +130,7 @@ func (s *Server) scrapeRoute(w http.ResponseWriter, r *http.Request, _ httproute
|
|||
return
|
||||
}
|
||||
|
||||
if s.AfterScrape != nil {
|
||||
s.AfterScrape(req, resp)
|
||||
if t.AfterScrape != nil {
|
||||
t.AfterScrape(req, resp)
|
||||
}
|
||||
}
|
|
@ -38,56 +38,56 @@ type Config struct {
|
|||
AllowIPSpoofing bool
|
||||
}
|
||||
|
||||
type Server struct {
|
||||
type Tracker struct {
|
||||
sock *net.UDPConn
|
||||
closing chan struct{}
|
||||
wg sync.WaitGroup
|
||||
|
||||
bittorrent.ServerFuncs
|
||||
bittorrent.TrackerFuncs
|
||||
Config
|
||||
}
|
||||
|
||||
func NewServer(funcs bittorrent.ServerFuncs, cfg Config) {
|
||||
return &Server{
|
||||
func NewTracker(funcs bittorrent.TrackerFuncs, cfg Config) {
|
||||
return &Tracker{
|
||||
closing: make(chan struct{}),
|
||||
ServerFuncs: funcs,
|
||||
TrackerFuncs: funcs,
|
||||
Config: cfg,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *udpServer) Stop() {
|
||||
close(s.closing)
|
||||
s.sock.SetReadDeadline(time.Now())
|
||||
s.wg.Wait()
|
||||
func (t *Tracker) Stop() {
|
||||
close(t.closing)
|
||||
t.sock.SetReadDeadline(time.Now())
|
||||
t.wg.Wait()
|
||||
}
|
||||
|
||||
func (s *Server) ListenAndServe() error {
|
||||
udpAddr, err := net.ResolveUDPAddr("udp", s.Addr)
|
||||
func (t *Tracker) ListenAndServe() error {
|
||||
udpAddr, err := net.ResolveUDPAddr("udp", t.Addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.sock, err = net.ListenUDP("udp", udpAddr)
|
||||
t.sock, err = net.ListenUDP("udp", udpAddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer s.sock.Close()
|
||||
defer t.sock.Close()
|
||||
|
||||
pool := bytepool.New(256, 2048)
|
||||
|
||||
for {
|
||||
// Check to see if we need to shutdown.
|
||||
select {
|
||||
case <-s.closing:
|
||||
s.wg.Wait()
|
||||
case <-t.closing:
|
||||
t.wg.Wait()
|
||||
return nil
|
||||
default:
|
||||
}
|
||||
|
||||
// Read a UDP packet into a reusable buffer.
|
||||
buffer := pool.Get()
|
||||
s.sock.SetReadDeadline(time.Now().Add(time.Second))
|
||||
n, addr, err := s.sock.ReadFromUDP(buffer)
|
||||
t.sock.SetReadDeadline(time.Now().Add(time.Second))
|
||||
n, addr, err := t.sock.ReadFromUDP(buffer)
|
||||
if err != nil {
|
||||
pool.Put(buffer)
|
||||
if netErr, ok := err.(net.Error); ok && netErr.Temporary() {
|
||||
|
@ -105,13 +105,13 @@ func (s *Server) ListenAndServe() error {
|
|||
|
||||
log.Println("Got UDP packet")
|
||||
start := time.Now()
|
||||
s.wg.Add(1)
|
||||
t.wg.Add(1)
|
||||
go func(start time.Time) {
|
||||
defer s.wg.Done()
|
||||
defer t.wg.Done()
|
||||
defer pool.Put(buffer)
|
||||
|
||||
// Handle the response.
|
||||
response, action, err := s.handlePacket(buffer[:n], addr)
|
||||
response, action, err := t.handlePacket(buffer[:n], addr)
|
||||
log.Printf("Handled UDP packet: %s, %s, %s\n", response, action, err)
|
||||
|
||||
// Record to Prometheus the time in milliseconds to receive, handle, and
|
||||
|
@ -141,7 +141,7 @@ func (w *ResponseWriter) Write(b []byte) (int, error) {
|
|||
return len(b), nil
|
||||
}
|
||||
|
||||
func (s *Server) handlePacket(r *Request, w *ResponseWriter) (response []byte, actionName string, err error) {
|
||||
func (t *Tracker) handlePacket(r *Request, w *ResponseWriter) (response []byte, actionName string, err error) {
|
||||
if len(r.packet) < 16 {
|
||||
// Malformed, no client packets are less than 16 bytes.
|
||||
// We explicitly return nothing in case this is a DoS attempt.
|
||||
|
@ -156,7 +156,7 @@ func (s *Server) handlePacket(r *Request, w *ResponseWriter) (response []byte, a
|
|||
|
||||
// If this isn't requesting a new connection ID and the connection ID is
|
||||
// invalid, then fail.
|
||||
if actionID != connectActionID && !ValidConnectionID(connID, r.IP, time.Now(), s.PrivateKey) {
|
||||
if actionID != connectActionID && !ValidConnectionID(connID, r.IP, time.Now(), t.PrivateKey) {
|
||||
err = errBadConnectionID
|
||||
WriteError(w, txID, err)
|
||||
return
|
||||
|
@ -172,21 +172,21 @@ func (s *Server) handlePacket(r *Request, w *ResponseWriter) (response []byte, a
|
|||
return
|
||||
}
|
||||
|
||||
WriteConnectionID(w, txID, NewConnectionID(r.IP, time.Now(), s.PrivateKey))
|
||||
WriteConnectionID(w, txID, NewConnectionID(r.IP, time.Now(), t.PrivateKey))
|
||||
return
|
||||
|
||||
case announceActionID:
|
||||
actionName = "announce"
|
||||
|
||||
var req *bittorrent.AnnounceRequest
|
||||
req, err = ParseAnnounce(r, s.AllowIPSpoofing)
|
||||
req, err = ParseAnnounce(r, t.AllowIPSpoofing)
|
||||
if err != nil {
|
||||
WriteError(w, txID, err)
|
||||
return
|
||||
}
|
||||
|
||||
var resp *bittorrent.AnnounceResponse
|
||||
resp, err = s.HandleAnnounce(req)
|
||||
resp, err = t.HandleAnnounce(req)
|
||||
if err != nil {
|
||||
WriteError(w, txID, err)
|
||||
return
|
||||
|
@ -194,8 +194,8 @@ func (s *Server) handlePacket(r *Request, w *ResponseWriter) (response []byte, a
|
|||
|
||||
WriteAnnounce(w, txID, resp)
|
||||
|
||||
if s.AfterAnnounce != nil {
|
||||
s.AfterAnnounce(req, resp)
|
||||
if t.AfterAnnounce != nil {
|
||||
t.AfterAnnounce(req, resp)
|
||||
}
|
||||
|
||||
return
|
||||
|
@ -212,7 +212,7 @@ func (s *Server) handlePacket(r *Request, w *ResponseWriter) (response []byte, a
|
|||
|
||||
var resp *bittorrent.ScrapeResponse
|
||||
ctx := context.TODO()
|
||||
resp, err = s.HandleScrape(ctx, req)
|
||||
resp, err = t.HandleScrape(ctx, req)
|
||||
if err != nil {
|
||||
WriteError(w, txID, err)
|
||||
return
|
||||
|
@ -220,8 +220,8 @@ func (s *Server) handlePacket(r *Request, w *ResponseWriter) (response []byte, a
|
|||
|
||||
WriteScrape(w, txID, resp)
|
||||
|
||||
if s.AfterScrape != nil {
|
||||
s.AfterScrape(req, resp)
|
||||
if t.AfterScrape != nil {
|
||||
t.AfterScrape(req, resp)
|
||||
}
|
||||
|
||||
return
|
Loading…
Reference in a new issue