forked from jackpal/Taipei-Torrent
/
torrentLoop.go
120 lines (106 loc) · 2.66 KB
/
torrentLoop.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
package torrent
import (
"encoding/hex"
"log"
"net"
"os"
"os/signal"
)
type Dialer func(network, addr string) (net.Conn, error)
type TorrentFlags struct {
Port int
FileDir string
SeedRatio float64
UseDeadlockDetector bool
UseLPD bool
UseDHT bool
UseUPnP bool
UseNATPMP bool
TrackerlessMode bool
// The dial function to use. Nil means use net.Dial
Dial Dialer
// IP address of gateway used for NAT-PMP
Gateway string
}
func RunTorrents(flags *TorrentFlags, torrentFiles []string) (err error) {
conChan, listenPort, err := ListenForPeerConnections(flags)
if err != nil {
log.Println("Couldn't listen for peers connection: ", err)
return
}
quitChan := listenSigInt()
doneChan := make(chan *TorrentSession)
torrentSessions := make(map[string]*TorrentSession)
for _, torrentFile := range torrentFiles {
var ts *TorrentSession
ts, err = NewTorrentSession(flags, torrentFile, uint16(listenPort))
if err != nil {
log.Println("Could not create torrent session.", err)
return
}
log.Printf("Starting torrent session for %x", ts.M.InfoHash)
torrentSessions[ts.M.InfoHash] = ts
}
for _, ts := range torrentSessions {
go func(ts *TorrentSession) {
ts.DoTorrent()
doneChan <- ts
}(ts)
}
lpd := &Announcer{}
if flags.UseLPD {
lpd = startLPD(torrentSessions, uint16(listenPort))
}
mainLoop:
for {
select {
case ts := <-doneChan:
delete(torrentSessions, ts.M.InfoHash)
if len(torrentSessions) == 0 {
break mainLoop
}
case <-quitChan:
for _, ts := range torrentSessions {
err := ts.Quit()
if err != nil {
log.Println("Failed: ", err)
} else {
log.Println("Done")
}
}
case c := <-conChan:
log.Printf("New bt connection for ih %x", c.Infohash)
if ts, ok := torrentSessions[c.Infohash]; ok {
ts.AcceptNewPeer(c)
}
case announce := <-lpd.Announces:
hexhash, err := hex.DecodeString(announce.Infohash)
if err != nil {
log.Println("Err with hex-decoding:", err)
break
}
if ts, ok := torrentSessions[string(hexhash)]; ok {
log.Printf("Received LPD announce for ih %s", announce.Infohash)
ts.HintNewPeer(announce.Peer)
}
}
}
return
}
func listenSigInt() chan os.Signal {
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, os.Kill)
return c
}
func startLPD(torrentSessions map[string]*TorrentSession, listenPort uint16) (lpd *Announcer) {
lpd, err := NewAnnouncer(listenPort)
if err != nil {
log.Println("Couldn't listen for Local Peer Discoveries: ", err)
return
} else {
for _, ts := range torrentSessions {
lpd.Announce(ts.M.InfoHash)
}
}
return
}