2013-09-26 09:49:15 +00:00
package torrent
import (
2013-09-30 11:51:08 +00:00
"bufio"
2018-02-03 04:09:38 +00:00
"bytes"
2017-08-16 05:35:17 +00:00
"context"
2013-09-28 22:11:24 +00:00
"crypto/rand"
2018-02-19 05:19:18 +00:00
"encoding/binary"
2013-09-26 09:49:15 +00:00
"errors"
2013-10-07 07:58:33 +00:00
"fmt"
2013-09-26 09:49:15 +00:00
"io"
2013-09-28 22:11:24 +00:00
"net"
2015-03-18 07:21:00 +00:00
"strconv"
2014-09-13 17:50:15 +00:00
"strings"
2013-10-20 14:07:01 +00:00
"time"
2014-03-20 05:58:09 +00:00
2018-06-15 12:42:05 +00:00
"github.com/anacrolix/missinggo/perf"
2017-01-01 00:01:41 +00:00
"github.com/anacrolix/dht"
"github.com/anacrolix/dht/krpc"
2018-01-31 05:42:40 +00:00
"github.com/anacrolix/log"
2015-08-05 22:56:36 +00:00
"github.com/anacrolix/missinggo"
2016-03-06 06:26:04 +00:00
"github.com/anacrolix/missinggo/pproffd"
2015-09-06 02:35:56 +00:00
"github.com/anacrolix/missinggo/pubsub"
2016-07-12 06:40:14 +00:00
"github.com/anacrolix/missinggo/slices"
2015-03-20 12:52:53 +00:00
"github.com/anacrolix/sync"
2018-06-09 23:18:52 +00:00
"github.com/davecgh/go-spew/spew"
2016-05-19 07:15:10 +00:00
"github.com/dustin/go-humanize"
2018-04-04 07:59:28 +00:00
"github.com/google/btree"
2015-03-26 06:18:08 +00:00
2015-04-28 05:24:17 +00:00
"github.com/anacrolix/torrent/bencode"
2015-03-20 05:37:44 +00:00
"github.com/anacrolix/torrent/iplist"
2015-04-28 05:24:17 +00:00
"github.com/anacrolix/torrent/metainfo"
2015-03-26 06:18:08 +00:00
"github.com/anacrolix/torrent/mse"
2015-03-20 05:37:44 +00:00
pp "github.com/anacrolix/torrent/peer_protocol"
2016-03-28 09:38:30 +00:00
"github.com/anacrolix/torrent/storage"
2013-09-26 09:49:15 +00:00
)
2016-05-03 04:58:26 +00:00
// Clients contain zero or more Torrents. A Client manages a blocklist, the
2015-06-03 03:30:55 +00:00
// TCP/UDP protocol ports, and DHT as desired.
2013-10-06 07:01:39 +00:00
type Client struct {
2016-10-09 13:04:14 +00:00
mu sync . RWMutex
event sync . Cond
closed missinggo . Event
2018-06-16 06:30:04 +00:00
config * ClientConfig
2018-01-29 07:19:53 +00:00
logger * log . Logger
2016-10-09 13:04:14 +00:00
halfOpenLimit int
2018-01-06 04:50:45 +00:00
peerID PeerID
2016-10-09 13:04:14 +00:00
defaultStorage * storage . Client
2017-06-01 12:57:08 +00:00
onClose [ ] func ( )
2018-04-12 01:41:07 +00:00
conns [ ] socket
dhtServers [ ] * dht . Server
2015-09-23 08:25:22 +00:00
ipBlockList iplist . Ranger
2016-10-09 13:04:14 +00:00
// Our BitTorrent protocol extension bytes, sent in our BT handshakes.
2015-04-27 04:05:27 +00:00
extensionBytes peerExtensionBytes
2016-10-09 13:04:14 +00:00
2015-03-18 07:29:51 +00: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-23 16:09:47 +00:00
badPeerIPs map [ string ] struct { }
2016-10-09 13:04:14 +00:00
torrents map [ metainfo . Hash ] * Torrent
2018-06-09 23:18:52 +00:00
// An aggregate of stats over all connections.
stats ConnStats
2018-06-15 12:38:11 +00:00
acceptLimiter map [ ipStr ] int
2015-02-25 00:25:22 +00:00
}
2014-08-24 19:24:18 +00:00
2018-06-15 12:38:11 +00:00
type ipStr string
2016-07-29 14:37:52 +00:00
func ( cl * Client ) BadPeerIPs ( ) [ ] string {
cl . mu . RLock ( )
defer cl . mu . RUnlock ( )
2016-11-27 03:26:45 +00:00
return cl . badPeerIPsLocked ( )
}
func ( cl * Client ) badPeerIPsLocked ( ) [ ] string {
2016-07-29 14:37:52 +00:00
return slices . FromMapKeys ( cl . badPeerIPs ) . ( [ ] string )
}
2018-01-06 04:50:45 +00:00
func ( cl * Client ) PeerID ( ) PeerID {
2017-11-08 08:28:37 +00:00
return cl . peerID
2014-11-16 19:54:43 +00:00
}
2016-05-11 11:11:52 +00:00
type torrentAddr string
2017-01-01 00:03:02 +00:00
func ( torrentAddr ) Network ( ) string { return "" }
2016-05-11 11:11:52 +00:00
func ( me torrentAddr ) String ( ) string { return string ( me ) }
2018-04-12 01:41:07 +00:00
func ( cl * Client ) LocalPort ( ) ( port int ) {
cl . eachListener ( func ( l socket ) bool {
_port := missinggo . AddrPort ( l . Addr ( ) )
if _port == 0 {
panic ( l )
}
if port == 0 {
port = _port
} else if port != _port {
panic ( "mismatched ports" )
}
return true
} )
return
}
func writeDhtServerStatus ( w io . Writer , s * dht . Server ) {
dhtStats := s . Stats ( )
2018-04-12 05:12:15 +00:00
fmt . Fprintf ( w , "\t# Nodes: %d (%d good, %d banned)\n" , dhtStats . Nodes , dhtStats . GoodNodes , dhtStats . BadNodes )
fmt . Fprintf ( w , "\tServer ID: %x\n" , s . ID ( ) )
2018-04-12 07:28:13 +00:00
fmt . Fprintf ( w , "\tAnnounces: %d\n" , dhtStats . SuccessfulOutboundAnnouncePeerQueries )
2018-04-12 01:41:07 +00:00
fmt . Fprintf ( w , "\tOutstanding transactions: %d\n" , dhtStats . OutstandingTransactions )
2014-08-21 08:07:06 +00:00
}
2015-03-08 06:28:14 +00:00
// Writes out a human readable status of the client, such as for writing to a
// HTTP status page.
2014-11-19 03:56:50 +00:00
func ( cl * Client ) WriteStatus ( _w io . Writer ) {
2018-06-17 06:11:50 +00:00
cl . mu . RLock ( )
defer cl . mu . RUnlock ( )
2014-11-19 03:56:50 +00:00
w := bufio . NewWriter ( _w )
defer w . Flush ( )
2018-04-12 01:41:07 +00:00
fmt . Fprintf ( w , "Listen port: %d\n" , cl . LocalPort ( ) )
2016-07-29 14:37:52 +00:00
fmt . Fprintf ( w , "Peer ID: %+q\n" , cl . PeerID ( ) )
2018-02-19 05:19:18 +00:00
fmt . Fprintf ( w , "Announce key: %x\n" , cl . announceKey ( ) )
2016-11-27 03:26:45 +00:00
fmt . Fprintf ( w , "Banned IPs: %d\n" , len ( cl . badPeerIPsLocked ( ) ) )
2018-04-12 01:41:07 +00:00
cl . eachDhtServer ( func ( s * dht . Server ) {
2018-04-12 05:12:15 +00:00
fmt . Fprintf ( w , "%s DHT server at %s:\n" , s . Addr ( ) . Network ( ) , s . Addr ( ) . String ( ) )
2018-04-12 01:41:07 +00:00
writeDhtServerStatus ( w , s )
} )
2018-06-09 23:18:52 +00:00
spew . Fdump ( w , cl . stats )
2016-11-27 03:26:45 +00:00
fmt . Fprintf ( w , "# Torrents: %d\n" , len ( cl . torrentsAsSlice ( ) ) )
2014-07-16 07:07:28 +00:00
fmt . Fprintln ( w )
2016-11-27 03:26:45 +00:00
for _ , t := range slices . Sort ( cl . torrentsAsSlice ( ) , func ( l , r * Torrent ) bool {
2016-07-29 14:37:52 +00:00
return l . InfoHash ( ) . AsString ( ) < r . InfoHash ( ) . AsString ( )
} ) . ( [ ] * Torrent ) {
2016-11-27 03:26:45 +00:00
if t . name ( ) == "" {
2014-11-18 20:32:51 +00:00
fmt . Fprint ( w , "<unknown name>" )
} else {
2016-11-27 03:26:45 +00:00
fmt . Fprint ( w , t . name ( ) )
2014-11-18 20:32:51 +00:00
}
2015-02-21 03:57:37 +00:00
fmt . Fprint ( w , "\n" )
2017-08-29 05:16:53 +00: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 03:57:37 +00:00
} else {
w . WriteString ( "<missing metainfo>" )
2014-11-18 20:32:51 +00:00
}
fmt . Fprint ( w , "\n" )
2016-07-12 11:23:20 +00:00
t . writeStatus ( w )
2014-07-17 05:58:33 +00:00
fmt . Fprintln ( w )
2014-06-26 07:29:12 +00:00
}
}
2018-01-29 07:19:53 +00:00
const debugLogValue = "debug"
func ( cl * Client ) debugLogFilter ( m * log . Msg ) bool {
if ! cl . config . Debug {
_ , ok := m . Values ( ) [ debugLogValue ]
return ! ok
}
return true
}
func ( cl * Client ) initLogger ( ) {
cl . logger = log . Default . Clone ( ) . AddValue ( cl ) . AddFilter ( log . NewFilter ( cl . debugLogFilter ) )
}
2018-02-19 05:19:18 +00:00
func ( cl * Client ) announceKey ( ) int32 {
return int32 ( binary . BigEndian . Uint32 ( cl . peerID [ 16 : 20 ] ) )
}
2018-06-16 06:30:04 +00:00
func NewClient ( cfg * ClientConfig ) ( cl * Client , err error ) {
2017-11-07 18:14:13 +00:00
if cfg == nil {
2018-06-16 06:30:04 +00:00
cfg = NewDefaultClientConfig ( )
2017-11-07 18:14:13 +00:00
}
2015-04-01 03:30:22 +00:00
defer func ( ) {
if err != nil {
cl = nil
}
} ( )
2014-08-21 08:07:06 +00:00
cl = & Client {
2017-11-07 18:14:13 +00:00
halfOpenLimit : cfg . HalfOpenConnsPerTorrent ,
2018-06-16 06:30:04 +00:00
config : cfg ,
2015-03-18 07:29:51 +00:00
dopplegangerAddrs : make ( map [ string ] struct { } ) ,
2016-04-04 03:01:31 +00:00
torrents : make ( map [ metainfo . Hash ] * Torrent ) ,
2014-08-21 08:07:06 +00:00
}
2018-06-15 12:38:11 +00:00
go cl . acceptLimitClearer ( )
2018-01-29 07:19:53 +00:00
cl . initLogger ( )
2017-06-01 12:57:08 +00:00
defer func ( ) {
if err == nil {
return
}
cl . Close ( )
} ( )
2018-02-03 02:36:17 +00:00
cl . extensionBytes = defaultPeerExtensionBytes ( )
2014-08-21 08:07:06 +00:00
cl . event . L = & cl . mu
2016-09-02 05:10:57 +00:00
storageImpl := cfg . DefaultStorage
if storageImpl == nil {
2017-09-16 14:45:12 +00:00
// We'd use mmap but HFS+ doesn't support sparse files.
2016-09-02 05:10:57 +00:00
storageImpl = storage . NewFile ( cfg . DataDir )
2017-06-01 12:57:08 +00:00
cl . onClose = append ( cl . onClose , func ( ) {
if err := storageImpl . Close ( ) ; err != nil {
log . Printf ( "error closing default storage: %s" , err )
}
} )
2015-02-25 04:41:13 +00:00
}
2016-09-02 05:10:57 +00:00
cl . defaultStorage = storage . NewClient ( storageImpl )
2015-08-03 15:07:22 +00:00
if cfg . IPBlocklist != nil {
cl . ipBlockList = cfg . IPBlocklist
2014-12-01 22:39:09 +00:00
}
2014-11-16 19:54:43 +00:00
if cfg . PeerID != "" {
2016-03-30 08:11:55 +00:00
missinggo . CopyExact ( & cl . peerID , cfg . PeerID )
2014-11-16 19:54:43 +00:00
} else {
2017-11-07 18:14:13 +00:00
o := copy ( cl . peerID [ : ] , cfg . Bep20 )
2014-11-16 19:54:43 +00:00
_ , err = rand . Read ( cl . peerID [ o : ] )
if err != nil {
panic ( "error generating peer id" )
}
2013-09-28 22:11:24 +00:00
}
2014-08-21 08:07:06 +00:00
2018-06-08 10:52:36 +00:00
cl . conns , err = listenAll ( cl . enabledPeerNetworks ( ) , cl . config . ListenHost , cl . config . ListenPort , cl . config . ProxyURL )
2016-05-11 11:11:52 +00:00
if err != nil {
return
2014-11-16 19:29:31 +00:00
}
2018-04-12 06:12:27 +00:00
// Check for panics.
2018-04-12 01:41:07 +00:00
cl . LocalPort ( )
for _ , s := range cl . conns {
if peerNetworkEnabled ( s . Addr ( ) . Network ( ) , cl . config ) {
go cl . acceptConnections ( s )
}
2014-03-17 14:44:22 +00:00
}
2018-04-12 01:41:07 +00:00
go cl . forwardPort ( )
2014-08-21 08:07:06 +00:00
if ! cfg . NoDHT {
2018-04-12 01:41:07 +00:00
for _ , s := range cl . conns {
if pc , ok := s . ( net . PacketConn ) ; ok {
ds , err := cl . newDhtServer ( pc )
2017-07-20 14:40:49 +00:00
if err != nil {
2018-04-12 01:41:07 +00:00
panic ( err )
2017-07-20 14:40:49 +00:00
}
2018-04-12 01:41:07 +00:00
cl . dhtServers = append ( cl . dhtServers , ds )
2017-07-20 14:40:49 +00:00
}
2014-11-28 18:13:08 +00:00
}
2018-04-12 01:41:07 +00:00
}
return
}
func ( cl * Client ) enabledPeerNetworks ( ) ( ns [ ] string ) {
for _ , n := range allPeerNetworks {
if peerNetworkEnabled ( n , cl . config ) {
ns = append ( ns , n )
2014-08-21 08:07:06 +00:00
}
2018-04-12 01:41:07 +00:00
}
return
}
func ( cl * Client ) newDhtServer ( conn net . PacketConn ) ( s * dht . Server , err error ) {
cfg := dht . ServerConfig {
IPBlocklist : cl . ipBlockList ,
Conn : conn ,
OnAnnouncePeer : cl . onDHTAnnouncePeer ,
PublicIP : func ( ) net . IP {
if connIsIpv6 ( conn ) && cl . config . PublicIp6 != nil {
return cl . config . PublicIp6
}
return cl . config . PublicIp4
} ( ) ,
StartingNodes : cl . config . DhtStartingNodes ,
}
s , err = dht . NewServer ( & cfg )
if err == nil {
2017-08-10 01:18:48 +00:00
go func ( ) {
2018-04-12 01:41:07 +00:00
if _ , err := s . Bootstrap ( ) ; err != nil {
2017-08-10 01:18:48 +00:00
log . Printf ( "error bootstrapping dht: %s" , err )
}
} ( )
2014-08-21 08:07:06 +00:00
}
return
2014-03-17 14:44:22 +00:00
}
2016-05-24 09:46:24 +00:00
func firstNonEmptyString ( ss ... string ) string {
for _ , s := range ss {
if s != "" {
return s
}
}
return ""
}
2018-02-08 12:57:53 +00:00
func ( cl * Client ) Closed ( ) <- chan struct { } {
cl . mu . Lock ( )
defer cl . mu . Unlock ( )
return cl . closed . C ( )
}
2018-04-12 01:41:07 +00:00
func ( cl * Client ) eachDhtServer ( f func ( * dht . Server ) ) {
for _ , ds := range cl . dhtServers {
f ( ds )
}
}
func ( cl * Client ) closeSockets ( ) {
cl . eachListener ( func ( l socket ) bool {
l . Close ( )
return true
} )
cl . conns = nil
}
2014-04-08 16:36:05 +00:00
// Stops the client. All connections to peers are closed and all activity will
// come to a halt.
2016-04-19 04:11:11 +00:00
func ( cl * Client ) Close ( ) {
cl . mu . Lock ( )
defer cl . mu . Unlock ( )
cl . closed . Set ( )
2018-04-12 01:41:07 +00:00
cl . eachDhtServer ( func ( s * dht . Server ) { s . Close ( ) } )
cl . closeSockets ( )
2016-04-19 04:11:11 +00:00
for _ , t := range cl . torrents {
2015-02-09 13:12:29 +00:00
t . close ( )
2014-03-18 11:39:33 +00:00
}
2017-06-01 12:57:08 +00:00
for _ , f := range cl . onClose {
f ( )
}
2016-04-19 04:11:11 +00:00
cl . event . Broadcast ( )
2014-03-18 11:39:33 +00:00
}
2015-10-18 13:00:26 +00:00
func ( cl * Client ) ipBlockRange ( ip net . IP ) ( r iplist . Range , blocked bool ) {
2014-11-29 01:41:53 +00:00
if cl . ipBlockList == nil {
2014-11-30 02:33:17 +00:00
return
2014-11-29 01:41:53 +00:00
}
2018-02-11 04:11:26 +00:00
return cl . ipBlockList . Lookup ( ip )
2014-11-29 01:41:53 +00:00
}
2018-02-19 05:19:18 +00:00
func ( cl * Client ) ipIsBlocked ( ip net . IP ) bool {
_ , blocked := cl . ipBlockRange ( ip )
return blocked
}
2015-03-18 07:36:27 +00:00
func ( cl * Client ) waitAccept ( ) {
for {
for _ , t := range cl . torrents {
2016-07-05 06:23:17 +00:00
if t . wantConns ( ) {
2015-03-18 07:36:27 +00:00
return
}
}
2016-03-05 08:36:21 +00:00
if cl . closed . IsSet ( ) {
2015-08-03 15:15:09 +00:00
return
}
2015-03-18 07:36:27 +00:00
cl . event . Wait ( )
}
}
2018-02-15 23:46:11 +00:00
func ( cl * Client ) rejectAccepted ( conn net . Conn ) bool {
ra := conn . RemoteAddr ( )
rip := missinggo . AddrIP ( ra )
if cl . config . DisableIPv4Peers && rip . To4 ( ) != nil {
return true
}
if cl . config . DisableIPv4 && len ( rip ) == net . IPv4len {
return true
}
if cl . config . DisableIPv6 && len ( rip ) == net . IPv6len && rip . To4 ( ) == nil {
return true
}
2018-06-15 12:38:11 +00:00
if cl . rateLimitAccept ( rip ) {
return true
}
2018-02-15 23:46:11 +00:00
return cl . badPeerIPPort ( rip , missinggo . AddrPort ( ra ) )
}
2018-04-12 01:41:07 +00:00
func ( cl * Client ) acceptConnections ( l net . Listener ) {
2014-03-17 14:44:22 +00:00
for {
2014-11-16 19:29:31 +00:00
conn , err := l . Accept ( )
2016-03-06 06:26:04 +00:00
conn = pproffd . WrapNetConn ( conn )
2018-06-10 00:29:19 +00:00
cl . mu . RLock ( )
closed := cl . closed . IsSet ( )
reject := false
if conn != nil {
reject = cl . rejectAccepted ( conn )
}
cl . mu . RUnlock ( )
if closed {
2014-07-03 15:44:15 +00:00
if conn != nil {
conn . Close ( )
}
2014-03-18 11:39:33 +00:00
return
}
2014-03-17 14:44:22 +00:00
if err != nil {
log . Print ( err )
2016-03-05 08:36:21 +00:00
// I think something harsher should happen here? Our accept
// routine just fucked off.
2014-03-17 14:44:22 +00:00
return
}
2018-06-10 00:29:19 +00:00
go func ( ) {
if reject {
torrent . Add ( "rejected accepted connections" , 1 )
conn . Close ( )
} else {
go cl . incomingConnection ( conn )
}
log . Fmsg ( "accepted %s connection from %s" , conn . RemoteAddr ( ) . Network ( ) , conn . RemoteAddr ( ) ) . AddValue ( debugLogValue ) . Log ( cl . logger )
torrent . Add ( fmt . Sprintf ( "accepted conn remote IP len=%d" , len ( missinggo . AddrIP ( conn . RemoteAddr ( ) ) ) ) , 1 )
torrent . Add ( fmt . Sprintf ( "accepted conn network=%s" , conn . RemoteAddr ( ) . Network ( ) ) , 1 )
torrent . Add ( fmt . Sprintf ( "accepted on %s listener" , l . Addr ( ) . Network ( ) ) , 1 )
} ( )
2015-03-18 07:28:13 +00:00
}
}
2018-04-12 01:41:07 +00:00
func ( cl * Client ) incomingConnection ( nc net . Conn ) {
2015-03-18 07:28:13 +00:00
defer nc . Close ( )
if tc , ok := nc . ( * net . TCPConn ) ; ok {
tc . SetLinger ( 0 )
}
2018-06-12 10:14:00 +00:00
c := cl . newConnection ( nc , false )
2015-03-18 07:28:13 +00:00
c . Discovery = peerSourceIncoming
2016-05-16 09:50:10 +00:00
cl . runReceivedConn ( c )
2013-09-26 09:49:15 +00:00
}
2015-03-19 23:52:01 +00:00
// Returns a handle to the given torrent, if it's present in the client.
2016-04-04 03:01:31 +00:00
func ( cl * Client ) Torrent ( ih metainfo . Hash ) ( t * Torrent , ok bool ) {
2015-03-18 07:28:13 +00:00
cl . mu . Lock ( )
defer cl . mu . Unlock ( )
2016-04-03 08:40:43 +00:00
t , ok = cl . torrents [ ih ]
2015-03-18 07:28:13 +00:00
return
}
2016-04-19 04:11:11 +00:00
func ( cl * Client ) torrent ( ih metainfo . Hash ) * Torrent {
return cl . torrents [ ih ]
2013-09-28 22:11:24 +00:00
}
2014-11-17 05:27:01 +00:00
type dialResult struct {
2015-03-18 07:28:13 +00:00
Conn net . Conn
2014-11-17 05:27:01 +00:00
}
2017-08-16 07:05:05 +00:00
func countDialResult ( err error ) {
2014-11-17 07:44:06 +00:00
if err == nil {
2018-06-15 04:30:31 +00:00
torrent . Add ( "successful dials" , 1 )
2017-08-16 07:05:05 +00:00
} else {
2018-06-15 04:30:31 +00:00
torrent . Add ( "unsuccessful dials" , 1 )
2014-11-17 07:44:06 +00:00
}
2014-11-17 05:27:01 +00:00
}
2017-11-07 18:14:13 +00:00
func reducedDialTimeout ( minDialTimeout , max time . Duration , halfOpenLimit int , pendingPeers int ) ( ret time . Duration ) {
2014-11-19 03:53:00 +00:00
ret = max / time . Duration ( ( pendingPeers + halfOpenLimit ) / halfOpenLimit )
if ret < minDialTimeout {
ret = minDialTimeout
}
return
2014-11-18 00:04:09 +00:00
}
2015-09-17 02:54:03 +00:00
// Returns whether an address is known to connect to a client with our own ID.
2016-04-19 04:11:11 +00:00
func ( cl * Client ) dopplegangerAddr ( addr string ) bool {
_ , ok := cl . dopplegangerAddrs [ addr ]
2015-03-18 07:29:51 +00:00
return ok
}
2018-02-15 23:46:11 +00:00
func ipNetworkSuffix ( allowIpv4 , allowIpv6 bool ) string {
switch {
case allowIpv4 && allowIpv6 :
return ""
case allowIpv4 && ! allowIpv6 :
return "4"
case ! allowIpv4 && allowIpv6 :
return "6"
default :
panic ( "unhandled ip network combination" )
}
}
2018-04-12 01:41:07 +00:00
func dialUTP ( ctx context . Context , addr string , sock utpSocket ) ( c net . Conn , err error ) {
return sock . DialContext ( ctx , "" , addr )
2015-03-18 07:28:13 +00:00
}
2018-04-12 01:41:07 +00:00
var allPeerNetworks = [ ] string { "tcp4" , "tcp6" , "udp4" , "udp6" }
2018-06-16 06:30:04 +00:00
func peerNetworkEnabled ( network string , cfg * ClientConfig ) bool {
2018-04-12 01:41:07 +00:00
c := func ( s string ) bool {
return strings . Contains ( network , s )
}
if cfg . DisableUTP {
if c ( "udp" ) || c ( "utp" ) {
return false
}
}
if cfg . DisableTCP && c ( "tcp" ) {
return false
}
2018-05-02 09:24:46 +00:00
if cfg . DisableIPv6 && c ( "6" ) {
return false
}
2018-04-12 01:41:07 +00:00
return true
}
2017-09-15 02:56:15 +00:00
2015-08-01 18:04:42 +00:00
// Returns a connection over UTP or TCP, whichever is first to connect.
2018-04-12 01:41:07 +00:00
func ( cl * Client ) dialFirst ( ctx context . Context , addr string ) net . Conn {
2017-08-16 07:05:05 +00:00
ctx , cancel := context . WithCancel ( ctx )
// As soon as we return one connection, cancel the others.
defer cancel ( )
2015-03-18 07:28:13 +00:00
left := 0
resCh := make ( chan dialResult , left )
2018-04-12 01:41:07 +00:00
dial := func ( f func ( _ context . Context , addr string ) ( net . Conn , error ) ) {
2017-08-16 00:32:25 +00:00
left ++
2017-08-16 07:05:05 +00:00
go func ( ) {
2018-04-12 01:41:07 +00:00
c , err := f ( ctx , addr )
2018-06-15 12:39:37 +00:00
// This is a bit optimistic, but it looks non-trivial to thread
// this through the proxy code. Set it now in case we close the
// connection forthwith.
if tc , ok := c . ( * net . TCPConn ) ; ok {
tc . SetLinger ( 0 )
}
2018-04-12 01:41:07 +00:00
countDialResult ( err )
resCh <- dialResult { c }
2017-08-16 07:05:05 +00:00
} ( )
2015-03-18 07:28:13 +00:00
}
2018-04-12 01:41:07 +00:00
func ( ) {
cl . mu . Lock ( )
defer cl . mu . Unlock ( )
cl . eachListener ( func ( s socket ) bool {
if peerNetworkEnabled ( s . Addr ( ) . Network ( ) , cl . config ) {
dial ( s . dial )
}
return true
} )
} ( )
2015-03-18 07:28:13 +00:00
var res dialResult
// Wait for a successful connection.
2018-06-15 12:42:05 +00:00
func ( ) {
defer perf . ScopeTimer ( ) ( )
for ; left > 0 && res . Conn == nil ; left -- {
res = <- resCh
}
} ( )
2018-04-12 01:41:07 +00:00
// There are still incompleted dials.
go func ( ) {
for ; left > 0 ; left -- {
conn := ( <- resCh ) . Conn
if conn != nil {
conn . Close ( )
2014-04-03 12:16:59 +00:00
}
2017-09-15 02:56:15 +00:00
}
2018-04-12 01:41:07 +00:00
} ( )
if res . Conn != nil {
go torrent . Add ( fmt . Sprintf ( "network dialed first: %s" , res . Conn . RemoteAddr ( ) . Network ( ) ) , 1 )
2017-09-15 02:56:15 +00:00
}
2018-04-12 01:41:07 +00:00
return res . Conn
2015-03-18 07:28:13 +00:00
}
2016-04-19 04:11:11 +00:00
func ( cl * Client ) noLongerHalfOpen ( t * Torrent , addr string ) {
2016-04-03 06:50:53 +00:00
if _ , ok := t . halfOpen [ addr ] ; ! ok {
2015-03-18 07:28:13 +00:00
panic ( "invariant broken" )
}
2016-04-03 06:50:53 +00:00
delete ( t . halfOpen , addr )
2018-02-04 01:59:23 +00:00
t . openNewConns ( )
2015-03-18 07:28:13 +00:00
}
2016-03-02 12:27:46 +00:00
// Performs initiator handshakes and returns a connection. Returns nil
// *connection if no connection for valid reasons.
2018-04-12 01:41:07 +00:00
func ( cl * Client ) handshakesConnection ( ctx context . Context , nc net . Conn , t * Torrent , encryptHeader bool ) ( c * connection , err error ) {
2018-06-12 10:14:00 +00:00
c = cl . newConnection ( nc , true )
2017-09-13 08:20:20 +00:00
c . headerEncrypted = encryptHeader
2017-11-07 18:14:13 +00:00
ctx , cancel := context . WithTimeout ( ctx , cl . config . HandshakesTimeout )
2017-08-16 07:05:05 +00:00
defer cancel ( )
dl , ok := ctx . Deadline ( )
if ! ok {
panic ( ctx )
}
err = nc . SetDeadline ( dl )
2015-08-01 18:04:42 +00:00
if err != nil {
2017-08-16 07:05:05 +00:00
panic ( err )
2015-08-01 18:04:42 +00:00
}
2017-08-16 07:05:05 +00:00
ok , err = cl . initiateHandshakes ( c , t )
2015-08-01 18:04:42 +00:00
if ! ok {
c = nil
}
return
}
2018-04-12 01:41:07 +00:00
// Returns nil connection and nil error if no connection could be established
// for valid reasons.
func ( cl * Client ) establishOutgoingConnEx ( t * Torrent , addr string , ctx context . Context , obfuscatedHeader bool ) ( c * connection , err error ) {
nc := cl . dialFirst ( ctx , addr )
if nc == nil {
return
}
defer func ( ) {
if c == nil || err != nil {
nc . Close ( )
}
} ( )
return cl . handshakesConnection ( ctx , nc , t , obfuscatedHeader )
}
2017-09-15 02:56:15 +00:00
2015-03-18 07:28:13 +00:00
// Returns nil connection and nil error if no connection could be established
// for valid reasons.
2016-04-19 04:11:11 +00:00
func ( cl * Client ) establishOutgoingConn ( t * Torrent , addr string ) ( c * connection , err error ) {
2017-08-16 07:05:05 +00:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , time . Minute )
defer cancel ( )
2017-09-13 08:20:20 +00:00
obfuscatedHeaderFirst := ! cl . config . DisableEncryption && ! cl . config . PreferNoEncryption
2018-04-12 01:41:07 +00:00
c , err = cl . establishOutgoingConnEx ( t , addr , ctx , obfuscatedHeaderFirst )
2015-03-18 07:28:13 +00:00
if err != nil {
return
2018-04-12 01:41:07 +00:00
}
if c != nil {
2018-06-12 10:16:17 +00:00
torrent . Add ( "initiated conn with preferred header obfuscation" , 1 )
2015-03-18 07:28:13 +00:00
return
}
2017-09-13 08:20:20 +00: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 08:16:01 +00:00
return
}
2018-04-12 01:41:07 +00:00
// Try again with encryption if we didn't earlier, or without if we did.
c , err = cl . establishOutgoingConnEx ( t , addr , ctx , ! obfuscatedHeaderFirst )
if c != nil {
2018-06-12 10:16:17 +00:00
torrent . Add ( "initiated conn with fallback header obfuscation" , 1 )
2017-09-15 02:56:15 +00:00
}
2015-03-18 07:28:13 +00:00
return
}
2014-11-17 05:27:01 +00:00
2015-03-18 07:28:13 +00:00
// Called to dial out and run a connection. The addr we're given is already
// considered half-open.
2016-04-19 04:11:11 +00: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 07:28:13 +00:00
// Don't release lock between here and addConnection, unless it's for
// failure.
2016-04-19 04:11:11 +00:00
cl . noLongerHalfOpen ( t , addr )
2015-03-18 07:28:13 +00:00
if err != nil {
2016-04-19 04:11:11 +00:00
if cl . config . Debug {
2016-03-22 02:10:18 +00:00
log . Printf ( "error establishing outgoing connection: %s" , err )
}
2015-03-18 07:28:13 +00:00
return
}
if c == nil {
return
}
defer c . Close ( )
c . Discovery = ps
2018-06-12 10:14:00 +00:00
cl . runHandshookConn ( c , t )
2013-09-28 22:11:24 +00:00
}
2014-11-16 19:16:26 +00:00
// The port number for incoming peer connections. 0 if the client isn't
// listening.
2014-06-29 08:57:49 +00:00
func ( cl * Client ) incomingPeerPort ( ) int {
2018-04-12 01:41:07 +00:00
return cl . LocalPort ( )
2014-06-29 08:57:49 +00:00
}
2016-04-19 04:11:11 +00:00
func ( cl * Client ) initiateHandshakes ( c * connection , t * Torrent ) ( ok bool , err error ) {
2017-09-13 08:20:20 +00:00
if c . headerEncrypted {
2016-10-10 05:30:51 +00:00
var rw io . ReadWriter
2018-02-15 23:59:56 +00:00
rw , c . cryptoMethod , err = mse . InitiateHandshake (
2017-09-13 08:20:20 +00:00
struct {
io . Reader
io . Writer
} { c . r , c . w } ,
t . infoHash [ : ] ,
nil ,
2018-02-15 23:36:29 +00:00
func ( ) mse . CryptoMethod {
2017-09-13 08:20:20 +00:00
switch {
case cl . config . ForceEncryption :
return mse . CryptoMethodRC4
case cl . config . DisableEncryption :
return mse . CryptoMethodPlaintext
default :
return mse . AllSupportedCrypto
}
} ( ) ,
)
2016-10-10 05:30:51 +00:00
c . setRW ( rw )
2015-03-18 07:28:13 +00:00
if err != nil {
return
2014-09-13 17:45:38 +00:00
}
}
2016-04-19 04:11:11 +00:00
ih , ok , err := cl . connBTHandshake ( c , & t . infoHash )
2016-04-03 08:40:43 +00:00
if ih != t . infoHash {
2015-03-18 07:28:13 +00:00
ok = false
}
2014-08-27 23:45:20 +00:00
return
}
2017-04-04 08:41:08 +00: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 04:37:58 +00:00
// Do encryption and bittorrent handshakes as receiver.
2016-04-03 08:40:43 +00:00
func ( cl * Client ) receiveHandshakes ( c * connection ) ( t * Torrent , err error ) {
2018-06-15 12:42:05 +00:00
defer perf . ScopeTimerErr ( & err ) ( )
2017-09-13 08:20:20 +00: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 07:28:13 +00:00
}
2017-09-13 08:20:20 +00:00
return
2014-08-28 00:06:57 +00:00
}
2017-09-13 08:20:20 +00:00
if cl . config . ForceEncryption && ! c . headerEncrypted {
2016-09-16 02:42:41 +00:00
err = errors . New ( "connection not encrypted" )
return
}
2015-03-18 07:28:13 +00:00
ih , ok , err := cl . connBTHandshake ( c , nil )
2015-02-09 13:17:59 +00:00
if err != nil {
2015-06-28 06:39:04 +00:00
err = fmt . Errorf ( "error during bt handshake: %s" , err )
2015-02-09 13:17:59 +00:00
return
}
2015-03-18 07:28:13 +00:00
if ! ok {
return
2015-03-12 19:21:13 +00:00
}
2015-03-18 07:28:13 +00:00
cl . mu . Lock ( )
t = cl . torrents [ ih ]
cl . mu . Unlock ( )
return
}
// Returns !ok if handshake failed for valid reasons.
2016-04-04 03:01:31 +00:00
func ( cl * Client ) connBTHandshake ( c * connection , ih * metainfo . Hash ) ( ret metainfo . Hash , ok bool , err error ) {
2016-10-10 05:30:51 +00:00
res , ok , err := handshake ( c . rw ( ) , ih , cl . peerID , cl . extensionBytes )
2015-03-18 07:28:13 +00:00
if err != nil || ! ok {
2015-03-12 19:21:13 +00:00
return
}
2016-04-04 03:01:31 +00:00
ret = res . Hash
2015-03-18 07:28:13 +00:00
c . PeerExtensionBytes = res . peerExtensionBytes
2018-01-06 04:50:45 +00:00
c . PeerID = res . PeerID
2015-03-18 07:28:13 +00:00
c . completedHandshake = time . Now ( )
return
}
2016-05-16 09:50:10 +00:00
func ( cl * Client ) runReceivedConn ( c * connection ) {
2017-11-07 18:14:13 +00:00
err := c . conn . SetDeadline ( time . Now ( ) . Add ( cl . config . HandshakesTimeout ) )
2014-08-21 08:12:49 +00:00
if err != nil {
2016-05-16 09:50:10 +00:00
panic ( err )
2014-08-21 08:12:49 +00:00
}
2015-03-18 07:28:13 +00:00
t , err := cl . receiveHandshakes ( c )
if err != nil {
2018-06-15 12:42:05 +00:00
log . Fmsg (
"error receiving handshakes: %s" , err ,
) . AddValue (
debugLogValue ,
) . Add (
"network" , c . remoteAddr ( ) . Network ( ) ,
) . Log ( cl . logger )
torrent . Add ( "error receiving handshake" , 1 )
2018-06-15 12:38:11 +00:00
cl . mu . Lock ( )
cl . onBadAccept ( c . remoteAddr ( ) )
cl . mu . Unlock ( )
2014-08-21 08:12:49 +00:00
return
2013-09-29 06:45:17 +00:00
}
2015-03-18 07:28:13 +00:00
if t == nil {
2018-06-15 12:42:05 +00:00
torrent . Add ( "received handshake for unloaded torrent" , 1 )
2018-06-15 12:38:11 +00:00
cl . mu . Lock ( )
cl . onBadAccept ( c . remoteAddr ( ) )
cl . mu . Unlock ( )
2014-11-16 19:54:00 +00:00
return
}
2018-06-15 12:42:05 +00:00
torrent . Add ( "received handshake for loaded torrent" , 1 )
2015-03-18 07:28:13 +00:00
cl . mu . Lock ( )
defer cl . mu . Unlock ( )
2018-06-12 10:14:00 +00:00
cl . runHandshookConn ( c , t )
2015-03-18 07:28:13 +00:00
}
2018-06-12 10:14:00 +00:00
func ( cl * Client ) runHandshookConn ( c * connection , t * Torrent ) {
2018-06-09 23:18:52 +00:00
c . setTorrent ( t )
2018-02-02 08:07:20 +00:00
if c . PeerID == cl . peerID {
2018-06-12 10:14:00 +00:00
if c . outgoing {
2018-02-02 08:07:20 +00:00
connsToSelf . Add ( 1 )
addr := c . conn . RemoteAddr ( ) . String ( )
cl . dopplegangerAddrs [ addr ] = struct { } { }
} else {
// 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.
}
return
}
2015-03-18 07:28:13 +00:00
c . conn . SetWriteDeadline ( time . Time { } )
2016-10-10 05:30:51 +00:00
c . r = deadlineReader { c . conn , c . r }
2015-08-01 18:06:22 +00:00
completedHandshakeConnectionFlags . Add ( c . connectionFlags ( ) , 1 )
2018-02-12 13:48:21 +00:00
if connIsIpv6 ( c . conn ) {
torrent . Add ( "completed handshake over ipv6" , 1 )
}
2018-06-12 10:14:00 +00:00
if err := t . addConnection ( c ) ; err != nil {
log . Fmsg ( "error adding connection: %s" , err ) . AddValues ( c , debugLogValue ) . Log ( t . logger )
2014-03-16 15:30:10 +00:00
return
}
2016-05-11 11:44:55 +00:00
defer t . dropConnection ( c )
2016-05-07 08:56:44 +00:00
go c . writer ( time . Minute )
2015-03-18 07:28:13 +00:00
cl . sendInitialMessages ( c , t )
2016-09-11 04:32:56 +00:00
err := c . mainReadLoop ( )
2016-05-16 09:50:10 +00:00
if err != nil && cl . config . Debug {
2018-01-25 02:10:52 +00:00
log . Printf ( "error during connection main read loop: %s" , err )
2015-03-18 07:28:13 +00:00
}
}
2016-04-19 04:11:11 +00:00
func ( cl * Client ) sendInitialMessages ( conn * connection , torrent * Torrent ) {
2018-02-05 06:41:53 +00:00
func ( ) {
if conn . fastEnabled ( ) {
if torrent . haveAllPieces ( ) {
conn . Post ( pp . Message { Type : pp . HaveAll } )
conn . sentHaves . AddRange ( 0 , conn . t . NumPieces ( ) )
return
} else if ! torrent . haveAnyPieces ( ) {
conn . Post ( pp . Message { Type : pp . HaveNone } )
conn . sentHaves . Clear ( )
return
}
}
conn . PostBitfield ( )
} ( )
2016-04-19 04:11:11 +00:00
if conn . PeerExtensionBytes . SupportsExtended ( ) && cl . extensionBytes . SupportsExtended ( ) {
2014-06-26 14:57:07 +00:00
conn . Post ( pp . Message {
Type : pp . Extended ,
ExtendedID : pp . HandshakeExtendedID ,
ExtendedPayload : func ( ) [ ] byte {
2014-06-28 09:38:31 +00:00
d := map [ string ] interface { } {
2015-03-25 04:49:27 +00:00
"m" : func ( ) ( ret map [ string ] int ) {
ret = make ( map [ string ] int , 2 )
ret [ "ut_metadata" ] = metadataExtendedId
2016-04-19 04:11:11 +00:00
if ! cl . config . DisablePEX {
2015-03-25 04:49:27 +00:00
ret [ "ut_pex" ] = pexExtendedId
}
return
} ( ) ,
2017-11-07 18:14:13 +00:00
"v" : cl . config . ExtendedHandshakeClientVersion ,
2014-08-25 12:12:50 +00:00
// No upload queue is implemented yet.
2015-05-14 22:39:53 +00:00
"reqq" : 64 ,
2015-04-20 07:30:22 +00:00
}
2016-04-19 04:11:11 +00:00
if ! cl . config . DisableEncryption {
2015-04-20 07:30:22 +00:00
d [ "e" ] = 1
2014-06-28 09:38:31 +00:00
}
if torrent . metadataSizeKnown ( ) {
d [ "metadata_size" ] = torrent . metadataSize ( )
}
2016-04-19 04:11:11 +00:00
if p := cl . incomingPeerPort ( ) ; p != 0 {
2014-06-29 08:57:49 +00:00
d [ "p" ] = p
}
2015-03-12 19:21:13 +00:00
yourip , err := addrCompactIP ( conn . remoteAddr ( ) )
2014-07-22 11:45:12 +00:00
if err != nil {
log . Printf ( "error calculating yourip field value in extension handshake: %s" , err )
} else {
d [ "yourip" ] = yourip
}
2014-07-24 03:43:45 +00:00
// log.Printf("sending %v", d)
2014-06-28 09:38:31 +00:00
b , err := bencode . Marshal ( d )
2014-06-26 14:57:07 +00:00
if err != nil {
panic ( err )
}
return b
} ( ) ,
} )
}
2018-04-12 01:41:07 +00:00
if conn . PeerExtensionBytes . SupportsDHT ( ) && cl . extensionBytes . SupportsDHT ( ) && cl . haveDhtServer ( ) {
2014-08-25 12:12:16 +00:00
conn . Post ( pp . Message {
Type : pp . Port ,
2018-04-12 01:41:07 +00:00
Port : cl . dhtPort ( ) ,
2014-08-25 12:12:16 +00:00
} )
}
2013-09-30 11:51:08 +00:00
}
2018-04-12 01:41:07 +00:00
func ( cl * Client ) dhtPort ( ) ( ret uint16 ) {
cl . eachDhtServer ( func ( s * dht . Server ) {
ret = uint16 ( missinggo . AddrPort ( s . Addr ( ) ) )
} )
return
}
func ( cl * Client ) haveDhtServer ( ) ( ret bool ) {
cl . eachDhtServer ( func ( _ * dht . Server ) {
ret = true
} )
return
}
2014-08-21 08:12:49 +00:00
// Process incoming ut_metadata message.
2016-07-23 14:34:40 +00:00
func ( cl * Client ) gotMetadataExtensionMsg ( payload [ ] byte , t * Torrent , c * connection ) error {
2014-06-28 09:38:31 +00:00
var d map [ string ] int
2016-07-23 14:34:40 +00:00
err := bencode . Unmarshal ( payload , & d )
2018-02-12 13:21:28 +00:00
if _ , ok := err . ( bencode . ErrUnusedTrailingBytes ) ; ok {
} else if err != nil {
return fmt . Errorf ( "error unmarshalling bencode: %s" , err )
2014-06-28 09:38:31 +00:00
}
msgType , ok := d [ "msg_type" ]
if ! ok {
2016-07-23 14:34:40 +00:00
return errors . New ( "missing msg_type field" )
2014-06-28 09:38:31 +00:00
}
piece := d [ "piece" ]
switch msgType {
case pp . DataMetadataExtensionMsgType :
2016-05-03 04:59:54 +00:00
if ! c . requestedMetadataPiece ( piece ) {
2016-07-23 14:34:40 +00:00
return fmt . Errorf ( "got unexpected piece %d" , piece )
2014-06-28 09:38:31 +00:00
}
2016-05-03 04:59:54 +00:00
c . metadataRequests [ piece ] = false
2014-11-19 03:57:27 +00:00
begin := len ( payload ) - metadataPieceSize ( d [ "total_size" ] , piece )
if begin < 0 || begin >= len ( payload ) {
2016-07-23 14:34:40 +00:00
return fmt . Errorf ( "data has bad offset in payload: %d" , begin )
2015-03-27 04:36:59 +00:00
}
2015-03-19 23:52:01 +00:00
t . saveMetadataPiece ( piece , payload [ begin : ] )
2018-06-12 10:21:53 +00:00
c . allStats ( add ( 1 , func ( cs * ConnStats ) * Count { return & cs . ChunksReadUseful } ) )
2014-12-01 09:32:17 +00:00
c . lastUsefulChunkReceived = time . Now ( )
2016-07-23 14:34:40 +00:00
return t . maybeCompleteMetadata ( )
2014-06-28 09:38:31 +00:00
case pp . RequestMetadataExtensionMsgType :
2015-02-25 04:42:47 +00:00
if ! t . haveMetadataPiece ( piece ) {
c . Post ( t . newMetadataExtensionMessage ( c , pp . RejectMetadataExtensionMsgType , d [ "piece" ] , nil ) )
2016-07-23 14:34:40 +00:00
return nil
2014-06-28 09:38:31 +00:00
}
2014-08-21 08:12:49 +00:00
start := ( 1 << 14 ) * piece
2016-04-03 06:50:53 +00:00
c . Post ( t . newMetadataExtensionMessage ( c , pp . DataMetadataExtensionMsgType , piece , t . metadataBytes [ start : start + t . metadataPieceSize ( piece ) ] ) )
2016-07-23 14:34:40 +00:00
return nil
2014-06-28 09:38:31 +00:00
case pp . RejectMetadataExtensionMsgType :
2016-07-23 14:34:40 +00:00
return nil
2014-06-28 09:38:31 +00:00
default :
2016-07-23 14:34:40 +00:00
return errors . New ( "unknown msg_type value" )
2014-06-28 09:38:31 +00:00
}
}
2016-05-23 16:09:47 +00: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-28 22:11:24 +00:00
}
2016-07-05 06:23:17 +00:00
// Return a Torrent ready for insertion into a Client.
2017-03-16 14:24:54 +00: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 08:40:43 +00:00
t = & Torrent {
2016-10-05 04:57:00 +00:00
cl : cl ,
infoHash : ih ,
2018-04-04 07:59:28 +00:00
peers : prioritizedPeers {
2018-04-14 11:44:41 +00:00
om : btree . New ( 32 ) ,
2018-04-04 07:59:28 +00:00
getPrio : func ( p Peer ) peerPriority {
2018-04-14 11:43:08 +00:00
return bep40PriorityIgnoreError ( cl . publicAddr ( p . IP ) , p . addr ( ) )
2018-04-04 07:59:28 +00:00
} ,
} ,
conns : make ( map [ * connection ] struct { } , 2 * cl . config . EstablishedConnsPerTorrent ) ,
2014-08-24 20:01:05 +00:00
2017-09-15 09:10:09 +00:00
halfOpen : make ( map [ string ] Peer ) ,
2015-09-06 02:33:22 +00:00
pieceStateChanges : pubsub . NewPubSub ( ) ,
2016-05-09 04:37:29 +00:00
2017-03-16 14:24:54 +00:00
storageOpener : storageClient ,
2017-11-07 18:14:13 +00:00
maxEstablishedConns : cl . config . EstablishedConnsPerTorrent ,
2017-08-17 15:51:02 +00:00
networkingEnabled : true ,
2017-09-23 05:25:47 +00:00
requestStrategy : 2 ,
2017-11-08 08:31:10 +00:00
metadataChanged : sync . Cond {
L : & cl . mu ,
} ,
2014-06-26 14:57:07 +00:00
}
2018-01-29 07:19:53 +00:00
t . logger = cl . logger . Clone ( ) . AddValue ( t )
2016-10-05 04:57:00 +00:00
t . setChunkSize ( defaultChunkSize )
2014-11-21 06:09:55 +00:00
return
}
2015-03-07 06:11:02 +00:00
// A file-like handle to some torrent data resource.
2015-03-01 03:32:54 +00:00
type Handle interface {
io . Reader
io . Seeker
io . Closer
2015-03-04 02:06:33 +00:00
io . ReaderAt
2015-03-01 03:32:54 +00:00
}
2016-05-09 04:37:29 +00:00
func ( cl * Client ) AddTorrentInfoHash ( infoHash metainfo . Hash ) ( t * Torrent , new bool ) {
2017-03-16 14:24:54 +00: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 04:37:29 +00:00
cl . mu . Lock ( )
defer cl . mu . Unlock ( )
t , ok := cl . torrents [ infoHash ]
if ok {
return
}
new = true
2018-06-16 06:34:35 +00:00
2017-03-16 14:24:54 +00:00
t = cl . newTorrent ( infoHash , specStorage )
2018-04-12 01:41:07 +00:00
cl . eachDhtServer ( func ( s * dht . Server ) {
go t . dhtAnnouncer ( s )
} )
2016-05-09 05:47:39 +00:00
cl . torrents [ infoHash ] = t
2018-06-16 06:34:35 +00:00
cl . clearAcceptLimits ( )
2016-05-23 00:19:14 +00:00
t . updateWantPeersEvent ( )
2016-07-07 04:49:18 +00:00
// Tickle Client.waitAccept, new torrent may want conns.
cl . event . Broadcast ( )
2016-05-09 04:37:29 +00:00
return
}
2015-03-27 15:50:55 +00: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 14:24:54 +00: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 08:40:43 +00:00
func ( cl * Client ) AddTorrentSpec ( spec * TorrentSpec ) ( t * Torrent , new bool , err error ) {
2017-03-16 14:24:54 +00:00
t , new = cl . AddTorrentInfoHashWithStorage ( spec . InfoHash , spec . Storage )
2015-03-18 07:32:31 +00:00
if spec . DisplayName != "" {
2016-05-09 05:47:39 +00:00
t . SetDisplayName ( spec . DisplayName )
2015-03-18 07:32:31 +00:00
}
2016-08-26 10:29:05 +00:00
if spec . InfoBytes != nil {
err = t . SetInfoBytes ( spec . InfoBytes )
2016-05-09 05:47:39 +00:00
if err != nil {
return
}
2013-10-20 14:07:01 +00:00
}
2016-05-09 05:47:39 +00:00
cl . mu . Lock ( )
defer cl . mu . Unlock ( )
2016-05-09 13:00:20 +00:00
if spec . ChunkSize != 0 {
2016-10-05 04:57:00 +00:00
t . setChunkSize ( pp . Integer ( spec . ChunkSize ) )
2016-05-09 13:00:20 +00:00
}
2015-03-27 15:50:55 +00:00
t . addTrackers ( spec . Trackers )
2016-04-03 12:06:25 +00:00
t . maybeNewConns ( )
2014-06-26 14:57:07 +00:00
return
}
2014-05-21 07:37:31 +00:00
2016-04-19 04:11:11 +00:00
func ( cl * Client ) dropTorrent ( infoHash metainfo . Hash ) ( err error ) {
t , ok := cl . torrents [ infoHash ]
2014-07-22 15:54:11 +00:00
if ! ok {
err = fmt . Errorf ( "no such torrent" )
return
}
2015-02-09 13:12:29 +00:00
err = t . close ( )
2014-07-22 15:54:11 +00:00
if err != nil {
panic ( err )
}
2016-04-19 04:11:11 +00:00
delete ( cl . torrents , infoHash )
2014-07-22 15:54:11 +00:00
return
}
2014-03-16 15:30:10 +00:00
func ( cl * Client ) allTorrentsCompleted ( ) bool {
for _ , t := range cl . torrents {
2014-09-14 17:25:53 +00:00
if ! t . haveInfo ( ) {
return false
}
2018-02-04 08:10:25 +00:00
if ! t . haveAllPieces ( ) {
2014-03-16 15:30:10 +00:00
return false
}
}
return true
}
2014-04-08 16:36:05 +00:00
// Returns true when all torrents are completely downloaded and false if the
2014-06-29 14:22:05 +00:00
// client is stopped before that.
2016-04-19 04:11:11 +00:00
func ( cl * Client ) WaitAll ( ) bool {
cl . mu . Lock ( )
defer cl . mu . Unlock ( )
for ! cl . allTorrentsCompleted ( ) {
if cl . closed . IsSet ( ) {
2014-04-08 16:36:05 +00:00
return false
}
2016-04-19 04:11:11 +00:00
cl . event . Wait ( )
2013-10-20 14:07:01 +00:00
}
2014-04-08 16:36:05 +00:00
return true
2013-09-26 09:49:15 +00:00
}
2015-03-08 06:28:14 +00:00
// Returns handles to all the torrents loaded in the Client.
2016-11-27 03:26:45 +00:00
func ( cl * Client ) Torrents ( ) [ ] * Torrent {
2016-04-19 04:11:11 +00:00
cl . mu . Lock ( )
2016-11-27 03:26:45 +00:00
defer cl . mu . Unlock ( )
return cl . torrentsAsSlice ( )
}
func ( cl * Client ) torrentsAsSlice ( ) ( ret [ ] * Torrent ) {
2016-04-19 04:11:11 +00:00
for _ , t := range cl . torrents {
2016-04-03 08:40:43 +00:00
ret = append ( ret , t )
2013-10-20 14:07:01 +00:00
}
2013-10-06 07:01:39 +00:00
return
}
2015-03-18 07:32:31 +00:00
2016-04-19 04:11:11 +00:00
func ( cl * Client ) AddMagnet ( uri string ) ( T * Torrent , err error ) {
2015-03-18 07:32:31 +00:00
spec , err := TorrentSpecFromMagnetURI ( uri )
if err != nil {
return
}
2016-04-19 04:11:11 +00:00
T , _ , err = cl . AddTorrentSpec ( spec )
2015-03-18 07:32:31 +00:00
return
}
2016-04-19 04:11:11 +00:00
func ( cl * Client ) AddTorrent ( mi * metainfo . MetaInfo ) ( T * Torrent , err error ) {
T , _ , err = cl . AddTorrentSpec ( TorrentSpecFromMetaInfo ( mi ) )
2016-02-24 10:56:50 +00:00
var ss [ ] string
2016-07-12 06:40:14 +00:00
slices . MakeInto ( & ss , mi . Nodes )
2016-04-19 04:11:11 +00:00
cl . AddDHTNodes ( ss )
2015-03-18 07:32:31 +00:00
return
}
2016-04-19 04:11:11 +00:00
func ( cl * Client ) AddTorrentFromFile ( filename string ) ( T * Torrent , err error ) {
2015-03-18 07:32:31 +00:00
mi , err := metainfo . LoadFromFile ( filename )
if err != nil {
return
}
2016-04-19 04:11:11 +00:00
return cl . AddTorrent ( mi )
2015-03-18 07:32:31 +00:00
}
2015-08-03 15:07:22 +00:00
2018-04-12 01:41:07 +00:00
func ( cl * Client ) DhtServers ( ) [ ] * dht . Server {
return cl . dhtServers
2015-08-03 15:07:22 +00:00
}
2016-02-24 10:56:50 +00:00
2016-04-19 04:11:11 +00:00
func ( cl * Client ) AddDHTNodes ( nodes [ ] string ) {
2016-02-24 10:56:50 +00:00
for _ , n := range nodes {
2016-03-15 10:32:47 +00:00
hmp := missinggo . SplitHostMaybePort ( n )
2016-02-24 10:56:50 +00: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 06:40:08 +00:00
ni := krpc . NodeInfo {
2018-02-11 04:13:00 +00:00
Addr : krpc . NodeAddr {
2016-02-24 10:56:50 +00:00
IP : ip ,
Port : hmp . Port ,
2016-05-17 06:40:08 +00:00
} ,
2016-02-24 10:56:50 +00:00
}
2018-04-12 01:41:07 +00:00
cl . eachDhtServer ( func ( s * dht . Server ) {
s . AddNode ( ni )
} )
2016-02-24 10:56:50 +00:00
}
}
2016-05-23 16:09:47 +00: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 05:55:56 +00:00
2018-06-12 10:14:00 +00:00
func ( cl * Client ) newConnection ( nc net . Conn , outgoing bool ) ( c * connection ) {
2016-10-10 05:55:56 +00:00
c = & connection {
2018-02-03 04:09:38 +00:00
conn : nc ,
2018-06-12 10:14:00 +00:00
outgoing : outgoing ,
2016-10-10 05:55:56 +00:00
Choked : true ,
PeerChoked : true ,
PeerMaxRequests : 250 ,
2018-02-03 04:09:38 +00:00
writeBuffer : new ( bytes . Buffer ) ,
2016-10-10 05:55:56 +00:00
}
2017-08-31 06:26:45 +00:00
c . writerCond . L = & cl . mu
2018-06-12 10:21:53 +00:00
c . setRW ( connStatsReadWriter { nc , c } )
2018-01-28 04:42:37 +00:00
c . r = & rateLimitedReader {
2018-06-16 06:30:04 +00:00
l : cl . config . DownloadRateLimiter ,
2018-01-28 04:42:37 +00:00
r : c . r ,
}
2016-10-10 05:55:56 +00:00
return
}
2016-11-26 13:05:19 +00:00
func ( cl * Client ) onDHTAnnouncePeer ( ih metainfo . Hash , p dht . Peer ) {
cl . mu . Lock ( )
defer cl . mu . Unlock ( )
2016-11-27 03:43:21 +00:00
t := cl . torrent ( ih )
if t == nil {
2016-11-26 13:05:19 +00:00
return
}
t . addPeers ( [ ] Peer { {
IP : p . IP ,
Port : p . Port ,
Source : peerSourceDHTAnnouncePeer ,
} } )
}
2018-04-04 07:59:28 +00:00
func firstNotNil ( ips ... net . IP ) net . IP {
for _ , ip := range ips {
if ip != nil {
return ip
}
}
return nil
}
2018-04-12 01:41:07 +00:00
func ( cl * Client ) eachListener ( f func ( socket ) bool ) {
for _ , s := range cl . conns {
if ! f ( s ) {
break
}
}
}
func ( cl * Client ) findListener ( f func ( net . Listener ) bool ) ( ret net . Listener ) {
cl . eachListener ( func ( l socket ) bool {
ret = l
return ! f ( l )
} )
return
}
2018-04-04 07:59:28 +00:00
func ( cl * Client ) publicIp ( peer net . IP ) net . IP {
// TODO: Use BEP 10 to determine how peers are seeing us.
if peer . To4 ( ) != nil {
2018-04-12 01:41:07 +00:00
return firstNotNil (
cl . config . PublicIp4 ,
cl . findListenerIp ( func ( ip net . IP ) bool { return ip . To4 ( ) != nil } ) ,
)
2018-04-04 07:59:28 +00:00
} else {
2018-04-12 01:41:07 +00:00
return firstNotNil (
cl . config . PublicIp6 ,
cl . findListenerIp ( func ( ip net . IP ) bool { return ip . To4 ( ) == nil } ) ,
)
2018-04-04 07:59:28 +00:00
}
}
2018-04-12 01:41:07 +00:00
func ( cl * Client ) findListenerIp ( f func ( net . IP ) bool ) net . IP {
return missinggo . AddrIP ( cl . findListener ( func ( l net . Listener ) bool {
return f ( missinggo . AddrIP ( l . Addr ( ) ) )
} ) . Addr ( ) )
}
2018-04-04 07:59:28 +00:00
// Our IP as a peer should see it.
func ( cl * Client ) publicAddr ( peer net . IP ) ipPort {
return ipPort { cl . publicIp ( peer ) , uint16 ( cl . incomingPeerPort ( ) ) }
}
2018-04-12 01:41:07 +00:00
func ( cl * Client ) ListenAddrs ( ) ( ret [ ] net . Addr ) {
2018-06-13 00:53:38 +00:00
cl . mu . Lock ( )
defer cl . mu . Unlock ( )
2018-04-12 01:41:07 +00:00
cl . eachListener ( func ( l socket ) bool {
ret = append ( ret , l . Addr ( ) )
return true
} )
return
}
2018-06-15 12:38:11 +00:00
func ( cl * Client ) onBadAccept ( addr net . Addr ) {
ip := maskIpForAcceptLimiting ( missinggo . AddrIP ( addr ) )
if cl . acceptLimiter == nil {
cl . acceptLimiter = make ( map [ ipStr ] int )
}
cl . acceptLimiter [ ipStr ( ip . String ( ) ) ] ++
}
func maskIpForAcceptLimiting ( ip net . IP ) net . IP {
if ip4 := ip . To4 ( ) ; ip4 != nil {
return ip4 . Mask ( net . CIDRMask ( 24 , 32 ) )
}
return ip
}
2018-06-16 06:34:35 +00:00
func ( cl * Client ) clearAcceptLimits ( ) {
cl . acceptLimiter = nil
}
2018-06-15 12:38:11 +00:00
func ( cl * Client ) acceptLimitClearer ( ) {
for {
select {
case <- cl . closed . LockedChan ( & cl . mu ) :
return
2018-06-16 06:37:13 +00:00
case <- time . After ( 5 * time . Minute ) :
2018-06-15 12:38:11 +00:00
cl . mu . Lock ( )
2018-06-16 06:34:35 +00:00
cl . clearAcceptLimits ( )
2018-06-15 12:38:11 +00:00
cl . mu . Unlock ( )
}
}
}
func ( cl * Client ) rateLimitAccept ( ip net . IP ) bool {
2018-06-16 06:37:13 +00:00
if cl . config . DisableAcceptRateLimiting {
return false
}
return cl . acceptLimiter [ ipStr ( maskIpForAcceptLimiting ( ip ) . String ( ) ) ] >= 3
2018-06-15 12:38:11 +00:00
}