2013-09-26 17:49:15 +08:00
package torrent
import (
2013-09-30 19:51:08 +08:00
"bufio"
2017-08-16 13:35:17 +08:00
"context"
2013-09-29 06:11:24 +08:00
"crypto/rand"
2013-09-26 17:49:15 +08:00
"errors"
2017-09-15 10:56:15 +08:00
"expvar"
2013-10-07 15:58:33 +08:00
"fmt"
2013-09-26 17:49:15 +08:00
"io"
2013-09-29 06:11:24 +08:00
"log"
"net"
2015-03-10 23:41:41 +08:00
"net/url"
2015-03-18 15:21:00 +08:00
"strconv"
2014-09-14 01:50:15 +08:00
"strings"
2013-10-20 22:07:01 +08:00
"time"
2014-03-20 13:58:09 +08:00
2017-01-01 08:01:41 +08:00
"github.com/anacrolix/dht"
"github.com/anacrolix/dht/krpc"
2015-08-06 06:56:36 +08:00
"github.com/anacrolix/missinggo"
2016-03-06 14:26:04 +08:00
"github.com/anacrolix/missinggo/pproffd"
2015-09-06 10:35:56 +08:00
"github.com/anacrolix/missinggo/pubsub"
2016-07-12 14:40:14 +08:00
"github.com/anacrolix/missinggo/slices"
2015-03-20 20:52:53 +08:00
"github.com/anacrolix/sync"
2016-05-19 15:15:10 +08:00
"github.com/dustin/go-humanize"
2016-10-10 11:58:29 +08:00
"golang.org/x/time/rate"
2015-03-26 14:18:08 +08:00
2015-04-28 13:24:17 +08:00
"github.com/anacrolix/torrent/bencode"
2015-03-20 13:37:44 +08:00
"github.com/anacrolix/torrent/iplist"
2015-04-28 13:24:17 +08:00
"github.com/anacrolix/torrent/metainfo"
2015-03-26 14:18:08 +08:00
"github.com/anacrolix/torrent/mse"
2015-03-20 13:37:44 +08:00
pp "github.com/anacrolix/torrent/peer_protocol"
2016-03-28 17:38:30 +08:00
"github.com/anacrolix/torrent/storage"
2013-09-26 17:49:15 +08:00
)
2016-05-03 12:58:26 +08:00
// Clients contain zero or more Torrents. A Client manages a blocklist, the
2015-06-03 11:30:55 +08:00
// TCP/UDP protocol ports, and DHT as desired.
2013-10-06 15:01:39 +08:00
type Client struct {
2016-10-09 21:04:14 +08:00
mu sync . RWMutex
event sync . Cond
closed missinggo . Event
config Config
halfOpenLimit int
peerID [ 20 ] byte
defaultStorage * storage . Client
2017-06-01 20:57:08 +08:00
onClose [ ] func ( )
2016-05-11 19:11:52 +08:00
tcpListener net . Listener
2017-06-16 16:08:24 +08:00
utpSock utpSocket
2015-04-27 12:05:27 +08:00
dHT * dht . Server
2015-09-23 16:25:22 +08:00
ipBlockList iplist . Ranger
2016-10-09 21:04:14 +08:00
// Our BitTorrent protocol extension bytes, sent in our BT handshakes.
2015-04-27 12:05:27 +08:00
extensionBytes peerExtensionBytes
2016-10-09 21:04:14 +08:00
// The net.Addr.String part that should be common to all active listeners.
2016-10-10 14:29:39 +08:00
listenAddr string
uploadLimit * rate . Limiter
downloadLimit * rate . Limiter
2016-10-09 21:04:14 +08:00
2015-03-18 15:29:51 +08:00
// Set of addresses that have our client ID. This intentionally will
// include ourselves if we end up trying to connect to our own address
// through legitimate channels.
dopplegangerAddrs map [ string ] struct { }
2016-05-24 00:09:47 +08:00
badPeerIPs map [ string ] struct { }
2016-10-09 21:04:14 +08:00
torrents map [ metainfo . Hash ] * Torrent
2015-02-25 08:25:22 +08:00
}
2014-08-25 03:24:18 +08:00
2016-07-29 22:37:52 +08:00
func ( cl * Client ) BadPeerIPs ( ) [ ] string {
cl . mu . RLock ( )
defer cl . mu . RUnlock ( )
2016-11-27 11:26:45 +08:00
return cl . badPeerIPsLocked ( )
}
func ( cl * Client ) badPeerIPsLocked ( ) [ ] string {
2016-07-29 22:37:52 +08:00
return slices . FromMapKeys ( cl . badPeerIPs ) . ( [ ] string )
}
2016-04-19 12:11:11 +08:00
func ( cl * Client ) IPBlockList ( ) iplist . Ranger {
cl . mu . Lock ( )
defer cl . mu . Unlock ( )
return cl . ipBlockList
2013-09-26 17:49:15 +08:00
}
2016-04-19 12:11:11 +08:00
func ( cl * Client ) SetIPBlockList ( list iplist . Ranger ) {
cl . mu . Lock ( )
defer cl . mu . Unlock ( )
cl . ipBlockList = list
if cl . dHT != nil {
cl . dHT . SetIPBlockList ( list )
2014-11-30 10:33:17 +08:00
}
2014-11-29 09:41:53 +08:00
}
2017-11-08 16:28:37 +08:00
func ( cl * Client ) PeerID ( ) [ 20 ] byte {
return cl . peerID
2014-11-17 03:54:43 +08:00
}
2016-05-11 19:11:52 +08:00
type torrentAddr string
2017-01-01 08:03:02 +08:00
func ( torrentAddr ) Network ( ) string { return "" }
2016-05-11 19:11:52 +08:00
func ( me torrentAddr ) String ( ) string { return string ( me ) }
func ( cl * Client ) ListenAddr ( ) net . Addr {
if cl . listenAddr == "" {
return nil
2014-11-17 03:16:26 +08:00
}
2016-05-11 19:11:52 +08:00
return torrentAddr ( cl . listenAddr )
2014-08-21 16:07:06 +08:00
}
2015-03-08 14:28:14 +08:00
// Writes out a human readable status of the client, such as for writing to a
// HTTP status page.
2014-11-19 11:56:50 +08:00
func ( cl * Client ) WriteStatus ( _w io . Writer ) {
2016-11-27 11:26:45 +08:00
cl . mu . Lock ( )
defer cl . mu . Unlock ( )
2014-11-19 11:56:50 +08:00
w := bufio . NewWriter ( _w )
defer w . Flush ( )
2015-02-25 11:52:19 +08:00
if addr := cl . ListenAddr ( ) ; addr != nil {
2016-07-29 22:37:52 +08:00
fmt . Fprintf ( w , "Listening on %s\n" , addr )
2015-02-25 11:52:19 +08:00
} else {
2015-03-10 23:39:01 +08:00
fmt . Fprintln ( w , "Not listening!" )
2015-02-25 11:52:19 +08:00
}
2016-07-29 22:37:52 +08:00
fmt . Fprintf ( w , "Peer ID: %+q\n" , cl . PeerID ( ) )
2016-11-27 11:26:45 +08:00
fmt . Fprintf ( w , "Banned IPs: %d\n" , len ( cl . badPeerIPsLocked ( ) ) )
2016-07-29 22:37:52 +08:00
if dht := cl . DHT ( ) ; dht != nil {
dhtStats := dht . Stats ( )
2015-08-03 22:31:53 +08:00
fmt . Fprintf ( w , "DHT nodes: %d (%d good, %d banned)\n" , dhtStats . Nodes , dhtStats . GoodNodes , dhtStats . BadNodes )
2016-07-29 22:37:52 +08:00
fmt . Fprintf ( w , "DHT Server ID: %x\n" , dht . ID ( ) )
fmt . Fprintf ( w , "DHT port: %d\n" , missinggo . AddrPort ( dht . Addr ( ) ) )
2015-04-01 14:29:55 +08:00
fmt . Fprintf ( w , "DHT announces: %d\n" , dhtStats . ConfirmedAnnounces )
fmt . Fprintf ( w , "Outstanding transactions: %d\n" , dhtStats . OutstandingTransactions )
2014-07-22 23:50:49 +08:00
}
2016-11-27 11:26:45 +08:00
fmt . Fprintf ( w , "# Torrents: %d\n" , len ( cl . torrentsAsSlice ( ) ) )
2014-07-16 15:07:28 +08:00
fmt . Fprintln ( w )
2016-11-27 11:26:45 +08:00
for _ , t := range slices . Sort ( cl . torrentsAsSlice ( ) , func ( l , r * Torrent ) bool {
2016-07-29 22:37:52 +08:00
return l . InfoHash ( ) . AsString ( ) < r . InfoHash ( ) . AsString ( )
} ) . ( [ ] * Torrent ) {
2016-11-27 11:26:45 +08:00
if t . name ( ) == "" {
2014-11-19 04:32:51 +08:00
fmt . Fprint ( w , "<unknown name>" )
} else {
2016-11-27 11:26:45 +08:00
fmt . Fprint ( w , t . name ( ) )
2014-11-19 04:32:51 +08:00
}
2015-02-21 11:57:37 +08:00
fmt . Fprint ( w , "\n" )
2017-08-29 13:16:53 +08:00
if t . info != nil {
fmt . Fprintf ( w , "%f%% of %d bytes (%s)" , 100 * ( 1 - float64 ( t . bytesMissingLocked ( ) ) / float64 ( t . info . TotalLength ( ) ) ) , t . length , humanize . Bytes ( uint64 ( t . info . TotalLength ( ) ) ) )
2015-02-21 11:57:37 +08:00
} else {
w . WriteString ( "<missing metainfo>" )
2014-11-19 04:32:51 +08:00
}
fmt . Fprint ( w , "\n" )
2016-07-12 19:23:20 +08:00
t . writeStatus ( w )
2014-07-17 13:58:33 +08:00
fmt . Fprintln ( w )
2014-06-26 15:29:12 +08:00
}
}
2017-06-16 16:08:24 +08:00
func listenUTP ( networkSuffix , addr string ) ( utpSocket , error ) {
return NewUtpSocket ( "udp" + networkSuffix , addr )
2016-05-11 19:11:52 +08:00
}
func listenTCP ( networkSuffix , addr string ) ( net . Listener , error ) {
return net . Listen ( "tcp" + networkSuffix , addr )
}
2017-06-16 16:08:24 +08:00
func listenBothSameDynamicPort ( networkSuffix , host string ) ( tcpL net . Listener , utpSock utpSocket , listenedAddr string , err error ) {
2016-05-11 19:11:52 +08:00
for {
tcpL , err = listenTCP ( networkSuffix , net . JoinHostPort ( host , "0" ) )
if err != nil {
return
}
listenedAddr = tcpL . Addr ( ) . String ( )
utpSock , err = listenUTP ( networkSuffix , listenedAddr )
if err == nil {
return
}
tcpL . Close ( )
if ! strings . Contains ( err . Error ( ) , "address already in use" ) {
return
}
}
}
2016-05-24 17:45:42 +08:00
// Listen to enabled protocols, ensuring ports match.
2017-06-16 16:08:24 +08:00
func listen ( tcp , utp bool , networkSuffix , addr string ) ( tcpL net . Listener , utpSock utpSocket , listenedAddr string , err error ) {
2016-05-11 19:11:52 +08:00
if addr == "" {
addr = ":50007"
}
2016-08-30 12:19:29 +08:00
if tcp && utp {
var host string
var port int
host , port , err = missinggo . ParseHostPort ( addr )
if err != nil {
return
}
if port == 0 {
// If both protocols are active, they need to have the same port.
return listenBothSameDynamicPort ( networkSuffix , host )
}
2016-05-11 19:11:52 +08:00
}
2016-05-24 17:45:42 +08:00
defer func ( ) {
if err != nil {
listenedAddr = ""
}
} ( )
2016-05-11 19:11:52 +08:00
if tcp {
tcpL , err = listenTCP ( networkSuffix , addr )
if err != nil {
return
}
2016-05-24 17:45:42 +08:00
defer func ( ) {
if err != nil {
tcpL . Close ( )
}
} ( )
2016-05-24 13:18:04 +08:00
listenedAddr = tcpL . Addr ( ) . String ( )
2016-05-11 19:11:52 +08:00
}
if utp {
utpSock , err = listenUTP ( networkSuffix , addr )
2016-05-24 17:45:42 +08:00
if err != nil {
2016-05-24 13:24:29 +08:00
return
2016-05-11 19:11:52 +08:00
}
2016-05-24 13:18:04 +08:00
listenedAddr = utpSock . Addr ( ) . String ( )
2016-05-11 19:11:52 +08:00
}
return
}
2015-06-03 11:30:55 +08:00
// Creates a new client.
2014-08-21 16:07:06 +08:00
func NewClient ( cfg * Config ) ( cl * Client , err error ) {
if cfg == nil {
2017-08-18 09:14:28 +08:00
cfg = & Config {
DHTConfig : dht . ServerConfig {
2017-08-25 14:28:27 +08:00
StartingNodes : dht . GlobalBootstrapAddrs ,
2017-08-18 09:14:28 +08:00
} ,
}
2013-10-14 22:39:12 +08:00
}
2014-08-21 16:07:06 +08:00
2015-04-01 11:30:22 +08:00
defer func ( ) {
if err != nil {
cl = nil
}
} ( )
2014-08-21 16:07:06 +08:00
cl = & Client {
2016-07-05 14:23:17 +08:00
halfOpenLimit : defaultHalfOpenConnsPerTorrent ,
2016-03-28 17:38:30 +08:00
config : * cfg ,
2015-03-18 15:29:51 +08:00
dopplegangerAddrs : make ( map [ string ] struct { } ) ,
2016-04-04 11:01:31 +08:00
torrents : make ( map [ metainfo . Hash ] * Torrent ) ,
2014-08-21 16:07:06 +08:00
}
2017-06-01 20:57:08 +08:00
defer func ( ) {
if err == nil {
return
}
cl . Close ( )
} ( )
2016-10-10 11:58:29 +08:00
if cfg . UploadRateLimiter == nil {
cl . uploadLimit = rate . NewLimiter ( rate . Inf , 0 )
} else {
cl . uploadLimit = cfg . UploadRateLimiter
}
2016-10-10 14:29:39 +08:00
if cfg . DownloadRateLimiter == nil {
cl . downloadLimit = rate . NewLimiter ( rate . Inf , 0 )
} else {
cl . downloadLimit = cfg . DownloadRateLimiter
}
2016-03-30 16:11:55 +08:00
missinggo . CopyExact ( & cl . extensionBytes , defaultExtensionBytes )
2014-08-21 16:07:06 +08:00
cl . event . L = & cl . mu
2016-09-02 13:10:57 +08:00
storageImpl := cfg . DefaultStorage
if storageImpl == nil {
2017-09-16 22:45:12 +08:00
// We'd use mmap but HFS+ doesn't support sparse files.
2016-09-02 13:10:57 +08:00
storageImpl = storage . NewFile ( cfg . DataDir )
2017-06-01 20:57:08 +08:00
cl . onClose = append ( cl . onClose , func ( ) {
if err := storageImpl . Close ( ) ; err != nil {
log . Printf ( "error closing default storage: %s" , err )
}
} )
2015-02-25 12:41:13 +08:00
}
2016-09-02 13:10:57 +08:00
cl . defaultStorage = storage . NewClient ( storageImpl )
2015-08-03 23:07:22 +08:00
if cfg . IPBlocklist != nil {
cl . ipBlockList = cfg . IPBlocklist
2014-12-02 06:39:09 +08:00
}
2014-11-17 03:54:43 +08:00
if cfg . PeerID != "" {
2016-03-30 16:11:55 +08:00
missinggo . CopyExact ( & cl . peerID , cfg . PeerID )
2014-11-17 03:54:43 +08:00
} else {
2015-03-08 14:28:14 +08:00
o := copy ( cl . peerID [ : ] , bep20 )
2014-11-17 03:54:43 +08:00
_ , err = rand . Read ( cl . peerID [ o : ] )
if err != nil {
panic ( "error generating peer id" )
}
2013-09-29 06:11:24 +08:00
}
2014-08-21 16:07:06 +08:00
2016-05-11 19:11:52 +08:00
cl . tcpListener , cl . utpSock , cl . listenAddr , err = listen (
! cl . config . DisableTCP ,
! cl . config . DisableUTP ,
func ( ) string {
2015-08-05 00:41:50 +08:00
if cl . config . DisableIPv6 {
2016-05-11 19:11:52 +08:00
return "4"
2015-08-05 00:41:50 +08:00
} else {
2016-05-11 19:11:52 +08:00
return ""
2015-08-05 00:41:50 +08:00
}
2016-05-11 19:11:52 +08:00
} ( ) ,
cl . config . ListenAddr )
if err != nil {
return
2014-11-17 03:29:31 +08:00
}
2016-05-11 19:11:52 +08:00
if cl . tcpListener != nil {
go cl . acceptConnections ( cl . tcpListener , false )
}
if cl . utpSock != nil {
2015-01-10 21:16:19 +08:00
go cl . acceptConnections ( cl . utpSock , true )
2014-03-17 22:44:22 +08:00
}
2014-08-21 16:07:06 +08:00
if ! cfg . NoDHT {
2014-11-29 02:13:08 +08:00
dhtCfg := cfg . DHTConfig
2015-08-03 22:43:46 +08:00
if dhtCfg . IPBlocklist == nil {
dhtCfg . IPBlocklist = cl . ipBlockList
2014-11-20 10:02:20 +08:00
}
2017-07-20 22:40:49 +08:00
if dhtCfg . Conn == nil {
if cl . utpSock != nil {
dhtCfg . Conn = cl . utpSock
} else {
dhtCfg . Conn , err = net . ListenPacket ( "udp" , firstNonEmptyString ( cl . listenAddr , cl . config . ListenAddr ) )
if err != nil {
return
}
}
2014-11-29 02:13:08 +08:00
}
2016-11-26 21:05:19 +08:00
if dhtCfg . OnAnnouncePeer == nil {
dhtCfg . OnAnnouncePeer = cl . onDHTAnnouncePeer
}
2016-01-16 21:12:53 +08:00
cl . dHT , err = dht . NewServer ( & dhtCfg )
2014-08-21 16:07:06 +08:00
if err != nil {
return
}
2017-08-10 09:18:48 +08:00
go func ( ) {
if _ , err := cl . dHT . Bootstrap ( ) ; err != nil {
log . Printf ( "error bootstrapping dht: %s" , err )
}
} ( )
2014-08-21 16:07:06 +08:00
}
return
2014-03-17 22:44:22 +08:00
}
2016-05-24 17:46:24 +08:00
func firstNonEmptyString ( ss ... string ) string {
for _ , s := range ss {
if s != "" {
return s
}
}
return ""
}
2014-04-09 00:36:05 +08:00
// Stops the client. All connections to peers are closed and all activity will
// come to a halt.
2016-04-19 12:11:11 +08:00
func ( cl * Client ) Close ( ) {
cl . mu . Lock ( )
defer cl . mu . Unlock ( )
cl . closed . Set ( )
if cl . dHT != nil {
cl . dHT . Close ( )
}
2016-05-11 19:11:52 +08:00
if cl . utpSock != nil {
2017-06-16 16:08:24 +08:00
cl . utpSock . Close ( )
2016-05-11 19:11:52 +08:00
}
if cl . tcpListener != nil {
cl . tcpListener . Close ( )
2014-11-21 14:07:04 +08:00
}
2016-04-19 12:11:11 +08:00
for _ , t := range cl . torrents {
2015-02-09 21:12:29 +08:00
t . close ( )
2014-03-18 19:39:33 +08:00
}
2017-06-01 20:57:08 +08:00
for _ , f := range cl . onClose {
f ( )
}
2016-04-19 12:11:11 +08:00
cl . event . Broadcast ( )
2014-03-18 19:39:33 +08:00
}
2014-12-01 17:27:11 +08:00
var ipv6BlockRange = iplist . Range { Description : "non-IPv4 address" }
2015-10-18 21:00:26 +08:00
func ( cl * Client ) ipBlockRange ( ip net . IP ) ( r iplist . Range , blocked bool ) {
2014-11-29 09:41:53 +08:00
if cl . ipBlockList == nil {
2014-11-30 10:33:17 +08:00
return
2014-11-29 09:41:53 +08:00
}
2015-04-01 14:36:51 +08:00
ip4 := ip . To4 ( )
2015-10-18 21:00:26 +08:00
// If blocklists are enabled, then block non-IPv4 addresses, because
// blocklists do not yet support IPv6.
2015-04-01 14:36:51 +08:00
if ip4 == nil {
2015-11-13 19:33:50 +08:00
if missinggo . CryHeard ( ) {
log . Printf ( "blocking non-IPv4 address: %s" , ip )
}
2015-10-18 21:00:26 +08:00
r = ipv6BlockRange
blocked = true
2014-12-01 17:27:11 +08:00
return
}
2015-10-18 21:00:26 +08:00
return cl . ipBlockList . Lookup ( ip4 )
2014-11-29 09:41:53 +08:00
}
2015-03-18 15:36:27 +08:00
func ( cl * Client ) waitAccept ( ) {
for {
for _ , t := range cl . torrents {
2016-07-05 14:23:17 +08:00
if t . wantConns ( ) {
2015-03-18 15:36:27 +08:00
return
}
}
2016-03-05 16:36:21 +08:00
if cl . closed . IsSet ( ) {
2015-08-03 23:15:09 +08:00
return
}
2015-03-18 15:36:27 +08:00
cl . event . Wait ( )
}
}
2014-11-17 03:29:31 +08:00
func ( cl * Client ) acceptConnections ( l net . Listener , utp bool ) {
2016-07-05 22:38:43 +08:00
cl . mu . Lock ( )
defer cl . mu . Unlock ( )
2014-03-17 22:44:22 +08:00
for {
2015-03-18 15:36:27 +08:00
cl . waitAccept ( )
2016-07-05 22:38:43 +08:00
cl . mu . Unlock ( )
2014-11-17 03:29:31 +08:00
conn , err := l . Accept ( )
2016-03-06 14:26:04 +08:00
conn = pproffd . WrapNetConn ( conn )
2016-07-05 22:38:43 +08:00
cl . mu . Lock ( )
2016-03-05 16:36:21 +08:00
if cl . closed . IsSet ( ) {
2014-07-03 23:44:15 +08:00
if conn != nil {
conn . Close ( )
}
2014-03-18 19:39:33 +08:00
return
}
2014-03-17 22:44:22 +08:00
if err != nil {
log . Print ( err )
2016-03-05 16:36:21 +08:00
// I think something harsher should happen here? Our accept
// routine just fucked off.
2014-03-17 22:44:22 +08:00
return
}
2015-06-29 22:35:47 +08:00
if utp {
acceptUTP . Add ( 1 )
} else {
acceptTCP . Add ( 1 )
}
2016-09-21 19:00:18 +08:00
if cl . config . Debug {
log . Printf ( "accepted connection from %s" , conn . RemoteAddr ( ) )
}
2016-05-24 00:09:47 +08:00
reject := cl . badPeerIPPort (
missinggo . AddrIP ( conn . RemoteAddr ( ) ) ,
missinggo . AddrPort ( conn . RemoteAddr ( ) ) )
if reject {
2016-09-21 19:00:18 +08:00
if cl . config . Debug {
log . Printf ( "rejecting connection from %s" , conn . RemoteAddr ( ) )
}
2015-06-29 22:35:47 +08:00
acceptReject . Add ( 1 )
2014-12-26 14:18:36 +08:00
conn . Close ( )
2014-11-29 09:41:53 +08:00
continue
}
2015-03-18 15:28:13 +08:00
go cl . incomingConnection ( conn , utp )
}
}
func ( cl * Client ) incomingConnection ( nc net . Conn , utp bool ) {
defer nc . Close ( )
if tc , ok := nc . ( * net . TCPConn ) ; ok {
tc . SetLinger ( 0 )
}
2016-10-10 13:55:56 +08:00
c := cl . newConnection ( nc )
2015-03-18 15:28:13 +08:00
c . Discovery = peerSourceIncoming
c . uTP = utp
2016-05-16 17:50:10 +08:00
cl . runReceivedConn ( c )
2013-09-26 17:49:15 +08:00
}
2015-03-20 07:52:01 +08:00
// Returns a handle to the given torrent, if it's present in the client.
2016-04-04 11:01:31 +08:00
func ( cl * Client ) Torrent ( ih metainfo . Hash ) ( t * Torrent , ok bool ) {
2015-03-18 15:28:13 +08:00
cl . mu . Lock ( )
defer cl . mu . Unlock ( )
2016-04-03 16:40:43 +08:00
t , ok = cl . torrents [ ih ]
2015-03-18 15:28:13 +08:00
return
}
2016-04-19 12:11:11 +08:00
func ( cl * Client ) torrent ( ih metainfo . Hash ) * Torrent {
return cl . torrents [ ih ]
2013-09-29 06:11:24 +08:00
}
2014-11-17 13:27:01 +08:00
type dialResult struct {
2015-03-18 15:28:13 +08:00
Conn net . Conn
UTP bool
2014-11-17 13:27:01 +08:00
}
2017-08-16 15:05:05 +08:00
func countDialResult ( err error ) {
2014-11-17 15:44:06 +08:00
if err == nil {
successfulDials . Add ( 1 )
2017-08-16 15:05:05 +08:00
} else {
unsuccessfulDials . Add ( 1 )
2014-11-17 15:44:06 +08:00
}
2014-11-17 13:27:01 +08:00
}
2014-11-19 11:53:00 +08:00
func reducedDialTimeout ( max time . Duration , halfOpenLimit int , pendingPeers int ) ( ret time . Duration ) {
ret = max / time . Duration ( ( pendingPeers + halfOpenLimit ) / halfOpenLimit )
if ret < minDialTimeout {
ret = minDialTimeout
}
return
2014-11-18 08:04:09 +08:00
}
2015-09-17 10:54:03 +08:00
// Returns whether an address is known to connect to a client with our own ID.
2016-04-19 12:11:11 +08:00
func ( cl * Client ) dopplegangerAddr ( addr string ) bool {
_ , ok := cl . dopplegangerAddrs [ addr ]
2015-03-18 15:29:51 +08:00
return ok
}
2014-07-22 19:45:12 +08:00
// Start the process of connecting to the given peer for the given torrent if
// appropriate.
2016-04-19 12:11:11 +08:00
func ( cl * Client ) initiateConn ( peer Peer , t * Torrent ) {
if peer . Id == cl . peerID {
2013-09-29 06:11:24 +08:00
return
}
2016-05-24 00:09:47 +08:00
if cl . badPeerIPPort ( peer . IP , peer . Port ) {
2014-11-17 03:30:44 +08:00
return
2014-08-28 07:35:13 +08:00
}
2016-05-24 00:09:47 +08:00
addr := net . JoinHostPort ( peer . IP . String ( ) , fmt . Sprintf ( "%d" , peer . Port ) )
if t . addrActive ( addr ) {
2014-11-29 09:41:53 +08:00
return
}
2017-09-15 17:10:09 +08:00
t . halfOpen [ addr ] = peer
2016-04-19 12:11:11 +08:00
go cl . outgoingConnection ( t , addr , peer . Source )
2015-03-18 15:28:13 +08:00
}
2017-08-16 15:05:05 +08:00
func ( cl * Client ) dialTCP ( ctx context . Context , addr string ) ( c net . Conn , err error ) {
2017-08-16 13:48:30 +08:00
d := net . Dialer {
2017-08-16 15:05:05 +08:00
// LocalAddr: cl.tcpListener.Addr(),
2017-08-16 13:48:30 +08:00
}
2017-08-16 15:05:05 +08:00
c , err = d . DialContext ( ctx , "tcp" , addr )
countDialResult ( err )
2015-03-18 15:28:13 +08:00
if err == nil {
c . ( * net . TCPConn ) . SetLinger ( 0 )
}
2016-06-20 15:51:40 +08:00
c = pproffd . WrapNetConn ( c )
2015-03-18 15:28:13 +08:00
return
}
2017-08-16 15:05:05 +08:00
func ( cl * Client ) dialUTP ( ctx context . Context , addr string ) ( c net . Conn , err error ) {
c , err = cl . utpSock . DialContext ( ctx , addr )
countDialResult ( err )
return
2015-03-18 15:28:13 +08:00
}
2017-09-15 10:56:15 +08:00
var (
dialledFirstUtp = expvar . NewInt ( "dialledFirstUtp" )
dialledFirstNotUtp = expvar . NewInt ( "dialledFirstNotUtp" )
)
2015-08-02 02:04:42 +08:00
// Returns a connection over UTP or TCP, whichever is first to connect.
2017-08-16 15:05:05 +08:00
func ( cl * Client ) dialFirst ( ctx context . Context , addr string ) ( conn net . Conn , utp bool ) {
ctx , cancel := context . WithCancel ( ctx )
// As soon as we return one connection, cancel the others.
defer cancel ( )
2015-03-18 15:28:13 +08:00
left := 0
resCh := make ( chan dialResult , left )
2016-04-19 12:11:11 +08:00
if ! cl . config . DisableUTP {
2017-08-16 08:32:25 +08:00
left ++
2017-08-16 15:05:05 +08:00
go func ( ) {
c , _ := cl . dialUTP ( ctx , addr )
resCh <- dialResult { c , true }
} ( )
2015-03-18 15:28:13 +08:00
}
2016-04-19 12:11:11 +08:00
if ! cl . config . DisableTCP {
2017-08-16 08:32:25 +08:00
left ++
2017-08-16 15:05:05 +08:00
go func ( ) {
c , _ := cl . dialTCP ( ctx , addr )
resCh <- dialResult { c , false }
} ( )
2015-03-18 15:28:13 +08:00
}
var res dialResult
// Wait for a successful connection.
for ; left > 0 && res . Conn == nil ; left -- {
res = <- resCh
}
if left > 0 {
// There are still incompleted dials.
2014-04-03 20:16:59 +08:00
go func ( ) {
2015-03-18 15:28:13 +08:00
for ; left > 0 ; left -- {
conn := ( <- resCh ) . Conn
if conn != nil {
conn . Close ( )
}
2014-04-03 20:16:59 +08:00
}
} ( )
2015-03-18 15:28:13 +08:00
}
conn = res . Conn
utp = res . UTP
2017-09-15 10:56:15 +08:00
if conn != nil {
if utp {
dialledFirstUtp . Add ( 1 )
} else {
dialledFirstNotUtp . Add ( 1 )
}
}
2015-03-18 15:28:13 +08:00
return
}
2016-04-19 12:11:11 +08:00
func ( cl * Client ) noLongerHalfOpen ( t * Torrent , addr string ) {
2016-04-03 14:50:53 +08:00
if _ , ok := t . halfOpen [ addr ] ; ! ok {
2015-03-18 15:28:13 +08:00
panic ( "invariant broken" )
}
2016-04-03 14:50:53 +08:00
delete ( t . halfOpen , addr )
2016-04-19 12:11:11 +08:00
cl . openNewConns ( t )
2015-03-18 15:28:13 +08:00
}
2016-03-02 20:27:46 +08:00
// Performs initiator handshakes and returns a connection. Returns nil
// *connection if no connection for valid reasons.
2017-09-13 16:20:20 +08:00
func ( cl * Client ) handshakesConnection ( ctx context . Context , nc net . Conn , t * Torrent , encryptHeader , utp bool ) ( c * connection , err error ) {
2016-10-10 13:55:56 +08:00
c = cl . newConnection ( nc )
2017-09-13 16:20:20 +08:00
c . headerEncrypted = encryptHeader
2015-08-02 02:04:42 +08:00
c . uTP = utp
2017-08-16 15:05:05 +08:00
ctx , cancel := context . WithTimeout ( ctx , handshakesTimeout )
defer cancel ( )
dl , ok := ctx . Deadline ( )
if ! ok {
panic ( ctx )
}
err = nc . SetDeadline ( dl )
2015-08-02 02:04:42 +08:00
if err != nil {
2017-08-16 15:05:05 +08:00
panic ( err )
2015-08-02 02:04:42 +08:00
}
2017-08-16 15:05:05 +08:00
ok , err = cl . initiateHandshakes ( c , t )
2015-08-02 02:04:42 +08:00
if ! ok {
c = nil
}
return
}
2017-09-15 10:56:15 +08:00
var (
initiatedConnWithPreferredHeaderEncryption = expvar . NewInt ( "initiatedConnWithPreferredHeaderEncryption" )
initiatedConnWithFallbackHeaderEncryption = expvar . NewInt ( "initiatedConnWithFallbackHeaderEncryption" )
)
2015-03-18 15:28:13 +08:00
// Returns nil connection and nil error if no connection could be established
// for valid reasons.
2016-04-19 12:11:11 +08:00
func ( cl * Client ) establishOutgoingConn ( t * Torrent , addr string ) ( c * connection , err error ) {
2017-08-16 15:05:05 +08:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , time . Minute )
defer cancel ( )
nc , utp := cl . dialFirst ( ctx , addr )
2015-03-18 15:28:13 +08:00
if nc == nil {
return
}
2017-09-13 16:20:20 +08:00
obfuscatedHeaderFirst := ! cl . config . DisableEncryption && ! cl . config . PreferNoEncryption
c , err = cl . handshakesConnection ( ctx , nc , t , obfuscatedHeaderFirst , utp )
2015-03-18 15:28:13 +08:00
if err != nil {
2017-09-15 10:56:54 +08:00
// log.Printf("error initiating connection handshakes: %s", err)
2015-03-18 15:28:13 +08:00
nc . Close ( )
return
} else if c != nil {
2017-09-15 10:56:15 +08:00
initiatedConnWithPreferredHeaderEncryption . Add ( 1 )
2015-03-18 15:28:13 +08:00
return
}
nc . Close ( )
2017-09-13 16:20:20 +08:00
if cl . config . ForceEncryption {
// We should have just tried with an obfuscated header. A plaintext
// header can't result in an encrypted connection, so we're done.
if ! obfuscatedHeaderFirst {
panic ( cl . config . EncryptionPolicy )
}
2015-06-08 16:16:01 +08:00
return
}
2016-09-16 10:42:41 +08:00
// Try again with encryption if we didn't earlier, or without if we did,
// using whichever protocol type worked last time.
2015-03-18 15:28:13 +08:00
if utp {
2017-08-16 15:05:05 +08:00
nc , err = cl . dialUTP ( ctx , addr )
2015-03-18 15:28:13 +08:00
} else {
2017-08-16 15:05:05 +08:00
nc , err = cl . dialTCP ( ctx , addr )
2015-03-18 15:28:13 +08:00
}
if err != nil {
2017-09-15 10:56:54 +08:00
err = fmt . Errorf ( "error dialing for header encryption fallback: %s" , err )
2015-03-18 15:28:13 +08:00
return
}
2017-09-13 16:20:20 +08:00
c , err = cl . handshakesConnection ( ctx , nc , t , ! obfuscatedHeaderFirst , utp )
2016-03-02 20:27:46 +08:00
if err != nil || c == nil {
2015-03-18 15:28:13 +08:00
nc . Close ( )
}
2017-09-15 10:56:15 +08:00
if err == nil && c != nil {
initiatedConnWithFallbackHeaderEncryption . Add ( 1 )
}
2015-03-18 15:28:13 +08:00
return
}
2014-11-17 13:27:01 +08:00
2015-03-18 15:28:13 +08:00
// Called to dial out and run a connection. The addr we're given is already
// considered half-open.
2016-04-19 12:11:11 +08:00
func ( cl * Client ) outgoingConnection ( t * Torrent , addr string , ps peerSource ) {
c , err := cl . establishOutgoingConn ( t , addr )
cl . mu . Lock ( )
defer cl . mu . Unlock ( )
2015-03-18 15:28:13 +08:00
// Don't release lock between here and addConnection, unless it's for
// failure.
2016-04-19 12:11:11 +08:00
cl . noLongerHalfOpen ( t , addr )
2015-03-18 15:28:13 +08:00
if err != nil {
2016-04-19 12:11:11 +08:00
if cl . config . Debug {
2016-03-22 10:10:18 +08:00
log . Printf ( "error establishing outgoing connection: %s" , err )
}
2015-03-18 15:28:13 +08:00
return
}
if c == nil {
return
}
defer c . Close ( )
c . Discovery = ps
2016-05-16 17:50:10 +08:00
cl . runInitiatedHandshookConn ( c , t )
2013-09-29 06:11:24 +08:00
}
2014-11-17 03:16:26 +08:00
// The port number for incoming peer connections. 0 if the client isn't
// listening.
2014-06-29 16:57:49 +08:00
func ( cl * Client ) incomingPeerPort ( ) int {
2016-05-11 19:11:52 +08:00
if cl . listenAddr == "" {
2014-06-29 16:57:49 +08:00
return 0
}
2016-05-11 19:11:52 +08:00
_ , port , err := missinggo . ParseHostPort ( cl . listenAddr )
if err != nil {
panic ( err )
}
return port
2014-06-29 16:57:49 +08:00
}
2016-04-19 12:11:11 +08:00
func ( cl * Client ) initiateHandshakes ( c * connection , t * Torrent ) ( ok bool , err error ) {
2017-09-13 16:20:20 +08:00
if c . headerEncrypted {
2016-10-10 13:30:51 +08:00
var rw io . ReadWriter
2017-09-13 16:20:20 +08:00
rw , err = mse . InitiateHandshake (
struct {
io . Reader
io . Writer
} { c . r , c . w } ,
t . infoHash [ : ] ,
nil ,
func ( ) uint32 {
switch {
case cl . config . ForceEncryption :
return mse . CryptoMethodRC4
case cl . config . DisableEncryption :
return mse . CryptoMethodPlaintext
default :
return mse . AllSupportedCrypto
}
} ( ) ,
)
2016-10-10 13:30:51 +08:00
c . setRW ( rw )
2015-03-18 15:28:13 +08:00
if err != nil {
return
2014-09-14 01:45:38 +08:00
}
}
2016-04-19 12:11:11 +08:00
ih , ok , err := cl . connBTHandshake ( c , & t . infoHash )
2016-04-03 16:40:43 +08:00
if ih != t . infoHash {
2015-03-18 15:28:13 +08:00
ok = false
}
2014-08-28 07:45:20 +08:00
return
}
2017-04-04 16:41:08 +08:00
// Calls f with any secret keys.
func ( cl * Client ) forSkeys ( f func ( [ ] byte ) bool ) {
cl . mu . Lock ( )
defer cl . mu . Unlock ( )
for ih := range cl . torrents {
if ! f ( ih [ : ] ) {
break
}
}
}
2015-03-27 12:37:58 +08:00
// Do encryption and bittorrent handshakes as receiver.
2016-04-03 16:40:43 +08:00
func ( cl * Client ) receiveHandshakes ( c * connection ) ( t * Torrent , err error ) {
2017-09-13 16:20:20 +08:00
var rw io . ReadWriter
rw , c . headerEncrypted , c . cryptoMethod , err = handleEncryption ( c . rw ( ) , cl . forSkeys , cl . config . EncryptionPolicy )
c . setRW ( rw )
if err != nil {
if err == mse . ErrNoSecretKeyMatch {
err = nil
2015-03-18 15:28:13 +08:00
}
2017-09-13 16:20:20 +08:00
return
2014-08-28 08:06:57 +08:00
}
2017-09-13 16:20:20 +08:00
if cl . config . ForceEncryption && ! c . headerEncrypted {
2016-09-16 10:42:41 +08:00
err = errors . New ( "connection not encrypted" )
return
}
2015-03-18 15:28:13 +08:00
ih , ok , err := cl . connBTHandshake ( c , nil )
2015-02-09 21:17:59 +08:00
if err != nil {
2015-06-28 14:39:04 +08:00
err = fmt . Errorf ( "error during bt handshake: %s" , err )
2015-02-09 21:17:59 +08:00
return
}
2015-03-18 15:28:13 +08:00
if ! ok {
return
2015-03-13 03:21:13 +08:00
}
2015-03-18 15:28:13 +08:00
cl . mu . Lock ( )
t = cl . torrents [ ih ]
cl . mu . Unlock ( )
return
}
// Returns !ok if handshake failed for valid reasons.
2016-04-04 11:01:31 +08:00
func ( cl * Client ) connBTHandshake ( c * connection , ih * metainfo . Hash ) ( ret metainfo . Hash , ok bool , err error ) {
2016-10-10 13:30:51 +08:00
res , ok , err := handshake ( c . rw ( ) , ih , cl . peerID , cl . extensionBytes )
2015-03-18 15:28:13 +08:00
if err != nil || ! ok {
2015-03-13 03:21:13 +08:00
return
}
2016-04-04 11:01:31 +08:00
ret = res . Hash
2015-03-18 15:28:13 +08:00
c . PeerExtensionBytes = res . peerExtensionBytes
c . PeerID = res . peerID
c . completedHandshake = time . Now ( )
return
}
2016-05-16 17:50:10 +08:00
func ( cl * Client ) runInitiatedHandshookConn ( c * connection , t * Torrent ) {
2015-03-18 15:28:13 +08:00
if c . PeerID == cl . peerID {
connsToSelf . Add ( 1 )
addr := c . conn . RemoteAddr ( ) . String ( )
cl . dopplegangerAddrs [ addr ] = struct { } { }
return
2014-08-28 07:45:20 +08:00
}
2017-05-10 11:04:31 +08:00
cl . runHandshookConn ( c , t , true )
2015-03-18 15:28:13 +08:00
}
2016-05-16 17:50:10 +08:00
func ( cl * Client ) runReceivedConn ( c * connection ) {
err := c . conn . SetDeadline ( time . Now ( ) . Add ( handshakesTimeout ) )
2014-08-21 16:12:49 +08:00
if err != nil {
2016-05-16 17:50:10 +08:00
panic ( err )
2014-08-21 16:12:49 +08:00
}
2015-03-18 15:28:13 +08:00
t , err := cl . receiveHandshakes ( c )
if err != nil {
2016-05-16 17:50:10 +08:00
if cl . config . Debug {
log . Printf ( "error receiving handshakes: %s" , err )
}
2014-08-21 16:12:49 +08:00
return
2013-09-29 14:45:17 +08:00
}
2015-03-18 15:28:13 +08:00
if t == nil {
2014-11-17 03:54:00 +08:00
return
}
2015-03-18 15:28:13 +08:00
cl . mu . Lock ( )
defer cl . mu . Unlock ( )
if c . PeerID == cl . peerID {
2016-05-24 00:09:47 +08:00
// Because the remote address is not necessarily the same as its
// client's torrent listen address, we won't record the remote address
// as a doppleganger. Instead, the initiator can record *us* as the
// doppleganger.
2014-08-21 16:12:49 +08:00
return
}
2017-05-10 11:04:31 +08:00
cl . runHandshookConn ( c , t , false )
2015-03-18 15:28:13 +08:00
}
2017-05-10 11:04:31 +08:00
func ( cl * Client ) runHandshookConn ( c * connection , t * Torrent , outgoing bool ) {
2015-03-18 15:28:13 +08:00
c . conn . SetWriteDeadline ( time . Time { } )
2016-10-10 13:30:51 +08:00
c . r = deadlineReader { c . conn , c . r }
2015-08-02 02:06:22 +08:00
completedHandshakeConnectionFlags . Add ( c . connectionFlags ( ) , 1 )
2017-05-10 11:04:31 +08:00
if ! t . addConnection ( c , outgoing ) {
2014-03-16 23:30:10 +08:00
return
}
2016-05-11 19:44:55 +08:00
defer t . dropConnection ( c )
2016-05-07 16:56:44 +08:00
go c . writer ( time . Minute )
2015-03-18 15:28:13 +08:00
cl . sendInitialMessages ( c , t )
2016-09-11 12:32:56 +08:00
err := c . mainReadLoop ( )
2016-05-16 17:50:10 +08:00
if err != nil && cl . config . Debug {
log . Printf ( "error during connection loop: %s" , err )
2015-03-18 15:28:13 +08:00
}
}
2016-04-19 12:11:11 +08:00
func ( cl * Client ) sendInitialMessages ( conn * connection , torrent * Torrent ) {
if conn . PeerExtensionBytes . SupportsExtended ( ) && cl . extensionBytes . SupportsExtended ( ) {
2014-06-26 22:57:07 +08:00
conn . Post ( pp . Message {
Type : pp . Extended ,
ExtendedID : pp . HandshakeExtendedID ,
ExtendedPayload : func ( ) [ ] byte {
2014-06-28 17:38:31 +08:00
d := map [ string ] interface { } {
2015-03-25 12:49:27 +08:00
"m" : func ( ) ( ret map [ string ] int ) {
ret = make ( map [ string ] int , 2 )
ret [ "ut_metadata" ] = metadataExtendedId
2016-04-19 12:11:11 +08:00
if ! cl . config . DisablePEX {
2015-03-25 12:49:27 +08:00
ret [ "ut_pex" ] = pexExtendedId
}
return
} ( ) ,
2015-03-25 12:42:14 +08:00
"v" : extendedHandshakeClientVersion ,
2014-08-25 20:12:50 +08:00
// No upload queue is implemented yet.
2015-05-15 06:39:53 +08:00
"reqq" : 64 ,
2015-04-20 15:30:22 +08:00
}
2016-04-19 12:11:11 +08:00
if ! cl . config . DisableEncryption {
2015-04-20 15:30:22 +08:00
d [ "e" ] = 1
2014-06-28 17:38:31 +08:00
}
if torrent . metadataSizeKnown ( ) {
d [ "metadata_size" ] = torrent . metadataSize ( )
}
2016-04-19 12:11:11 +08:00
if p := cl . incomingPeerPort ( ) ; p != 0 {
2014-06-29 16:57:49 +08:00
d [ "p" ] = p
}
2015-03-13 03:21:13 +08:00
yourip , err := addrCompactIP ( conn . remoteAddr ( ) )
2014-07-22 19:45:12 +08:00
if err != nil {
log . Printf ( "error calculating yourip field value in extension handshake: %s" , err )
} else {
d [ "yourip" ] = yourip
}
2014-07-24 11:43:45 +08:00
// log.Printf("sending %v", d)
2014-06-28 17:38:31 +08:00
b , err := bencode . Marshal ( d )
2014-06-26 22:57:07 +08:00
if err != nil {
panic ( err )
}
return b
} ( ) ,
} )
}
2013-10-20 22:07:01 +08:00
if torrent . haveAnyPieces ( ) {
2016-01-04 19:37:49 +08:00
conn . Bitfield ( torrent . bitfield ( ) )
2016-04-19 12:11:11 +08:00
} else if cl . extensionBytes . SupportsFast ( ) && conn . PeerExtensionBytes . SupportsFast ( ) {
2015-03-13 03:21:13 +08:00
conn . Post ( pp . Message {
Type : pp . HaveNone ,
} )
2013-10-20 22:07:01 +08:00
}
2016-04-19 12:11:11 +08:00
if conn . PeerExtensionBytes . SupportsDHT ( ) && cl . extensionBytes . SupportsDHT ( ) && cl . dHT != nil {
2014-08-25 20:12:16 +08:00
conn . Post ( pp . Message {
Type : pp . Port ,
2016-04-19 12:11:11 +08:00
Port : uint16 ( missinggo . AddrPort ( cl . dHT . Addr ( ) ) ) ,
2014-08-25 20:12:16 +08:00
} )
}
2013-09-30 19:51:08 +08:00
}
2014-08-21 16:12:49 +08:00
// Process incoming ut_metadata message.
2016-07-23 22:34:40 +08:00
func ( cl * Client ) gotMetadataExtensionMsg ( payload [ ] byte , t * Torrent , c * connection ) error {
2014-06-28 17:38:31 +08:00
var d map [ string ] int
2016-07-23 22:34:40 +08:00
err := bencode . Unmarshal ( payload , & d )
2014-06-28 17:38:31 +08:00
if err != nil {
2016-07-23 22:34:40 +08:00
return fmt . Errorf ( "error unmarshalling payload: %s: %q" , err , payload )
2014-06-28 17:38:31 +08:00
}
msgType , ok := d [ "msg_type" ]
if ! ok {
2016-07-23 22:34:40 +08:00
return errors . New ( "missing msg_type field" )
2014-06-28 17:38:31 +08:00
}
piece := d [ "piece" ]
switch msgType {
case pp . DataMetadataExtensionMsgType :
2016-05-03 12:59:54 +08:00
if ! c . requestedMetadataPiece ( piece ) {
2016-07-23 22:34:40 +08:00
return fmt . Errorf ( "got unexpected piece %d" , piece )
2014-06-28 17:38:31 +08:00
}
2016-05-03 12:59:54 +08:00
c . metadataRequests [ piece ] = false
2014-11-19 11:57:27 +08:00
begin := len ( payload ) - metadataPieceSize ( d [ "total_size" ] , piece )
if begin < 0 || begin >= len ( payload ) {
2016-07-23 22:34:40 +08:00
return fmt . Errorf ( "data has bad offset in payload: %d" , begin )
2015-03-27 12:36:59 +08:00
}
2015-03-20 07:52:01 +08:00
t . saveMetadataPiece ( piece , payload [ begin : ] )
2014-12-01 17:32:17 +08:00
c . UsefulChunksReceived ++
c . lastUsefulChunkReceived = time . Now ( )
2016-07-23 22:34:40 +08:00
return t . maybeCompleteMetadata ( )
2014-06-28 17:38:31 +08:00
case pp . RequestMetadataExtensionMsgType :
2015-02-25 12:42:47 +08:00
if ! t . haveMetadataPiece ( piece ) {
c . Post ( t . newMetadataExtensionMessage ( c , pp . RejectMetadataExtensionMsgType , d [ "piece" ] , nil ) )
2016-07-23 22:34:40 +08:00
return nil
2014-06-28 17:38:31 +08:00
}
2014-08-21 16:12:49 +08:00
start := ( 1 << 14 ) * piece
2016-04-03 14:50:53 +08:00
c . Post ( t . newMetadataExtensionMessage ( c , pp . DataMetadataExtensionMsgType , piece , t . metadataBytes [ start : start + t . metadataPieceSize ( piece ) ] ) )
2016-07-23 22:34:40 +08:00
return nil
2014-06-28 17:38:31 +08:00
case pp . RejectMetadataExtensionMsgType :
2016-07-23 22:34:40 +08:00
return nil
2014-06-28 17:38:31 +08:00
default :
2016-07-23 22:34:40 +08:00
return errors . New ( "unknown msg_type value" )
2014-06-28 17:38:31 +08:00
}
}
2017-09-18 10:09:08 +08:00
func ( cl * Client ) sendChunk ( t * Torrent , c * connection , r request , msg func ( pp . Message ) bool ) ( more bool , err error ) {
2015-09-17 10:50:29 +08:00
// Count the chunk being sent, even if it isn't.
2015-06-16 14:57:47 +08:00
b := make ( [ ] byte , r . Length )
2016-04-03 14:50:53 +08:00
p := t . info . Piece ( int ( r . Index ) )
2016-02-21 00:32:59 +08:00
n , err := t . readAt ( b , p . Offset ( ) + int64 ( r . Begin ) )
2015-06-16 14:57:47 +08:00
if n != len ( b ) {
2016-02-20 11:40:28 +08:00
if err == nil {
panic ( "expected error" )
}
2017-09-18 10:09:08 +08:00
return
2017-11-06 11:01:07 +08:00
} else if err == io . EOF {
err = nil
2015-06-16 14:57:47 +08:00
}
2017-09-18 10:09:08 +08:00
more = msg ( pp . Message {
2015-06-16 14:57:47 +08:00
Type : pp . Piece ,
Index : r . Index ,
Begin : r . Begin ,
Piece : b ,
} )
2016-02-21 14:22:55 +08:00
c . chunksSent ++
2015-06-16 14:57:47 +08:00
uploadChunksPosted . Add ( 1 )
c . lastChunkSent = time . Now ( )
2017-09-18 10:09:08 +08:00
return
2015-06-16 14:57:47 +08:00
}
2016-04-19 12:11:11 +08:00
func ( cl * Client ) openNewConns ( t * Torrent ) {
2016-05-22 20:45:08 +08:00
defer t . updateWantPeersEvent ( )
2016-04-03 14:50:53 +08:00
for len ( t . peers ) != 0 {
2016-07-05 14:23:17 +08:00
if ! t . wantConns ( ) {
2014-12-03 15:07:50 +08:00
return
2014-08-28 07:39:27 +08:00
}
2016-04-19 12:11:11 +08:00
if len ( t . halfOpen ) >= cl . halfOpenLimit {
2014-12-03 15:07:50 +08:00
return
2014-11-21 14:09:55 +08:00
}
var (
2016-01-06 09:19:49 +08:00
k peersKey
2014-11-21 14:09:55 +08:00
p Peer
)
2016-04-03 14:50:53 +08:00
for k , p = range t . peers {
2014-11-21 14:09:55 +08:00
break
2013-09-29 06:11:24 +08:00
}
2016-04-03 14:50:53 +08:00
delete ( t . peers , k )
2016-04-19 12:11:11 +08:00
cl . initiateConn ( p , t )
2013-09-29 06:11:24 +08:00
}
}
2016-05-24 00:09:47 +08:00
func ( cl * Client ) badPeerIPPort ( ip net . IP , port int ) bool {
if port == 0 {
return true
}
if cl . dopplegangerAddr ( net . JoinHostPort ( ip . String ( ) , strconv . FormatInt ( int64 ( port ) , 10 ) ) ) {
return true
}
if _ , ok := cl . ipBlockRange ( ip ) ; ok {
return true
}
if _ , ok := cl . badPeerIPs [ ip . String ( ) ] ; ok {
return true
}
return false
2013-09-29 06:11:24 +08:00
}
2016-07-05 14:23:17 +08:00
// Return a Torrent ready for insertion into a Client.
2017-03-16 22:24:54 +08:00
func ( cl * Client ) newTorrent ( ih metainfo . Hash , specStorage storage . ClientImpl ) ( t * Torrent ) {
// use provided storage, if provided
storageClient := cl . defaultStorage
if specStorage != nil {
storageClient = storage . NewClient ( specStorage )
}
2016-04-03 16:40:43 +08:00
t = & Torrent {
2016-10-05 12:57:00 +08:00
cl : cl ,
infoHash : ih ,
peers : make ( map [ peersKey ] Peer ) ,
2016-11-23 08:48:44 +08:00
conns : make ( map [ * connection ] struct { } , 2 * defaultEstablishedConnsPerTorrent ) ,
2014-08-25 04:01:05 +08:00
2017-09-15 17:10:09 +08:00
halfOpen : make ( map [ string ] Peer ) ,
2015-09-06 10:33:22 +08:00
pieceStateChanges : pubsub . NewPubSub ( ) ,
2016-05-09 12:37:29 +08:00
2017-03-16 22:24:54 +08:00
storageOpener : storageClient ,
2016-07-05 14:23:17 +08:00
maxEstablishedConns : defaultEstablishedConnsPerTorrent ,
2017-08-17 23:51:02 +08:00
networkingEnabled : true ,
2017-09-23 13:25:47 +08:00
requestStrategy : 2 ,
2014-06-26 22:57:07 +08:00
}
2016-10-05 12:57:00 +08:00
t . setChunkSize ( defaultChunkSize )
2014-11-21 14:09:55 +08:00
return
}
2015-03-07 14:11:02 +08:00
// A file-like handle to some torrent data resource.
2015-03-01 11:32:54 +08:00
type Handle interface {
io . Reader
io . Seeker
io . Closer
2015-03-04 10:06:33 +08:00
io . ReaderAt
2015-03-01 11:32:54 +08:00
}
2016-05-09 12:37:29 +08:00
func ( cl * Client ) AddTorrentInfoHash ( infoHash metainfo . Hash ) ( t * Torrent , new bool ) {
2017-03-16 22:24:54 +08:00
return cl . AddTorrentInfoHashWithStorage ( infoHash , nil )
}
// Adds a torrent by InfoHash with a custom Storage implementation.
// If the torrent already exists then this Storage is ignored and the
// existing torrent returned with `new` set to `false`
func ( cl * Client ) AddTorrentInfoHashWithStorage ( infoHash metainfo . Hash , specStorage storage . ClientImpl ) ( t * Torrent , new bool ) {
2016-05-09 12:37:29 +08:00
cl . mu . Lock ( )
defer cl . mu . Unlock ( )
t , ok := cl . torrents [ infoHash ]
if ok {
return
}
new = true
2017-03-16 22:24:54 +08:00
t = cl . newTorrent ( infoHash , specStorage )
2016-05-09 13:47:39 +08:00
if cl . dHT != nil {
2016-07-23 20:38:31 +08:00
go t . dhtAnnouncer ( )
2016-05-09 13:47:39 +08:00
}
cl . torrents [ infoHash ] = t
2016-05-23 08:19:14 +08:00
t . updateWantPeersEvent ( )
2016-07-07 12:49:18 +08:00
// Tickle Client.waitAccept, new torrent may want conns.
cl . event . Broadcast ( )
2016-05-09 12:37:29 +08:00
return
}
2015-03-27 23:50:55 +08:00
// Add or merge a torrent spec. If the torrent is already present, the
// trackers will be merged with the existing ones. If the Info isn't yet
// known, it will be set. The display name is replaced if the new spec
// provides one. Returns new if the torrent wasn't already in the client.
2017-03-16 22:24:54 +08:00
// Note that any `Storage` defined on the spec will be ignored if the
// torrent is already present (i.e. `new` return value is `true`)
2016-04-03 16:40:43 +08:00
func ( cl * Client ) AddTorrentSpec ( spec * TorrentSpec ) ( t * Torrent , new bool , err error ) {
2017-03-16 22:24:54 +08:00
t , new = cl . AddTorrentInfoHashWithStorage ( spec . InfoHash , spec . Storage )
2015-03-18 15:32:31 +08:00
if spec . DisplayName != "" {
2016-05-09 13:47:39 +08:00
t . SetDisplayName ( spec . DisplayName )
2015-03-18 15:32:31 +08:00
}
2016-08-26 18:29:05 +08:00
if spec . InfoBytes != nil {
err = t . SetInfoBytes ( spec . InfoBytes )
2016-05-09 13:47:39 +08:00
if err != nil {
return
}
2013-10-20 22:07:01 +08:00
}
2016-05-09 13:47:39 +08:00
cl . mu . Lock ( )
defer cl . mu . Unlock ( )
2016-05-09 21:00:20 +08:00
if spec . ChunkSize != 0 {
2016-10-05 12:57:00 +08:00
t . setChunkSize ( pp . Integer ( spec . ChunkSize ) )
2016-05-09 21:00:20 +08:00
}
2015-03-27 23:50:55 +08:00
t . addTrackers ( spec . Trackers )
2016-04-03 20:06:25 +08:00
t . maybeNewConns ( )
2014-06-26 22:57:07 +08:00
return
}
2014-05-21 15:37:31 +08:00
2016-04-19 12:11:11 +08:00
func ( cl * Client ) dropTorrent ( infoHash metainfo . Hash ) ( err error ) {
t , ok := cl . torrents [ infoHash ]
2014-07-22 23:54:11 +08:00
if ! ok {
err = fmt . Errorf ( "no such torrent" )
return
}
2015-02-09 21:12:29 +08:00
err = t . close ( )
2014-07-22 23:54:11 +08:00
if err != nil {
panic ( err )
}
2016-04-19 12:11:11 +08:00
delete ( cl . torrents , infoHash )
2014-07-22 23:54:11 +08:00
return
}
2016-05-22 20:45:08 +08:00
func ( cl * Client ) prepareTrackerAnnounceUnlocked ( announceURL string ) ( blocked bool , urlToUse string , host string , err error ) {
_url , err := url . Parse ( announceURL )
2015-03-10 23:41:41 +08:00
if err != nil {
return
}
2016-05-22 20:45:08 +08:00
hmp := missinggo . SplitHostMaybePort ( _url . Host )
if hmp . Err != nil {
err = hmp . Err
return
2015-03-10 23:41:41 +08:00
}
2016-05-22 20:45:08 +08:00
addr , err := net . ResolveIPAddr ( "ip" , hmp . Host )
2015-03-10 23:41:41 +08:00
if err != nil {
return
}
2015-10-18 21:00:26 +08:00
cl . mu . RLock ( )
_ , blocked = cl . ipBlockRange ( addr . IP )
cl . mu . RUnlock ( )
2016-05-22 20:45:08 +08:00
host = _url . Host
hmp . Host = addr . String ( )
_url . Host = hmp . String ( )
urlToUse = _url . String ( )
2015-03-10 23:41:41 +08:00
return
}
2014-03-16 23:30:10 +08:00
func ( cl * Client ) allTorrentsCompleted ( ) bool {
for _ , t := range cl . torrents {
2014-09-15 01:25:53 +08:00
if ! t . haveInfo ( ) {
return false
}
2015-02-25 12:42:47 +08:00
if t . numPiecesCompleted ( ) != t . numPieces ( ) {
2014-03-16 23:30:10 +08:00
return false
}
}
return true
}
2014-04-09 00:36:05 +08:00
// Returns true when all torrents are completely downloaded and false if the
2014-06-29 22:22:05 +08:00
// client is stopped before that.
2016-04-19 12:11:11 +08:00
func ( cl * Client ) WaitAll ( ) bool {
cl . mu . Lock ( )
defer cl . mu . Unlock ( )
for ! cl . allTorrentsCompleted ( ) {
if cl . closed . IsSet ( ) {
2014-04-09 00:36:05 +08:00
return false
}
2016-04-19 12:11:11 +08:00
cl . event . Wait ( )
2013-10-20 22:07:01 +08:00
}
2014-04-09 00:36:05 +08:00
return true
2013-09-26 17:49:15 +08:00
}
2015-03-08 14:28:14 +08:00
// Returns handles to all the torrents loaded in the Client.
2016-11-27 11:26:45 +08:00
func ( cl * Client ) Torrents ( ) [ ] * Torrent {
2016-04-19 12:11:11 +08:00
cl . mu . Lock ( )
2016-11-27 11:26:45 +08:00
defer cl . mu . Unlock ( )
return cl . torrentsAsSlice ( )
}
func ( cl * Client ) torrentsAsSlice ( ) ( ret [ ] * Torrent ) {
2016-04-19 12:11:11 +08:00
for _ , t := range cl . torrents {
2016-04-03 16:40:43 +08:00
ret = append ( ret , t )
2013-10-20 22:07:01 +08:00
}
2013-10-06 15:01:39 +08:00
return
}
2015-03-18 15:32:31 +08:00
2016-04-19 12:11:11 +08:00
func ( cl * Client ) AddMagnet ( uri string ) ( T * Torrent , err error ) {
2015-03-18 15:32:31 +08:00
spec , err := TorrentSpecFromMagnetURI ( uri )
if err != nil {
return
}
2016-04-19 12:11:11 +08:00
T , _ , err = cl . AddTorrentSpec ( spec )
2015-03-18 15:32:31 +08:00
return
}
2016-04-19 12:11:11 +08:00
func ( cl * Client ) AddTorrent ( mi * metainfo . MetaInfo ) ( T * Torrent , err error ) {
T , _ , err = cl . AddTorrentSpec ( TorrentSpecFromMetaInfo ( mi ) )
2016-02-24 18:56:50 +08:00
var ss [ ] string
2016-07-12 14:40:14 +08:00
slices . MakeInto ( & ss , mi . Nodes )
2016-04-19 12:11:11 +08:00
cl . AddDHTNodes ( ss )
2015-03-18 15:32:31 +08:00
return
}
2016-04-19 12:11:11 +08:00
func ( cl * Client ) AddTorrentFromFile ( filename string ) ( T * Torrent , err error ) {
2015-03-18 15:32:31 +08:00
mi , err := metainfo . LoadFromFile ( filename )
if err != nil {
return
}
2016-04-19 12:11:11 +08:00
return cl . AddTorrent ( mi )
2015-03-18 15:32:31 +08:00
}
2015-08-03 23:07:22 +08:00
2016-04-19 12:11:11 +08:00
func ( cl * Client ) DHT ( ) * dht . Server {
return cl . dHT
2015-08-03 23:07:22 +08:00
}
2016-02-24 18:56:50 +08:00
2016-04-19 12:11:11 +08:00
func ( cl * Client ) AddDHTNodes ( nodes [ ] string ) {
2017-06-29 09:49:55 +08:00
if cl . DHT ( ) == nil {
return
}
2016-02-24 18:56:50 +08:00
for _ , n := range nodes {
2016-03-15 18:32:47 +08:00
hmp := missinggo . SplitHostMaybePort ( n )
2016-02-24 18:56:50 +08:00
ip := net . ParseIP ( hmp . Host )
if ip == nil {
log . Printf ( "won't add DHT node with bad IP: %q" , hmp . Host )
continue
}
2016-05-17 14:40:08 +08:00
ni := krpc . NodeInfo {
Addr : & net . UDPAddr {
2016-02-24 18:56:50 +08:00
IP : ip ,
Port : hmp . Port ,
2016-05-17 14:40:08 +08:00
} ,
2016-02-24 18:56:50 +08:00
}
2016-04-19 12:11:11 +08:00
cl . DHT ( ) . AddNode ( ni )
2016-02-24 18:56:50 +08:00
}
}
2016-05-24 00:09:47 +08:00
func ( cl * Client ) banPeerIP ( ip net . IP ) {
if cl . badPeerIPs == nil {
cl . badPeerIPs = make ( map [ string ] struct { } )
}
cl . badPeerIPs [ ip . String ( ) ] = struct { } { }
}
2016-10-10 13:55:56 +08:00
func ( cl * Client ) newConnection ( nc net . Conn ) ( c * connection ) {
c = & connection {
conn : nc ,
Choked : true ,
PeerChoked : true ,
PeerMaxRequests : 250 ,
}
2017-08-31 14:26:45 +08:00
c . writerCond . L = & cl . mu
2016-10-10 13:55:56 +08:00
c . setRW ( connStatsReadWriter { nc , & cl . mu , c } )
2016-10-10 14:29:39 +08:00
c . r = rateLimitedReader { cl . downloadLimit , c . r }
2016-10-10 13:55:56 +08:00
return
}
2016-11-26 21:05:19 +08:00
func ( cl * Client ) onDHTAnnouncePeer ( ih metainfo . Hash , p dht . Peer ) {
cl . mu . Lock ( )
defer cl . mu . Unlock ( )
2016-11-27 11:43:21 +08:00
t := cl . torrent ( ih )
if t == nil {
2016-11-26 21:05:19 +08:00
return
}
t . addPeers ( [ ] Peer { {
IP : p . IP ,
Port : p . Port ,
Source : peerSourceDHTAnnouncePeer ,
} } )
}