Tidy up the torrent and DHT APIs
This commit is contained in:
parent
96e44f8950
commit
40fd1d647c
124
client.go
124
client.go
@ -16,8 +16,6 @@ Simple example:
|
|||||||
package torrent
|
package torrent
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bitbucket.org/anacrolix/go.torrent/dht"
|
|
||||||
"bitbucket.org/anacrolix/go.torrent/util"
|
|
||||||
"bufio"
|
"bufio"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
@ -32,6 +30,9 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"bitbucket.org/anacrolix/go.torrent/dht"
|
||||||
|
. "bitbucket.org/anacrolix/go.torrent/util"
|
||||||
|
|
||||||
"github.com/anacrolix/libtorgo/metainfo"
|
"github.com/anacrolix/libtorgo/metainfo"
|
||||||
"github.com/nsf/libtorgo/bencode"
|
"github.com/nsf/libtorgo/bencode"
|
||||||
|
|
||||||
@ -63,7 +64,7 @@ func (me *Client) PrioritizeDataRegion(ih InfoHash, off, len_ int64) error {
|
|||||||
if !t.haveInfo() {
|
if !t.haveInfo() {
|
||||||
return errors.New("missing metadata")
|
return errors.New("missing metadata")
|
||||||
}
|
}
|
||||||
me.DownloadStrategy.TorrentPrioritize(t, off, len_)
|
me.downloadStrategy.TorrentPrioritize(t, off, len_)
|
||||||
for _, cn := range t.Conns {
|
for _, cn := range t.Conns {
|
||||||
me.replenishConnRequests(t, cn)
|
me.replenishConnRequests(t, cn)
|
||||||
}
|
}
|
||||||
@ -76,13 +77,13 @@ type dataSpec struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Client struct {
|
type Client struct {
|
||||||
DataDir string
|
dataDir string
|
||||||
HalfOpenLimit int
|
halfOpenLimit int
|
||||||
PeerId [20]byte
|
peerID [20]byte
|
||||||
Listener net.Listener
|
listener net.Listener
|
||||||
DisableTrackers bool
|
disableTrackers bool
|
||||||
DownloadStrategy DownloadStrategy
|
downloadStrategy DownloadStrategy
|
||||||
DHT *dht.Server
|
dHT *dht.Server
|
||||||
|
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
event sync.Cond
|
event sync.Cond
|
||||||
@ -93,18 +94,23 @@ type Client struct {
|
|||||||
dataWaiter chan struct{}
|
dataWaiter chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (me *Client) ListenAddr() net.Addr {
|
||||||
|
return me.listener.Addr()
|
||||||
|
}
|
||||||
|
|
||||||
func (cl *Client) WriteStatus(w io.Writer) {
|
func (cl *Client) WriteStatus(w io.Writer) {
|
||||||
cl.mu.Lock()
|
cl.mu.Lock()
|
||||||
defer cl.mu.Unlock()
|
defer cl.mu.Unlock()
|
||||||
if cl.Listener != nil {
|
if cl.listener != nil {
|
||||||
fmt.Fprintf(w, "Listening on %s\n", cl.Listener.Addr())
|
fmt.Fprintf(w, "Listening on %s\n", cl.listener.Addr())
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(w, "No listening torrent port!\n")
|
fmt.Fprintf(w, "No listening torrent port!\n")
|
||||||
}
|
}
|
||||||
fmt.Fprintf(w, "Peer ID: %q\n", cl.PeerId)
|
fmt.Fprintf(w, "Peer ID: %q\n", cl.peerID)
|
||||||
fmt.Fprintf(w, "Half open outgoing connections: %d\n", cl.halfOpen)
|
fmt.Fprintf(w, "Half open outgoing connections: %d\n", cl.halfOpen)
|
||||||
if cl.DHT != nil {
|
if cl.dHT != nil {
|
||||||
fmt.Fprintf(w, "DHT nodes: %d\n", cl.DHT.NumNodes())
|
fmt.Fprintf(w, "DHT nodes: %d\n", cl.dHT.NumNodes())
|
||||||
|
fmt.Fprintf(w, "DHT Server ID: %x\n", cl.dHT.IDString())
|
||||||
}
|
}
|
||||||
fmt.Fprintln(w)
|
fmt.Fprintln(w)
|
||||||
for _, t := range cl.torrents {
|
for _, t := range cl.torrents {
|
||||||
@ -164,26 +170,50 @@ func (cl *Client) TorrentReadAt(ih InfoHash, off int64, p []byte) (n int, err er
|
|||||||
return t.Data.ReadAt(p, off)
|
return t.Data.ReadAt(p, off)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Starts the client. Defaults are applied. The client will begin accepting
|
func NewClient(cfg *Config) (cl *Client, err error) {
|
||||||
// connections and tracking.
|
if cfg == nil {
|
||||||
func (c *Client) Start() {
|
cfg = &Config{}
|
||||||
c.event.L = &c.mu
|
|
||||||
c.torrents = make(map[InfoHash]*torrent)
|
|
||||||
if c.HalfOpenLimit == 0 {
|
|
||||||
c.HalfOpenLimit = 10
|
|
||||||
}
|
}
|
||||||
o := copy(c.PeerId[:], BEP20)
|
|
||||||
_, err := rand.Read(c.PeerId[o:])
|
cl = &Client{
|
||||||
|
disableTrackers: cfg.DisableTrackers,
|
||||||
|
downloadStrategy: cfg.DownloadStrategy,
|
||||||
|
halfOpenLimit: 100,
|
||||||
|
dataDir: cfg.DataDir,
|
||||||
|
|
||||||
|
quit: make(chan struct{}),
|
||||||
|
torrents: make(map[InfoHash]*torrent),
|
||||||
|
}
|
||||||
|
cl.event.L = &cl.mu
|
||||||
|
|
||||||
|
o := copy(cl.peerID[:], BEP20)
|
||||||
|
_, err = rand.Read(cl.peerID[o:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic("error generating peer id")
|
panic("error generating peer id")
|
||||||
}
|
}
|
||||||
c.quit = make(chan struct{})
|
|
||||||
if c.DownloadStrategy == nil {
|
if cl.downloadStrategy == nil {
|
||||||
c.DownloadStrategy = &DefaultDownloadStrategy{}
|
cl.downloadStrategy = &DefaultDownloadStrategy{}
|
||||||
}
|
}
|
||||||
if c.Listener != nil {
|
|
||||||
go c.acceptConnections()
|
cl.listener, err = net.Listen("tcp", cfg.ListenAddr)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
if cl.listener != nil {
|
||||||
|
go cl.acceptConnections()
|
||||||
|
}
|
||||||
|
|
||||||
|
if !cfg.NoDHT {
|
||||||
|
cl.dHT, err = dht.NewServer(&dht.ServerConfig{
|
||||||
|
Addr: cfg.ListenAddr,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cl *Client) stopped() bool {
|
func (cl *Client) stopped() bool {
|
||||||
@ -211,7 +241,7 @@ func (me *Client) Stop() {
|
|||||||
|
|
||||||
func (cl *Client) acceptConnections() {
|
func (cl *Client) acceptConnections() {
|
||||||
for {
|
for {
|
||||||
conn, err := cl.Listener.Accept()
|
conn, err := cl.listener.Accept()
|
||||||
select {
|
select {
|
||||||
case <-cl.quit:
|
case <-cl.quit:
|
||||||
if conn != nil {
|
if conn != nil {
|
||||||
@ -245,7 +275,7 @@ func (me *Client) torrent(ih InfoHash) *torrent {
|
|||||||
// Start the process of connecting to the given peer for the given torrent if
|
// Start the process of connecting to the given peer for the given torrent if
|
||||||
// appropriate.
|
// appropriate.
|
||||||
func (me *Client) initiateConn(peer Peer, torrent *torrent) {
|
func (me *Client) initiateConn(peer Peer, torrent *torrent) {
|
||||||
if peer.Id == me.PeerId {
|
if peer.Id == me.peerID {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
me.halfOpen++
|
me.halfOpen++
|
||||||
@ -291,10 +321,10 @@ func (me *Client) initiateConn(peer Peer, torrent *torrent) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (cl *Client) incomingPeerPort() int {
|
func (cl *Client) incomingPeerPort() int {
|
||||||
if cl.Listener == nil {
|
if cl.listener == nil {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
_, p, err := net.SplitHostPort(cl.Listener.Addr().String())
|
_, p, err := net.SplitHostPort(cl.listener.Addr().String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@ -452,7 +482,7 @@ func (me *Client) peerUnchoked(torrent *torrent, conn *connection) {
|
|||||||
func (cl *Client) connCancel(t *torrent, cn *connection, r request) (ok bool) {
|
func (cl *Client) connCancel(t *torrent, cn *connection, r request) (ok bool) {
|
||||||
ok = cn.Cancel(r)
|
ok = cn.Cancel(r)
|
||||||
if ok {
|
if ok {
|
||||||
cl.DownloadStrategy.DeleteRequest(t, r)
|
cl.downloadStrategy.DeleteRequest(t, r)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -461,7 +491,7 @@ func (cl *Client) connDeleteRequest(t *torrent, cn *connection, r request) {
|
|||||||
if !cn.RequestPending(r) {
|
if !cn.RequestPending(r) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
cl.DownloadStrategy.DeleteRequest(t, r)
|
cl.downloadStrategy.DeleteRequest(t, r)
|
||||||
delete(cn.Requests, r)
|
delete(cn.Requests, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -788,7 +818,7 @@ func (me *Client) addConnection(t *torrent, c *connection) bool {
|
|||||||
func (me *Client) openNewConns() {
|
func (me *Client) openNewConns() {
|
||||||
for _, t := range me.torrents {
|
for _, t := range me.torrents {
|
||||||
for len(t.Peers) != 0 {
|
for len(t.Peers) != 0 {
|
||||||
if me.halfOpen >= me.HalfOpenLimit {
|
if me.halfOpen >= me.halfOpenLimit {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
p := t.Peers[0]
|
p := t.Peers[0]
|
||||||
@ -812,7 +842,7 @@ func (me *Client) AddPeers(infoHash InfoHash, peers []Peer) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (cl *Client) setMetaData(t *torrent, md metainfo.Info, bytes []byte) (err error) {
|
func (cl *Client) setMetaData(t *torrent, md metainfo.Info, bytes []byte) (err error) {
|
||||||
err = t.setMetadata(md, cl.DataDir, bytes)
|
err = t.setMetadata(md, cl.dataDir, bytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -827,7 +857,7 @@ func (cl *Client) setMetaData(t *torrent, md metainfo.Info, bytes []byte) (err e
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
cl.DownloadStrategy.TorrentStarted(t)
|
cl.downloadStrategy.TorrentStarted(t)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -902,10 +932,10 @@ func (me *Client) addTorrent(t *torrent) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
me.torrents[t.InfoHash] = t
|
me.torrents[t.InfoHash] = t
|
||||||
if !me.DisableTrackers {
|
if !me.disableTrackers {
|
||||||
go me.announceTorrent(t)
|
go me.announceTorrent(t)
|
||||||
}
|
}
|
||||||
if me.DHT != nil {
|
if me.dHT != nil {
|
||||||
go me.announceTorrentDHT(t)
|
go me.announceTorrentDHT(t)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
@ -940,7 +970,7 @@ func (me *Client) AddTorrentFromFile(name string) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (cl *Client) listenerAnnouncePort() (port int16) {
|
func (cl *Client) listenerAnnouncePort() (port int16) {
|
||||||
l := cl.Listener
|
l := cl.listener
|
||||||
if l == nil {
|
if l == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -958,7 +988,7 @@ func (cl *Client) listenerAnnouncePort() (port int16) {
|
|||||||
|
|
||||||
func (cl *Client) announceTorrentDHT(t *torrent) {
|
func (cl *Client) announceTorrentDHT(t *torrent) {
|
||||||
for {
|
for {
|
||||||
ps, err := cl.DHT.GetPeers(string(t.InfoHash[:]))
|
ps, err := cl.dHT.GetPeers(string(t.InfoHash[:]))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("error getting peers from dht: %s", err)
|
log.Printf("error getting peers from dht: %s", err)
|
||||||
return
|
return
|
||||||
@ -1003,7 +1033,7 @@ func (cl *Client) announceTorrent(t *torrent) {
|
|||||||
Event: tracker.Started,
|
Event: tracker.Started,
|
||||||
NumWant: -1,
|
NumWant: -1,
|
||||||
Port: cl.listenerAnnouncePort(),
|
Port: cl.listenerAnnouncePort(),
|
||||||
PeerId: cl.PeerId,
|
PeerId: cl.peerID,
|
||||||
InfoHash: t.InfoHash,
|
InfoHash: t.InfoHash,
|
||||||
}
|
}
|
||||||
newAnnounce:
|
newAnnounce:
|
||||||
@ -1072,7 +1102,7 @@ func (me *Client) WaitAll() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (cl *Client) assertRequestHeat() {
|
func (cl *Client) assertRequestHeat() {
|
||||||
dds, ok := cl.DownloadStrategy.(*DefaultDownloadStrategy)
|
dds, ok := cl.downloadStrategy.(*DefaultDownloadStrategy)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1095,7 +1125,7 @@ func (me *Client) replenishConnRequests(t *torrent, c *connection) {
|
|||||||
if !t.haveInfo() {
|
if !t.haveInfo() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
me.DownloadStrategy.FillRequests(t, c)
|
me.downloadStrategy.FillRequests(t, c)
|
||||||
//me.assertRequestHeat()
|
//me.assertRequestHeat()
|
||||||
if len(c.Requests) == 0 && !c.PeerChoked {
|
if len(c.Requests) == 0 && !c.PeerChoked {
|
||||||
c.SetInterested(false)
|
c.SetInterested(false)
|
||||||
@ -1130,7 +1160,7 @@ func (me *Client) downloadedChunk(t *torrent, c *connection, msg *pp.Message) er
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Unprioritize the chunk.
|
// Unprioritize the chunk.
|
||||||
me.DownloadStrategy.TorrentGotChunk(t, req)
|
me.downloadStrategy.TorrentGotChunk(t, req)
|
||||||
|
|
||||||
// Cancel pending requests for this chunk.
|
// Cancel pending requests for this chunk.
|
||||||
cancelled := false
|
cancelled := false
|
||||||
@ -1171,7 +1201,7 @@ func (me *Client) pieceHashed(t *torrent, piece pp.Integer, correct bool) {
|
|||||||
p.EverHashed = true
|
p.EverHashed = true
|
||||||
if correct {
|
if correct {
|
||||||
p.PendingChunkSpecs = nil
|
p.PendingChunkSpecs = nil
|
||||||
me.DownloadStrategy.TorrentGotPiece(t, int(piece))
|
me.downloadStrategy.TorrentGotPiece(t, int(piece))
|
||||||
me.dataReady(dataSpec{
|
me.dataReady(dataSpec{
|
||||||
t.InfoHash,
|
t.InfoHash,
|
||||||
request{
|
request{
|
||||||
|
@ -7,6 +7,14 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestClientDefault(t *testing.T) {
|
||||||
|
cl, err := NewClient(nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
cl.Stop()
|
||||||
|
}
|
||||||
|
|
||||||
func TestAddTorrentNoSupportedTrackerSchemes(t *testing.T) {
|
func TestAddTorrentNoSupportedTrackerSchemes(t *testing.T) {
|
||||||
t.SkipNow()
|
t.SkipNow()
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bitbucket.org/anacrolix/go.torrent/dht"
|
|
||||||
"bitbucket.org/anacrolix/go.torrent/tracker"
|
|
||||||
_ "bitbucket.org/anacrolix/go.torrent/util/profile"
|
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
@ -11,6 +8,11 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"bitbucket.org/anacrolix/go.torrent/dht"
|
||||||
|
"bitbucket.org/anacrolix/go.torrent/util"
|
||||||
|
_ "bitbucket.org/anacrolix/go.torrent/util/profile"
|
||||||
)
|
)
|
||||||
|
|
||||||
type pingResponse struct {
|
type pingResponse struct {
|
||||||
@ -23,7 +25,7 @@ var (
|
|||||||
serveAddr = flag.String("serveAddr", ":0", "local UDP address")
|
serveAddr = flag.String("serveAddr", ":0", "local UDP address")
|
||||||
infoHash = flag.String("infoHash", "", "torrent infohash")
|
infoHash = flag.String("infoHash", "", "torrent infohash")
|
||||||
|
|
||||||
s dht.Server
|
s *dht.Server
|
||||||
)
|
)
|
||||||
|
|
||||||
func loadTable() error {
|
func loadTable() error {
|
||||||
@ -74,22 +76,17 @@ func init() {
|
|||||||
log.Fatal("require 20 byte infohash")
|
log.Fatal("require 20 byte infohash")
|
||||||
}
|
}
|
||||||
var err error
|
var err error
|
||||||
s.Socket, err = net.ListenUDP("udp4", func() *net.UDPAddr {
|
s, err = dht.NewServer(&dht.ServerConfig{
|
||||||
addr, err := net.ResolveUDPAddr("udp4", *serveAddr)
|
Addr: *serveAddr,
|
||||||
if err != nil {
|
})
|
||||||
log.Fatalf("error resolving serve addr: %s", err)
|
|
||||||
}
|
|
||||||
return addr
|
|
||||||
}())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
s.Init()
|
|
||||||
err = loadTable()
|
err = loadTable()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("error loading table: %s", err)
|
log.Fatalf("error loading table: %s", err)
|
||||||
}
|
}
|
||||||
log.Printf("dht server on %s, ID is %q", s.Socket.LocalAddr(), s.IDString())
|
log.Printf("dht server on %s, ID is %q", s.LocalAddr(), s.IDString())
|
||||||
setupSignals()
|
setupSignals()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,18 +128,13 @@ func setupSignals() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
go func() {
|
seen := make(map[util.CompactPeer]struct{})
|
||||||
defer s.StopServing()
|
for {
|
||||||
if err := s.Bootstrap(); err != nil {
|
|
||||||
log.Printf("error bootstrapping: %s", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
saveTable()
|
|
||||||
ps, err := s.GetPeers(*infoHash)
|
ps, err := s.GetPeers(*infoHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
seen := make(map[tracker.CompactPeer]struct{})
|
go func() {
|
||||||
for sl := range ps.Values {
|
for sl := range ps.Values {
|
||||||
for _, p := range sl {
|
for _, p := range sl {
|
||||||
if _, ok := seen[p]; ok {
|
if _, ok := seen[p]; ok {
|
||||||
@ -156,11 +148,9 @@ func main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
err := s.Serve()
|
time.Sleep(15 * time.Second)
|
||||||
|
}
|
||||||
if err := saveTable(); err != nil {
|
if err := saveTable(); err != nil {
|
||||||
log.Printf("error saving node table: %s", err)
|
log.Printf("error saving node table: %s", err)
|
||||||
}
|
}
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("error serving dht: %s", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bitbucket.org/anacrolix/go.torrent/dht"
|
|
||||||
"flag"
|
"flag"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"bitbucket.org/anacrolix/go.torrent/dht"
|
||||||
)
|
)
|
||||||
|
|
||||||
type pingResponse struct {
|
type pingResponse struct {
|
||||||
@ -21,20 +22,11 @@ func main() {
|
|||||||
os.Stderr.WriteString("u must specify addrs of nodes to ping e.g. router.bittorrent.com:6881\n")
|
os.Stderr.WriteString("u must specify addrs of nodes to ping e.g. router.bittorrent.com:6881\n")
|
||||||
os.Exit(2)
|
os.Exit(2)
|
||||||
}
|
}
|
||||||
s := dht.Server{}
|
s, err := dht.NewServer(nil)
|
||||||
var err error
|
|
||||||
s.Socket, err = net.ListenUDP("udp4", nil)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
log.Printf("dht server on %s", s.Socket.LocalAddr())
|
log.Printf("dht server on %s", s.LocalAddr())
|
||||||
s.Init()
|
|
||||||
go func() {
|
|
||||||
err := s.Serve()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
pingResponses := make(chan pingResponse)
|
pingResponses := make(chan pingResponse)
|
||||||
for _, netloc := range pingStrAddrs {
|
for _, netloc := range pingStrAddrs {
|
||||||
addr, err := net.ResolveUDPAddr("udp4", netloc)
|
addr, err := net.ResolveUDPAddr("udp4", netloc)
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bitbucket.org/anacrolix/go.torrent/dht"
|
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
|
|
||||||
|
"bitbucket.org/anacrolix/go.torrent/dht"
|
||||||
)
|
)
|
||||||
|
|
||||||
type pingResponse struct {
|
type pingResponse struct {
|
||||||
@ -20,7 +20,7 @@ var (
|
|||||||
tableFileName = flag.String("tableFile", "", "name of file for storing node info")
|
tableFileName = flag.String("tableFile", "", "name of file for storing node info")
|
||||||
serveAddr = flag.String("serveAddr", ":0", "local UDP address")
|
serveAddr = flag.String("serveAddr", ":0", "local UDP address")
|
||||||
|
|
||||||
s dht.Server
|
s *dht.Server
|
||||||
)
|
)
|
||||||
|
|
||||||
func loadTable() error {
|
func loadTable() error {
|
||||||
@ -61,22 +61,17 @@ func init() {
|
|||||||
log.SetFlags(log.LstdFlags | log.Lshortfile)
|
log.SetFlags(log.LstdFlags | log.Lshortfile)
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
var err error
|
var err error
|
||||||
s.Socket, err = net.ListenUDP("udp4", func() *net.UDPAddr {
|
s, err = dht.NewServer(&dht.ServerConfig{
|
||||||
addr, err := net.ResolveUDPAddr("udp4", *serveAddr)
|
Addr: *serveAddr,
|
||||||
if err != nil {
|
})
|
||||||
log.Fatalf("error resolving serve addr: %s", err)
|
|
||||||
}
|
|
||||||
return addr
|
|
||||||
}())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
s.Init()
|
|
||||||
err = loadTable()
|
err = loadTable()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("error loading table: %s", err)
|
log.Fatalf("error loading table: %s", err)
|
||||||
}
|
}
|
||||||
log.Printf("dht server on %s, ID is %q", s.Socket.LocalAddr(), s.IDString())
|
log.Printf("dht server on %s, ID is %q", s.LocalAddr(), s.IDString())
|
||||||
setupSignals()
|
setupSignals()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,20 +113,8 @@ func setupSignals() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
go func() {
|
select {}
|
||||||
err := s.Bootstrap()
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("error bootstrapping: %s", err)
|
|
||||||
s.StopServing()
|
|
||||||
} else {
|
|
||||||
log.Print("bootstrapping complete")
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
err := s.Serve()
|
|
||||||
if err := saveTable(); err != nil {
|
if err := saveTable(); err != nil {
|
||||||
log.Printf("error saving node table: %s", err)
|
log.Printf("error saving node table: %s", err)
|
||||||
}
|
}
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("error serving dht: %s", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bitbucket.org/anacrolix/go.torrent/dht"
|
|
||||||
"bitbucket.org/anacrolix/go.torrent/util"
|
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
@ -12,6 +10,8 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"bitbucket.org/anacrolix/go.torrent/util"
|
||||||
|
|
||||||
"github.com/anacrolix/libtorgo/metainfo"
|
"github.com/anacrolix/libtorgo/metainfo"
|
||||||
|
|
||||||
"bitbucket.org/anacrolix/go.torrent"
|
"bitbucket.org/anacrolix/go.torrent"
|
||||||
@ -32,57 +32,21 @@ func init() {
|
|||||||
flag.Parse()
|
flag.Parse()
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeListener() net.Listener {
|
|
||||||
l, err := net.Listen("tcp", *listenAddr)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
return l
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
if *httpAddr != "" {
|
if *httpAddr != "" {
|
||||||
util.LoggedHTTPServe(*httpAddr)
|
util.LoggedHTTPServe(*httpAddr)
|
||||||
}
|
}
|
||||||
dhtServer := &dht.Server{
|
client, err := torrent.NewClient(&torrent.Config{
|
||||||
Socket: func() *net.UDPConn {
|
|
||||||
addr, err := net.ResolveUDPAddr("udp4", *listenAddr)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("error resolving dht listen addr: %s", err)
|
|
||||||
}
|
|
||||||
s, err := net.ListenUDP("udp4", addr)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("error creating dht socket: %s", err)
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}(),
|
|
||||||
}
|
|
||||||
err := dhtServer.Init()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("error initing dht server: %s", err)
|
|
||||||
}
|
|
||||||
go func() {
|
|
||||||
err := dhtServer.Serve()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("error serving dht: %s", err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
go func() {
|
|
||||||
err := dhtServer.Bootstrap()
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("error bootstrapping dht server: %s", err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
client := torrent.Client{
|
|
||||||
DataDir: *downloadDir,
|
DataDir: *downloadDir,
|
||||||
Listener: makeListener(),
|
|
||||||
DisableTrackers: *disableTrackers,
|
DisableTrackers: *disableTrackers,
|
||||||
DHT: dhtServer,
|
ListenAddr: *listenAddr,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("error creating client: %s", err)
|
||||||
}
|
}
|
||||||
http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
|
http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
|
||||||
client.WriteStatus(w)
|
client.WriteStatus(w)
|
||||||
})
|
})
|
||||||
client.Start()
|
|
||||||
defer client.Stop()
|
defer client.Stop()
|
||||||
if flag.NArg() == 0 {
|
if flag.NArg() == 0 {
|
||||||
fmt.Fprintln(os.Stderr, "no torrents specified")
|
fmt.Fprintln(os.Stderr, "no torrents specified")
|
||||||
|
@ -45,14 +45,6 @@ func init() {
|
|||||||
flag.StringVar(&mountDir, "mountDir", "", "location the torrent contents are made available")
|
flag.StringVar(&mountDir, "mountDir", "", "location the torrent contents are made available")
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeListener() net.Listener {
|
|
||||||
l, err := net.Listen("tcp", *listenAddr)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
return l
|
|
||||||
}
|
|
||||||
|
|
||||||
func resolveTestPeerAddr() {
|
func resolveTestPeerAddr() {
|
||||||
if *testPeer == "" {
|
if *testPeer == "" {
|
||||||
return
|
return
|
||||||
@ -113,16 +105,15 @@ func main() {
|
|||||||
// TODO: Think about the ramifications of exiting not due to a signal.
|
// TODO: Think about the ramifications of exiting not due to a signal.
|
||||||
setSignalHandlers()
|
setSignalHandlers()
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
client := &torrent.Client{
|
client, err := torrent.NewClient(&torrent.Config{
|
||||||
DataDir: downloadDir,
|
DataDir: downloadDir,
|
||||||
DisableTrackers: *disableTrackers,
|
DisableTrackers: *disableTrackers,
|
||||||
DownloadStrategy: torrent.NewResponsiveDownloadStrategy(*readaheadBytes),
|
DownloadStrategy: torrent.NewResponsiveDownloadStrategy(*readaheadBytes),
|
||||||
Listener: makeListener(),
|
ListenAddr: *listenAddr,
|
||||||
}
|
})
|
||||||
http.DefaultServeMux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
|
http.DefaultServeMux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
|
||||||
client.WriteStatus(w)
|
client.WriteStatus(w)
|
||||||
})
|
})
|
||||||
client.Start()
|
|
||||||
dw, err := dirwatch.New(torrentPath)
|
dw, err := dirwatch.New(torrentPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
|
9
config.go
Normal file
9
config.go
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package torrent
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
DataDir string
|
||||||
|
ListenAddr string
|
||||||
|
DisableTrackers bool
|
||||||
|
DownloadStrategy DownloadStrategy
|
||||||
|
NoDHT bool
|
||||||
|
}
|
106
dht/dht.go
106
dht/dht.go
@ -1,25 +1,25 @@
|
|||||||
package dht
|
package dht
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bitbucket.org/anacrolix/go.torrent/tracker"
|
|
||||||
"bitbucket.org/anacrolix/go.torrent/util"
|
|
||||||
"crypto"
|
"crypto"
|
||||||
_ "crypto/sha1"
|
_ "crypto/sha1"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/nsf/libtorgo/bencode"
|
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"bitbucket.org/anacrolix/go.torrent/util"
|
||||||
|
"github.com/nsf/libtorgo/bencode"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Server struct {
|
type Server struct {
|
||||||
ID string
|
id string
|
||||||
Socket *net.UDPConn
|
socket *net.UDPConn
|
||||||
transactions []*transaction
|
transactions []*transaction
|
||||||
transactionIDInt uint64
|
transactionIDInt uint64
|
||||||
nodes map[string]*Node // Keyed by *net.UDPAddr.String().
|
nodes map[string]*Node // Keyed by *net.UDPAddr.String().
|
||||||
@ -27,8 +27,47 @@ type Server struct {
|
|||||||
closed chan struct{}
|
closed chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ServerConfig struct {
|
||||||
|
Addr string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) LocalAddr() net.Addr {
|
||||||
|
return s.socket.LocalAddr()
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeSocket(addr string) (socket *net.UDPConn, err error) {
|
||||||
|
addr_, err := net.ResolveUDPAddr("", addr)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
socket, err = net.ListenUDP("udp", addr_)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewServer(c *ServerConfig) (s *Server, err error) {
|
||||||
|
s = &Server{}
|
||||||
|
s.socket, err = makeSocket(c.Addr)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = s.init()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
panic(s.serve())
|
||||||
|
}()
|
||||||
|
go func() {
|
||||||
|
err := s.bootstrap()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Server) String() string {
|
func (s *Server) String() string {
|
||||||
return fmt.Sprintf("dht server on %s", s.Socket.LocalAddr())
|
return fmt.Sprintf("dht server on %s", s.socket.LocalAddr())
|
||||||
}
|
}
|
||||||
|
|
||||||
type Node struct {
|
type Node struct {
|
||||||
@ -96,25 +135,14 @@ func (t *transaction) handleResponse(m Msg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) setDefaults() (err error) {
|
func (s *Server) setDefaults() (err error) {
|
||||||
if s.Socket == nil {
|
if s.id == "" {
|
||||||
var addr *net.UDPAddr
|
|
||||||
addr, err = net.ResolveUDPAddr("", ":6882")
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
s.Socket, err = net.ListenUDP("udp", addr)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if s.ID == "" {
|
|
||||||
var id [20]byte
|
var id [20]byte
|
||||||
h := crypto.SHA1.New()
|
h := crypto.SHA1.New()
|
||||||
ss, err := os.Hostname()
|
ss, err := os.Hostname()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Print(err)
|
log.Print(err)
|
||||||
}
|
}
|
||||||
ss += s.Socket.LocalAddr().String()
|
ss += s.socket.LocalAddr().String()
|
||||||
h.Write([]byte(ss))
|
h.Write([]byte(ss))
|
||||||
if b := h.Sum(id[:0:20]); len(b) != 20 {
|
if b := h.Sum(id[:0:20]); len(b) != 20 {
|
||||||
panic(len(b))
|
panic(len(b))
|
||||||
@ -122,13 +150,13 @@ func (s *Server) setDefaults() (err error) {
|
|||||||
if len(id) != 20 {
|
if len(id) != 20 {
|
||||||
panic(len(id))
|
panic(len(id))
|
||||||
}
|
}
|
||||||
s.ID = string(id[:])
|
s.id = string(id[:])
|
||||||
}
|
}
|
||||||
s.nodes = make(map[string]*Node, 10000)
|
s.nodes = make(map[string]*Node, 10000)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) Init() (err error) {
|
func (s *Server) init() (err error) {
|
||||||
err = s.setDefaults()
|
err = s.setDefaults()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
@ -137,10 +165,10 @@ func (s *Server) Init() (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) Serve() error {
|
func (s *Server) serve() error {
|
||||||
for {
|
for {
|
||||||
var b [0x10000]byte
|
var b [0x10000]byte
|
||||||
n, addr, err := s.Socket.ReadFromUDP(b[:])
|
n, addr, err := s.socket.ReadFromUDP(b[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -296,7 +324,7 @@ func (s *Server) getNode(addr *net.UDPAddr) (n *Node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) writeToNode(b []byte, node *net.UDPAddr) (err error) {
|
func (s *Server) writeToNode(b []byte, node *net.UDPAddr) (err error) {
|
||||||
n, err := s.Socket.WriteTo(b, node)
|
n, err := s.socket.WriteTo(b, node)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("error writing %d bytes to %s: %s", len(b), node, err)
|
err = fmt.Errorf("error writing %d bytes to %s: %s", len(b), node, err)
|
||||||
return
|
return
|
||||||
@ -347,10 +375,10 @@ func (s *Server) addTransaction(t *transaction) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) IDString() string {
|
func (s *Server) IDString() string {
|
||||||
if len(s.ID) != 20 {
|
if len(s.id) != 20 {
|
||||||
panic("bad node id")
|
panic("bad node id")
|
||||||
}
|
}
|
||||||
return s.ID
|
return s.id
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) timeoutTransaction(t *transaction) {
|
func (s *Server) timeoutTransaction(t *transaction) {
|
||||||
@ -560,14 +588,9 @@ func (s *Server) findNode(addr *net.UDPAddr, targetID string) (t *transaction, e
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
type getPeersResponse struct {
|
|
||||||
Values []tracker.CompactPeer `bencode:"values"`
|
|
||||||
Nodes util.CompactPeers `bencode:"nodes"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type peerStream struct {
|
type peerStream struct {
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
Values chan []tracker.CompactPeer
|
Values chan []util.CompactPeer
|
||||||
stop chan struct{}
|
stop chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -577,12 +600,11 @@ func (ps *peerStream) Close() {
|
|||||||
case <-ps.stop:
|
case <-ps.stop:
|
||||||
default:
|
default:
|
||||||
close(ps.stop)
|
close(ps.stop)
|
||||||
close(ps.Values)
|
|
||||||
}
|
}
|
||||||
ps.mu.Unlock()
|
ps.mu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func extractValues(m Msg) (vs []tracker.CompactPeer) {
|
func extractValues(m Msg) (vs []util.CompactPeer) {
|
||||||
r, ok := m["r"]
|
r, ok := m["r"]
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
@ -595,19 +617,17 @@ func extractValues(m Msg) (vs []tracker.CompactPeer) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// log.Fatal(m)
|
|
||||||
vl, ok := v.([]interface{})
|
vl, ok := v.([]interface{})
|
||||||
if !ok {
|
if !ok {
|
||||||
panic(v)
|
panic(v)
|
||||||
}
|
}
|
||||||
vs = make([]tracker.CompactPeer, 0, len(vl))
|
vs = make([]util.CompactPeer, 0, len(vl))
|
||||||
for _, i := range vl {
|
for _, i := range vl {
|
||||||
// log.Printf("%T", i)
|
|
||||||
s, ok := i.(string)
|
s, ok := i.(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
panic(i)
|
panic(i)
|
||||||
}
|
}
|
||||||
var cp tracker.CompactPeer
|
var cp util.CompactPeer
|
||||||
err := cp.UnmarshalBinary([]byte(s))
|
err := cp.UnmarshalBinary([]byte(s))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("error decoding values list element: %s", err)
|
log.Printf("error decoding values list element: %s", err)
|
||||||
@ -620,7 +640,7 @@ func extractValues(m Msg) (vs []tracker.CompactPeer) {
|
|||||||
|
|
||||||
func (s *Server) GetPeers(infoHash string) (ps *peerStream, err error) {
|
func (s *Server) GetPeers(infoHash string) (ps *peerStream, err error) {
|
||||||
ps = &peerStream{
|
ps = &peerStream{
|
||||||
Values: make(chan []tracker.CompactPeer),
|
Values: make(chan []util.CompactPeer),
|
||||||
stop: make(chan struct{}),
|
stop: make(chan struct{}),
|
||||||
}
|
}
|
||||||
done := make(chan struct{})
|
done := make(chan struct{})
|
||||||
@ -657,7 +677,7 @@ func (s *Server) GetPeers(infoHash string) (ps *peerStream, err error) {
|
|||||||
case <-s.closed:
|
case <-s.closed:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ps.Close()
|
close(ps.Values)
|
||||||
}()
|
}()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -689,7 +709,7 @@ func (s *Server) addRootNode() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Populates the node table.
|
// Populates the node table.
|
||||||
func (s *Server) Bootstrap() (err error) {
|
func (s *Server) bootstrap() (err error) {
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
defer s.mu.Unlock()
|
defer s.mu.Unlock()
|
||||||
if len(s.nodes) == 0 {
|
if len(s.nodes) == 0 {
|
||||||
@ -702,7 +722,7 @@ func (s *Server) Bootstrap() (err error) {
|
|||||||
var outstanding sync.WaitGroup
|
var outstanding sync.WaitGroup
|
||||||
for _, node := range s.nodes {
|
for _, node := range s.nodes {
|
||||||
var t *transaction
|
var t *transaction
|
||||||
t, err = s.findNode(node.addr, s.ID)
|
t, err = s.findNode(node.addr, s.id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -768,7 +788,7 @@ func (s *Server) Nodes() (nis []NodeInfo) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) StopServing() {
|
func (s *Server) StopServing() {
|
||||||
s.Socket.Close()
|
s.socket.Close()
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
select {
|
select {
|
||||||
case <-s.closed:
|
case <-s.closed:
|
||||||
|
@ -6,19 +6,26 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
|
"net/http"
|
||||||
|
_ "net/http/pprof"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"bitbucket.org/anacrolix/go.torrent"
|
||||||
"bitbucket.org/anacrolix/go.torrent/testutil"
|
"bitbucket.org/anacrolix/go.torrent/testutil"
|
||||||
|
"bitbucket.org/anacrolix/go.torrent/util"
|
||||||
|
"github.com/anacrolix/libtorgo/metainfo"
|
||||||
|
|
||||||
"bazil.org/fuse"
|
"bazil.org/fuse"
|
||||||
fusefs "bazil.org/fuse/fs"
|
fusefs "bazil.org/fuse/fs"
|
||||||
"bitbucket.org/anacrolix/go.torrent"
|
|
||||||
"github.com/anacrolix/libtorgo/metainfo"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
go http.ListenAndServe(":6061", nil)
|
||||||
|
}
|
||||||
|
|
||||||
func TestTCPAddrString(t *testing.T) {
|
func TestTCPAddrString(t *testing.T) {
|
||||||
ta := &net.TCPAddr{
|
ta := &net.TCPAddr{
|
||||||
IP: net.IPv4(127, 0, 0, 1),
|
IP: net.IPv4(127, 0, 0, 1),
|
||||||
@ -65,6 +72,7 @@ func newGreetingLayout() (tl testLayout, err error) {
|
|||||||
metaInfoBuf := &bytes.Buffer{}
|
metaInfoBuf := &bytes.Buffer{}
|
||||||
testutil.CreateMetaInfo(name, metaInfoBuf)
|
testutil.CreateMetaInfo(name, metaInfoBuf)
|
||||||
tl.Metainfo, err = metainfo.Load(metaInfoBuf)
|
tl.Metainfo, err = metainfo.Load(metaInfoBuf)
|
||||||
|
log.Printf("%x", tl.Metainfo.Info.Pieces)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,14 +87,14 @@ func TestUnmountWedged(t *testing.T) {
|
|||||||
t.Log(err)
|
t.Log(err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
client := torrent.Client{
|
client, err := torrent.NewClient(&torrent.Config{
|
||||||
DataDir: filepath.Join(layout.BaseDir, "incomplete"),
|
DataDir: filepath.Join(layout.BaseDir, "incomplete"),
|
||||||
DisableTrackers: true,
|
DisableTrackers: true,
|
||||||
}
|
NoDHT: true,
|
||||||
client.Start()
|
})
|
||||||
log.Printf("%+v", *layout.Metainfo)
|
log.Printf("%+v", *layout.Metainfo)
|
||||||
client.AddTorrent(layout.Metainfo)
|
client.AddTorrent(layout.Metainfo)
|
||||||
fs := New(&client)
|
fs := New(client)
|
||||||
fuseConn, err := fuse.Mount(layout.MountDir)
|
fuseConn, err := fuse.Mount(layout.MountDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@ -125,40 +133,40 @@ func TestDownloadOnDemand(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
seeder := torrent.Client{
|
seeder, err := torrent.NewClient(&torrent.Config{
|
||||||
DataDir: layout.Completed,
|
DataDir: layout.Completed,
|
||||||
Listener: func() net.Listener {
|
|
||||||
conn, err := net.Listen("tcp", ":0")
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return conn
|
|
||||||
}(),
|
|
||||||
DisableTrackers: true,
|
DisableTrackers: true,
|
||||||
}
|
NoDHT: true,
|
||||||
defer seeder.Listener.Close()
|
})
|
||||||
seeder.Start()
|
http.HandleFunc("/seeder", func(w http.ResponseWriter, req *http.Request) {
|
||||||
|
seeder.WriteStatus(w)
|
||||||
|
})
|
||||||
defer seeder.Stop()
|
defer seeder.Stop()
|
||||||
err = seeder.AddMagnet(fmt.Sprintf("magnet:?xt=urn:btih:%x", layout.Metainfo.Info.Hash))
|
err = seeder.AddMagnet(fmt.Sprintf("magnet:?xt=urn:btih:%x", layout.Metainfo.Info.Hash))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
leecher := torrent.Client{
|
leecher, err := torrent.NewClient(&torrent.Config{
|
||||||
DataDir: filepath.Join(layout.BaseDir, "download"),
|
DataDir: filepath.Join(layout.BaseDir, "download"),
|
||||||
DownloadStrategy: &torrent.ResponsiveDownloadStrategy{},
|
DownloadStrategy: torrent.NewResponsiveDownloadStrategy(0),
|
||||||
DisableTrackers: true,
|
DisableTrackers: true,
|
||||||
}
|
NoDHT: true,
|
||||||
leecher.Start()
|
})
|
||||||
|
http.HandleFunc("/leecher", func(w http.ResponseWriter, req *http.Request) {
|
||||||
|
leecher.WriteStatus(w)
|
||||||
|
})
|
||||||
defer leecher.Stop()
|
defer leecher.Stop()
|
||||||
leecher.AddTorrent(layout.Metainfo)
|
leecher.AddTorrent(layout.Metainfo)
|
||||||
leecher.AddPeers(torrent.BytesInfoHash(layout.Metainfo.Info.Hash), []torrent.Peer{func() torrent.Peer {
|
var ih torrent.InfoHash
|
||||||
tcpAddr := seeder.Listener.Addr().(*net.TCPAddr)
|
util.CopyExact(ih[:], layout.Metainfo.Info.Hash)
|
||||||
|
leecher.AddPeers(ih, []torrent.Peer{func() torrent.Peer {
|
||||||
|
tcpAddr := seeder.ListenAddr().(*net.TCPAddr)
|
||||||
return torrent.Peer{
|
return torrent.Peer{
|
||||||
IP: tcpAddr.IP,
|
IP: tcpAddr.IP,
|
||||||
Port: tcpAddr.Port,
|
Port: tcpAddr.Port,
|
||||||
}
|
}
|
||||||
}()})
|
}()})
|
||||||
fs := New(&leecher)
|
fs := New(leecher)
|
||||||
mountDir := layout.MountDir
|
mountDir := layout.MountDir
|
||||||
fuseConn, err := fuse.Mount(layout.MountDir)
|
fuseConn, err := fuse.Mount(layout.MountDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user