diff --git a/Makefile b/Makefile index 45389c1..81cc7de 100644 --- a/Makefile +++ b/Makefile @@ -3,12 +3,13 @@ all: test magneticod magneticow magneticod: - go install --tags fts5 "-ldflags=-s -w" github.com/boramalper/magnetico/cmd/magneticod + go install --tags fts5 "-ldflags=-s -w -X main.compiledOn=`date -u +%Y-%m-%dT%H:%M:%SZ`" github.com/boramalper/magnetico/cmd/magneticod magneticow: # TODO: minify files! + # https://github.com/kevinburke/go-bindata go-bindata -o="cmd/magneticow/bindata.go" -prefix="cmd/magneticow/data/" cmd/magneticow/data/... - go install --tags fts5 "-ldflags=-s -w" github.com/boramalper/magnetico/cmd/magneticow + go install --tags fts5 "-ldflags=-s -w -X main.compiledOn=`date -u +%Y-%m-%dT%H:%M:%SZ`" github.com/boramalper/magnetico/cmd/magneticow image-magneticod: docker build -t magneticod -f Dockerfile.magneticod . diff --git a/cmd/magneticod/bittorrent/metadata/leech_test.go b/cmd/magneticod/bittorrent/metadata/leech_test.go index 25b2bf7..c32ca1e 100644 --- a/cmd/magneticod/bittorrent/metadata/leech_test.go +++ b/cmd/magneticod/bittorrent/metadata/leech_test.go @@ -2,9 +2,8 @@ package metadata import ( "bytes" - "testing" - "github.com/anacrolix/torrent/bencode" + "testing" ) var operationsTest_instances = []struct { diff --git a/cmd/magneticod/bittorrent/metadata/sink.go b/cmd/magneticod/bittorrent/metadata/sink.go index 2842a9c..39bc7c6 100644 --- a/cmd/magneticod/bittorrent/metadata/sink.go +++ b/cmd/magneticod/bittorrent/metadata/sink.go @@ -1,7 +1,7 @@ package metadata import ( - "crypto/rand" + "math/rand" "sync" "time" @@ -24,7 +24,7 @@ type Metadata struct { } type Sink struct { - clientID []byte + PeerID []byte deadline time.Duration drain chan Metadata incomingInfoHashes map[[20]byte]struct{} @@ -33,18 +33,49 @@ type Sink struct { termination chan interface{} } +func randomID() []byte { + /* > The peer_id is exactly 20 bytes (characters) long. + * > + * > There are mainly two conventions how to encode client and client version information into the peer_id, + * > Azureus-style and Shadow's-style. + * > + * > Azureus-style uses the following encoding: '-', two characters for client id, four ascii digits for version + * > number, '-', followed by random numbers. + * > + * > For example: '-AZ2060-'... + * + * https://wiki.theory.org/index.php/BitTorrentSpecification + * + * We encode the version number as: + * - First two digits for the major version number + * - Last two digits for the minor version number + * - Patch version number is not encoded. + */ + prefix := []byte("-MC0007-") + + var rando []byte + for i := 20 - len(prefix); i >= 0; i-- { + rando = append(rando, randomDigit()) + } + + return append(prefix, rando...) +} + +func randomDigit() byte { + var max, min int + max, min = '9', '0' + return byte(rand.Intn(max-min) + min) +} + func NewSink(deadline time.Duration) *Sink { ms := new(Sink) - ms.clientID = make([]byte, 20) - _, err := rand.Read(ms.clientID) - if err != nil { - zap.L().Panic("sinkMetadata couldn't read 20 random bytes for client ID!", zap.Error(err)) - } + ms.PeerID = randomID() ms.deadline = deadline ms.drain = make(chan Metadata) ms.incomingInfoHashes = make(map[[20]byte]struct{}) ms.termination = make(chan interface{}) + return ms } @@ -66,7 +97,7 @@ func (ms *Sink) Sink(res mainline.TrawlingResult) { zap.L().Info("Sunk!", zap.Int("leeches", len(ms.incomingInfoHashes)), util.HexField("infoHash", res.InfoHash[:])) - go NewLeech(res.InfoHash, res.PeerAddr, LeechEventHandlers{ + go NewLeech(res.InfoHash, res.PeerAddr, ms.PeerID, LeechEventHandlers{ OnSuccess: ms.flush, OnError: ms.onLeechError, }).Do(time.Now().Add(ms.deadline)) @@ -88,16 +119,18 @@ func (ms *Sink) Terminate() { } func (ms *Sink) flush(result Metadata) { - if !ms.terminated { - ms.drain <- result - // Delete the infoHash from ms.incomingInfoHashes ONLY AFTER once we've flushed the - // metadata! - var infoHash [20]byte - copy(infoHash[:], result.InfoHash) - ms.incomingInfoHashesMx.Lock() - delete(ms.incomingInfoHashes, infoHash) - ms.incomingInfoHashesMx.Unlock() + if ms.terminated { + return } + + ms.drain <- result + // Delete the infoHash from ms.incomingInfoHashes ONLY AFTER once we've flushed the + // metadata! + var infoHash [20]byte + copy(infoHash[:], result.InfoHash) + ms.incomingInfoHashesMx.Lock() + delete(ms.incomingInfoHashes, infoHash) + ms.incomingInfoHashesMx.Unlock() } func (ms *Sink) onLeechError(infoHash [20]byte, err error) {