<commit_before>package tracker

import (
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"math/rand"
	"net"
	"net/url"
	"time"
)

type Action int32

const (
	Connect Action = iota
	Announce
	Scrape
	Error

	// BEP 41
	optionTypeEndOfOptions = 0
	optionTypeNOP          = 1
	optionTypeURLData      = 2
)

type ConnectionRequest struct {
	ConnectionId int64
	Action       int32
	TransctionId int32
}

type ConnectionResponse struct {
	ConnectionId int64
}

type ResponseHeader struct {
	Action        Action
	TransactionId int32
}

type RequestHeader struct {
	ConnectionId  int64
	Action        Action
	TransactionId int32
} // 16 bytes

type AnnounceResponseHeader struct {
	Interval int32
	Leechers int32
	Seeders  int32
}

func init() {
	RegisterClientScheme("udp", newClient)
}

func newClient(url *url.URL) Client {
	return &udpClient{
		url: *url,
	}
}

func newTransactionId() int32 {
	return int32(rand.Uint32())
}

func timeout(contiguousTimeouts int) (d time.Duration) {
	if contiguousTimeouts > 8 {
		contiguousTimeouts = 8
	}
	d = 15 * time.Second
	for ; contiguousTimeouts > 0; contiguousTimeouts-- {
		d *= 2
	}
	return
}

type udpClient struct {
	contiguousTimeouts   int
	connectionIdReceived time.Time
	connectionId         int64
	socket               net.Conn
	url                  url.URL
}

func (c *udpClient) URL() string {
	return c.url.String()
}

func (c *udpClient) String() string {
	return c.URL()
}

func (c *udpClient) Announce(req *AnnounceRequest) (res AnnounceResponse, err error) {
	if !c.connected() {
		err = ErrNotConnected
		return
	}
	reqURI := c.url.RequestURI()
	// Clearly this limits the request URI to 255 bytes. BEP 41 supports
	// longer but I'm not fussed.
	options := append([]byte{optionTypeURLData, byte(len(reqURI))}, []byte(reqURI)...)
	b, err := c.request(Announce, req, options)
	if err != nil {
		return
	}
	var h AnnounceResponseHeader
	err = readBody(b, &h)
	if err != nil {
		if err == io.EOF {
			err = io.ErrUnexpectedEOF
		}
		err = fmt.Errorf("error parsing announce response: %s", err)
		return
	}
	res.Interval = h.Interval
	res.Leechers = h.Leechers
	res.Seeders = h.Seeders
	for {
		var p Peer
		err = binary.Read(b, binary.BigEndian, &p)
		switch err {
		case nil:
		case io.EOF:
			err = nil
			fallthrough
		default:
			return<commit_msg>Fix peer parsing error introduced during tracker package merges<commit_after>package tracker

import (
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"math/rand"
	"net"
	"net/url"
	"time"

	"github.com/anacrolix/torrent/util"
)

type Action int32

const (
	Connect Action = iota
	Announce
	Scrape
	Error

	// BEP 41
	optionTypeEndOfOptions = 0
	optionTypeNOP          = 1
	optionTypeURLData      = 2
)

type ConnectionRequest struct {
	ConnectionId int64
	Action       int32
	TransctionId int32
}

type ConnectionResponse struct {
	ConnectionId int64
}

type ResponseHeader struct {
	Action        Action
	TransactionId int32
}

type RequestHeader struct {
	ConnectionId  int64
	Action        Action
	TransactionId int32
} // 16 bytes

type AnnounceResponseHeader struct {
	Interval int32
	Leechers int32
	Seeders  int32
}

func init() {
	RegisterClientScheme("udp", newClient)
}

func newClient(url *url.URL) Client {
	return &udpClient{
		url: *url,
	}
}

func newTransactionId() int32 {
	return int32(rand.Uint32())
}

func timeout(contiguousTimeouts int) (d time.Duration) {
	if contiguousTimeouts > 8 {
		contiguousTimeouts = 8
	}
	d = 15 * time.Second
	for ; contiguousTimeouts > 0; contiguousTimeouts-- {
		d *= 2
	}
	return
}

type udpClient struct {
	contiguousTimeouts   int
	connectionIdReceived time.Time
	connectionId         int64
	socket               net.Conn
	url                  url.URL
}

func (c *udpClient) URL() string {
	return c.url.String()
}

func (c *udpClient) String() string {
	return c.URL()
}

func (c *udpClient) Announce(req *AnnounceRequest) (res AnnounceResponse, err error) {
	if !c.connected() {
		err = ErrNotConnected
		return
	}
	reqURI := c.url.RequestURI()
	// Clearly this limits the request URI to 255 bytes. BEP 41 supports
	// longer but I'm not fussed.
	options := append([]byte{optionTypeURLData, byte(len(reqURI))}, []byte(reqURI)...)
	b, err := c.request(Announce, req, options)
	if err != nil {
		return
	}
	var h AnnounceResponseHeader
	err = readBody(b, &h)
	if err != nil {
		if err == io.EOF {
			err = io.ErrUnexpectedEOF
		}
		err = fmt.Errorf("error parsing announce response: %s", err)
		return
	}
	res.Interval = h.Interval
	res.Leechers = h.Leechers
	res.Seeders = h.Seeders
	for {
		var p util.CompactPeer
		err = binary.Read(b, binary.BigEndian, &p)
		switch err {
		case nil:
		case io.EOF:
			err = nil
			fallthrough
		default:
			return
{'fraction_non_alphanumeric': 0.10190677966101695, 'fraction_numerical': 0.020338983050847456, 'mean_word_length': 3.2569882777276824, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6836754', 'n_tokens_mistral': 1823, 'n_tokens_neox': 1674, 'n_words': 464}