udptracker

package
v0.0.0-...-e294334 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 13, 2024 License: Apache-2.0 Imports: 14 Imported by: 0

Documentation

Overview

Package udptracker implements the tracker protocol based on UDP.

You can use the package to implement a UDP tracker server to track the information that other peers upload or download the file, or to create a UDP tracker client to communicate with the UDP tracker server.

Index

Examples

Constants

View Source
const (
	ActionConnect  = uint32(0)
	ActionAnnounce = uint32(1)
	ActionScrape   = uint32(2)
	ActionError    = uint32(3)
)

Predefine some actions.

BEP 15

View Source
const ProtocolID = uint64(0x41727101980)

ProtocolID is magic constant for the udp tracker connection.

BEP 15

Variables

View Source
var Dial = net.Dial

Functions

This section is empty.

Types

type AnnounceRequest

type AnnounceRequest struct {
	InfoHash metainfo.Hash
	PeerID   metainfo.Hash

	Downloaded int64
	Left       int64
	Uploaded   int64
	Event      uint32

	IP      net.Addr
	Key     int32
	NumWant int32 // -1 for default
	Port    uint16

	Exts []Extension // BEP 41
}

AnnounceRequest represents the announce request used by UDP tracker.

BEP 15

func (*AnnounceRequest) DecodeFrom

func (r *AnnounceRequest) DecodeFrom(b []byte, w int)

DecodeFrom decodes the request from b.

func (AnnounceRequest) EncodeTo

func (r AnnounceRequest) EncodeTo(buf *bytes.Buffer)

EncodeTo encodes the request to buf.

type AnnounceResponse

type AnnounceResponse struct {
	Interval  uint32
	Leechers  uint32
	Seeders   uint32
	Addresses []metainfo.Address
}

AnnounceResponse represents the announce response used by UDP tracker.

BEP 15

func (*AnnounceResponse) DecodeFrom

func (r *AnnounceResponse) DecodeFrom(b []byte, ipv4 bool)

DecodeFrom decodes the response from b.

func (AnnounceResponse) EncodeTo

func (r AnnounceResponse) EncodeTo(buf *bytes.Buffer)

EncodeTo encodes the response to buf.

type Client

type Client struct {
	// contains filtered or unexported fields
}

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

Example
package main

import (
	"context"
	"errors"
	"fmt"
	"log"
	"net"
	"time"

	"github.com/eyedeekay/go-i2p-bt/metainfo"
)

type testHandler struct{}

func (testHandler) OnConnect(raddr net.Addr) (err error) { return }
func (testHandler) OnAnnounce(raddr net.Addr, req AnnounceRequest) (
	r AnnounceResponse, err error) {
	if req.Port != 80 {
		err = errors.New("port is not 80")
		return
	}

	if len(req.Exts) > 0 {
		for i, ext := range req.Exts {
			switch ext.Type {
			case URLData:
				fmt.Printf("Extensions[%d]: URLData(%s)\n", i, string(ext.Data))
			default:
				fmt.Printf("Extensions[%d]: %s\n", i, ext.Type.String())
			}
		}
	}

	r = AnnounceResponse{
		Interval:  1,
		Leechers:  2,
		Seeders:   3,
		Addresses: []metainfo.Address{{IP: &net.IPAddr{IP: net.ParseIP("127.0.0.1")}, Port: 8001}},
	}
	return
}
func (testHandler) OnScrap(raddr net.Addr, infohashes []metainfo.Hash) (
	rs []ScrapeResponse, err error) {
	rs = make([]ScrapeResponse, len(infohashes))
	for i := range infohashes {
		rs[i] = ScrapeResponse{
			Seeders:   uint32(i)*10 + 1,
			Leechers:  uint32(i)*10 + 2,
			Completed: uint32(i)*10 + 3,
		}
	}
	return
}

func main() {
	// Start the UDP tracker server
	sconn, err := net.ListenPacket("udp4", "127.0.0.1:8001")
	if err != nil {
		log.Fatal(err)
	}
	server := NewServer(sconn, testHandler{})
	defer server.Close()
	go server.Run()

	// Wait for the server to be started
	time.Sleep(time.Second)

	// Create a client and dial to the UDP tracker server.
	client, err := NewClientByDial("udp4", "127.0.0.1:8001")
	if err != nil {
		log.Fatal(err)
	}

	// Send the ANNOUNCE request to the UDP tracker server,
	// and get the ANNOUNCE response.
	exts := []Extension{NewURLData([]byte("data")), NewNop()}
	req := &AnnounceRequest{IP: &net.IPAddr{IP: net.ParseIP("127.0.0.1")}, Port: 80, Exts: exts}
	resp, err := client.Announce(context.Background(), req)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("Interval: %d\n", resp.Interval)
	fmt.Printf("Leechers: %d\n", resp.Leechers)
	fmt.Printf("Seeders: %d\n", resp.Seeders)
	for i, addr := range resp.Addresses {
		fmt.Printf("Address[%d].IP: %s\n", i, addr.IP.String())
		fmt.Printf("Address[%d].Port: %d\n", i, addr.Port)
	}

	// 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(context.Background(), hs)
	if err != nil {
		log.Fatal(err)
	} else if len(rs) != 2 {
		log.Fatalf("%+v", rs)
	}

	for i, r := range rs {
		fmt.Printf("%d.Seeders: %d\n", i, r.Seeders)
		fmt.Printf("%d.Leechers: %d\n", i, r.Leechers)
		fmt.Printf("%d.Completed: %d\n", i, r.Completed)
	}

}
Output:

Extensions[0]: URLData(data)
Extensions[1]: Nop
Interval: 1
Leechers: 2
Seeders: 3
Address[0].IP: 127.0.0.1
Address[0].Port: 8001
0.Seeders: 1
0.Leechers: 2
0.Completed: 3
1.Seeders: 11
1.Leechers: 12
1.Completed: 13

func NewClient

func NewClient(conn net.Conn, c ...ClientConfig) *Client

NewClient returns a new Client.

func NewClientByDial

func NewClientByDial(network, address string, c ...ClientConfig) (*Client, error)

NewClientByDial returns a new Client by dialing.

func (*Client) Announce

func (utc *Client) Announce(c context.Context, r *AnnounceRequest) (AnnounceResponse, error)

Announce sends a Announce request to the tracker.

Notice:

  1. if it does not connect to the UDP tracker server, it will connect to it, 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 (*Client) Close

func (utc *Client) Close() error

Close closes the UDP tracker client.

func (*Client) Scrape

func (utc *Client) Scrape(c context.Context, hs []metainfo.Hash) ([]ScrapeResponse, error)

Scrape sends a Scrape request to the tracker.

Notice:

  1. if it does not connect to the UDP tracker server, it will connect to it, 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 (*Client) String

func (utc *Client) String() string

type ClientConfig

type ClientConfig struct {
	ID         metainfo.Hash
	MaxBufSize int // Default: 2048
}

ClientConfig is used to configure the Client.

type Extension

type Extension struct {
	Type   ExtensionType
	Length uint8
	Data   []byte
}

Extension represent the extension used by the UDP ANNOUNCE request.

BEP 41

func NewEndOfOptions

func NewEndOfOptions() Extension

NewEndOfOptions returns a new EndOfOptions UDP extension.

func NewNop

func NewNop() Extension

NewNop returns a new Nop UDP extension.

func NewURLData

func NewURLData(data []byte) Extension

NewURLData returns a new URLData UDP extension.

func (*Extension) DecodeFrom

func (e *Extension) DecodeFrom(b []byte) (parsed int)

DecodeFrom decodes the response from b.

func (Extension) EncodeTo

func (e Extension) EncodeTo(buf *bytes.Buffer)

EncodeTo encodes the response to buf.

type ExtensionType

type ExtensionType uint8

ExtensionType represents the type of UDP extension.

const (
	EndOfOptions ExtensionType = iota
	Nop
	URLData
)

Predefine some UDP extension types.

BEP 41

func (ExtensionType) String

func (et ExtensionType) String() string

type ScrapeResponse

type ScrapeResponse struct {
	Seeders   uint32
	Leechers  uint32
	Completed uint32
}

ScrapeResponse represents the UDP SCRAPE response.

BEP 15

func (*ScrapeResponse) DecodeFrom

func (r *ScrapeResponse) DecodeFrom(b []byte)

DecodeFrom decodes the response from b.

func (ScrapeResponse) EncodeTo

func (r ScrapeResponse) EncodeTo(buf *bytes.Buffer)

EncodeTo encodes the response to buf.

type Server

type Server struct {
	// contains filtered or unexported fields
}

Server is a tracker server based on UDP.

func NewServer

func NewServer(c net.PacketConn, h ServerHandler, sc ...ServerConfig) *Server

NewServer returns a new Server.

func (*Server) Close

func (uts *Server) Close()

Close closes the tracker server.

func (*Server) Run

func (uts *Server) Run()

Run starts the tracker server.

type ServerConfig

type ServerConfig struct {
	MaxBufSize int                                      // Default: 2048
	ErrorLog   func(format string, args ...interface{}) // Default: log.Printf
}

ServerConfig is used to configure the Server.

type ServerHandler

type ServerHandler interface {
	// OnConnect is used to check whether to make the connection or not.
	OnConnect(raddr net.Addr) (err error)
	OnAnnounce(raddr net.Addr, req AnnounceRequest) (AnnounceResponse, error)
	OnScrap(raddr net.Addr, infohashes []metainfo.Hash) ([]ScrapeResponse, error)
}

ServerHandler is used to handle the request from the client.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL