2013-09-26 17:49:15 +08:00
package torrent
import (
2013-09-30 19:51:08 +08:00
"bufio"
2018-02-03 12:09:38 +08:00
"bytes"
2017-08-16 13:35:17 +08:00
"context"
2013-09-29 06:11:24 +08:00
"crypto/rand"
2018-02-19 13:19:18 +08:00
"encoding/binary"
2013-09-26 17:49:15 +08:00
"errors"
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
"net"
2018-10-31 06:32:33 +08:00
"net/http"
"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
2019-08-10 16:46:07 +08:00
"github.com/anacrolix/dht/v2"
"github.com/anacrolix/dht/v2/krpc"
2018-01-31 13:42:40 +08:00
"github.com/anacrolix/log"
2015-08-06 06:56:36 +08:00
"github.com/anacrolix/missinggo"
2018-07-12 07:15:15 +08:00
"github.com/anacrolix/missinggo/bitmap"
2018-11-21 14:02:22 +08:00
"github.com/anacrolix/missinggo/conntrack"
2018-07-07 09:36:58 +08:00
"github.com/anacrolix/missinggo/perf"
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"
2019-08-21 18:58:40 +08:00
"github.com/davecgh/go-spew/spew"
"github.com/dustin/go-humanize"
"github.com/google/btree"
"golang.org/x/time/rate"
"golang.org/x/xerrors"
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 {
2018-06-23 16:33:56 +08:00
// An aggregate of stats over all connections. First in struct to ensure
// 64-bit alignment of fields. See #262.
2018-07-25 11:41:50 +08:00
stats ConnStats
_mu sync . RWMutex
2016-10-09 21:04:14 +08:00
event sync . Cond
closed missinggo . Event
2018-06-16 14:30:04 +08:00
config * ClientConfig
2019-08-21 18:44:12 +08:00
logger log . Logger
2016-10-09 21:04:14 +08:00
2018-01-06 12:50:45 +08:00
peerID PeerID
2016-10-09 21:04:14 +08:00
defaultStorage * storage . Client
2017-06-01 20:57:08 +08:00
onClose [ ] func ( )
2018-04-12 09:41:07 +08:00
conns [ ] socket
dhtServers [ ] * 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.
2018-07-07 09:31:29 +08:00
extensionBytes pp . PeerExtensionBits
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 { }
2018-07-07 09:32:52 +08:00
torrents map [ InfoHash ] * Torrent
2018-06-15 20:38:11 +08:00
2018-11-02 20:09:52 +08:00
acceptLimiter map [ ipStr ] int
dialRateLimiter * rate . Limiter
2015-02-25 08:25:22 +08:00
}
2014-08-25 03:24:18 +08:00
2018-06-15 20:38:11 +08:00
type ipStr string
2016-07-29 22:37:52 +08:00
func ( cl * Client ) BadPeerIPs ( ) [ ] string {
2018-07-25 11:41:50 +08:00
cl . rLock ( )
defer cl . 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 )
}
2018-01-06 12:50:45 +08:00
func ( cl * Client ) PeerID ( ) PeerID {
2017-11-08 16:28:37 +08:00
return cl . peerID
2014-11-17 03:54:43 +08:00
}
2018-04-12 09:41:07 +08: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 13:12:15 +08: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 15:28:13 +08:00
fmt . Fprintf ( w , "\tAnnounces: %d\n" , dhtStats . SuccessfulOutboundAnnouncePeerQueries )
2018-04-12 09:41:07 +08:00
fmt . Fprintf ( w , "\tOutstanding transactions: %d\n" , dhtStats . OutstandingTransactions )
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 ) {
2018-07-25 11:41:50 +08:00
cl . rLock ( )
defer cl . rUnlock ( )
2014-11-19 11:56:50 +08:00
w := bufio . NewWriter ( _w )
defer w . Flush ( )
2018-04-12 09:41:07 +08:00
fmt . Fprintf ( w , "Listen port: %d\n" , cl . LocalPort ( ) )
2016-07-29 22:37:52 +08:00
fmt . Fprintf ( w , "Peer ID: %+q\n" , cl . PeerID ( ) )
2018-02-19 13:19:18 +08:00
fmt . Fprintf ( w , "Announce key: %x\n" , cl . announceKey ( ) )
2016-11-27 11:26:45 +08:00
fmt . Fprintf ( w , "Banned IPs: %d\n" , len ( cl . badPeerIPsLocked ( ) ) )
2018-04-12 09:41:07 +08:00
cl . eachDhtServer ( func ( s * dht . Server ) {
2018-04-12 13:12:15 +08:00
fmt . Fprintf ( w , "%s DHT server at %s:\n" , s . Addr ( ) . Network ( ) , s . Addr ( ) . String ( ) )
2018-04-12 09:41:07 +08:00
writeDhtServerStatus ( w , s )
} )
2019-07-30 15:18:09 +08:00
spew . Fdump ( w , & cl . stats )
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
}
}
2019-01-16 02:18:30 +08:00
const debugLogValue = log . Debug
2018-01-29 15:19:53 +08:00
2019-08-21 18:44:12 +08:00
func ( cl * Client ) debugLogFilter ( m log . Msg ) bool {
if cl . config . Debug {
return true
2018-01-29 15:19:53 +08:00
}
2019-08-21 18:44:12 +08:00
return ! m . HasValue ( debugLogValue )
2018-01-29 15:19:53 +08:00
}
func ( cl * Client ) initLogger ( ) {
2019-08-21 18:44:12 +08:00
cl . logger = cl . config . Logger . WithValues ( cl ) . WithFilter ( cl . debugLogFilter )
2018-01-29 15:19:53 +08:00
}
2018-02-19 13:19:18 +08:00
func ( cl * Client ) announceKey ( ) int32 {
return int32 ( binary . BigEndian . Uint32 ( cl . peerID [ 16 : 20 ] ) )
}
2018-06-16 14:30:04 +08:00
func NewClient ( cfg * ClientConfig ) ( cl * Client , err error ) {
2017-11-08 02:14:13 +08:00
if cfg == nil {
2018-06-16 14:30:04 +08:00
cfg = NewDefaultClientConfig ( )
2019-07-30 15:19:14 +08:00
cfg . ListenPort = 0
2017-11-08 02:14:13 +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 {
2018-06-16 14:30:04 +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 ) ,
2018-11-02 20:09:52 +08:00
dialRateLimiter : rate . NewLimiter ( 10 , 10 ) ,
2014-08-21 16:07:06 +08:00
}
2018-06-15 20:38:11 +08:00
go cl . acceptLimitClearer ( )
2018-01-29 15:19:53 +08:00
cl . initLogger ( )
2017-06-01 20:57:08 +08:00
defer func ( ) {
if err == nil {
return
}
cl . Close ( )
} ( )
2018-02-03 10:36:17 +08:00
cl . extensionBytes = defaultPeerExtensionBytes ( )
2018-07-25 11:41:50 +08:00
cl . event . L = cl . locker ( )
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 {
2019-01-16 02:18:30 +08:00
cl . logger . Printf ( "error closing default storage: %s" , err )
2017-06-01 20:57:08 +08:00
}
} )
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 {
2017-11-08 02:14:13 +08:00
o := copy ( cl . peerID [ : ] , cfg . 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
2018-10-31 06:32:33 +08:00
if cl . config . HTTPProxy == nil && cl . config . ProxyURL != "" {
if fixedURL , err := url . Parse ( cl . config . ProxyURL ) ; err == nil {
cl . config . HTTPProxy = http . ProxyURL ( fixedURL )
}
}
2018-11-28 07:30:21 +08:00
cl . conns , err = listenAll ( cl . listenNetworks ( ) , cl . config . ListenHost , cl . config . ListenPort , cl . config . ProxyURL , cl . firewallCallback )
2016-05-11 19:11:52 +08:00
if err != nil {
return
2014-11-17 03:29:31 +08:00
}
2018-04-12 14:12:27 +08:00
// Check for panics.
2018-04-12 09:41:07 +08:00
cl . LocalPort ( )
for _ , s := range cl . conns {
2018-11-28 07:30:21 +08:00
if peerNetworkEnabled ( parseNetworkString ( s . Addr ( ) . Network ( ) ) , cl . config ) {
2018-04-12 09:41:07 +08:00
go cl . acceptConnections ( s )
}
2014-03-17 22:44:22 +08:00
}
2018-04-12 09:41:07 +08:00
go cl . forwardPort ( )
2014-08-21 16:07:06 +08:00
if ! cfg . NoDHT {
2018-04-12 09:41:07 +08:00
for _ , s := range cl . conns {
if pc , ok := s . ( net . PacketConn ) ; ok {
ds , err := cl . newDhtServer ( pc )
2017-07-20 22:40:49 +08:00
if err != nil {
2018-04-12 09:41:07 +08:00
panic ( err )
2017-07-20 22:40:49 +08:00
}
2018-04-12 09:41:07 +08:00
cl . dhtServers = append ( cl . dhtServers , ds )
2017-07-20 22:40:49 +08:00
}
2014-11-29 02:13:08 +08:00
}
2018-04-12 09:41:07 +08:00
}
return
}
2018-07-25 15:11:09 +08:00
func ( cl * Client ) firewallCallback ( net . Addr ) bool {
cl . rLock ( )
block := ! cl . wantConns ( )
cl . rUnlock ( )
if block {
torrent . Add ( "connections firewalled" , 1 )
} else {
torrent . Add ( "connections not firewalled" , 1 )
}
return block
}
2018-11-28 07:30:21 +08:00
func ( cl * Client ) enabledPeerNetworks ( ) ( ns [ ] network ) {
2018-04-12 09:41:07 +08:00
for _ , n := range allPeerNetworks {
if peerNetworkEnabled ( n , cl . config ) {
ns = append ( ns , n )
2014-08-21 16:07:06 +08:00
}
2018-04-12 09:41:07 +08:00
}
return
}
2018-11-28 07:30:21 +08:00
func ( cl * Client ) listenOnNetwork ( n network ) bool {
if n . Ipv4 && cl . config . DisableIPv4 {
return false
}
if n . Ipv6 && cl . config . DisableIPv6 {
return false
}
if n . Tcp && cl . config . DisableTCP {
return false
}
if n . Udp && cl . config . DisableUTP && cl . config . NoDHT {
return false
}
return true
}
func ( cl * Client ) listenNetworks ( ) ( ns [ ] network ) {
for _ , n := range allPeerNetworks {
if cl . listenOnNetwork ( n ) {
ns = append ( ns , n )
}
}
return
}
2018-04-12 09:41:07 +08:00
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
} ( ) ,
2018-11-21 14:02:22 +08:00
StartingNodes : cl . config . DhtStartingNodes ,
ConnectionTracking : cl . config . ConnTracker ,
2019-05-23 10:13:48 +08:00
OnQuery : cl . config . DHTOnQuery ,
2019-09-13 06:46:30 +08:00
Logger : cl . logger . WithValues ( "dht" , conn . LocalAddr ( ) . String ( ) ) ,
2018-04-12 09:41:07 +08:00
}
s , err = dht . NewServer ( & cfg )
if err == nil {
2017-08-10 09:18:48 +08:00
go func ( ) {
2018-11-21 14:05:56 +08:00
ts , err := s . Bootstrap ( )
if err != nil {
2019-01-16 02:18:30 +08:00
cl . logger . Printf ( "error bootstrapping dht: %s" , err )
2017-08-10 09:18:48 +08:00
}
2019-08-22 11:59:04 +08:00
log . Fstr ( "%v: completed bootstrap" , s ) . AddValues ( s , ts ) . Log ( cl . logger )
2017-08-10 09:18:48 +08:00
} ( )
2014-08-21 16:07:06 +08:00
}
return
2014-03-17 22:44:22 +08:00
}
2018-02-08 20:57:53 +08:00
func ( cl * Client ) Closed ( ) <- chan struct { } {
2018-07-25 11:41:50 +08:00
cl . lock ( )
defer cl . unlock ( )
2018-02-08 20:57:53 +08:00
return cl . closed . C ( )
}
2018-04-12 09:41:07 +08: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-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 ( ) {
2018-07-25 11:41:50 +08:00
cl . lock ( )
defer cl . unlock ( )
2016-04-19 12:11:11 +08:00
cl . closed . Set ( )
2018-04-12 09:41:07 +08:00
cl . eachDhtServer ( func ( s * dht . Server ) { s . Close ( ) } )
cl . closeSockets ( )
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
}
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
}
2018-02-11 12:11:26 +08:00
return cl . ipBlockList . Lookup ( ip )
2014-11-29 09:41:53 +08:00
}
2018-02-19 13:19:18 +08:00
func ( cl * Client ) ipIsBlocked ( ip net . IP ) bool {
_ , blocked := cl . ipBlockRange ( ip )
return blocked
}
2018-07-25 15:11:09 +08:00
func ( cl * Client ) wantConns ( ) bool {
for _ , t := range cl . torrents {
if t . wantConns ( ) {
return true
}
}
return false
}
2015-03-18 15:36:27 +08:00
func ( cl * Client ) waitAccept ( ) {
for {
2016-03-05 16:36:21 +08:00
if cl . closed . IsSet ( ) {
2015-08-03 23:15:09 +08:00
return
}
2018-07-25 15:11:09 +08:00
if cl . wantConns ( ) {
return
}
2015-03-18 15:36:27 +08:00
cl . event . Wait ( )
}
}
2018-02-16 07:46:11 +08: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 20:38:11 +08:00
if cl . rateLimitAccept ( rip ) {
return true
}
2018-02-16 07:46:11 +08:00
return cl . badPeerIPPort ( rip , missinggo . AddrPort ( ra ) )
}
2018-04-12 09:41:07 +08:00
func ( cl * Client ) acceptConnections ( l net . Listener ) {
2014-03-17 22:44:22 +08:00
for {
2014-11-17 03:29:31 +08:00
conn , err := l . Accept ( )
2019-06-21 12:49:21 +08:00
torrent . Add ( "client listener accepts" , 1 )
2016-03-06 14:26:04 +08:00
conn = pproffd . WrapNetConn ( conn )
2018-07-25 11:41:50 +08:00
cl . rLock ( )
2018-06-10 08:29:19 +08:00
closed := cl . closed . IsSet ( )
reject := false
if conn != nil {
reject = cl . rejectAccepted ( conn )
}
2018-07-25 11:41:50 +08:00
cl . rUnlock ( )
2018-06-10 08:29:19 +08:00
if closed {
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 {
2019-01-16 02:18:30 +08:00
cl . logger . Printf ( "error accepting connection: %s" , err )
2018-07-27 08:18:56 +08:00
continue
2014-03-17 22:44:22 +08:00
}
2018-06-10 08:29:19 +08: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 15:28:13 +08:00
}
}
2018-04-12 09:41:07 +08:00
func ( cl * Client ) incomingConnection ( nc net . Conn ) {
2015-03-18 15:28:13 +08:00
defer nc . Close ( )
if tc , ok := nc . ( * net . TCPConn ) ; ok {
tc . SetLinger ( 0 )
}
2018-11-16 07:35:30 +08:00
c := cl . newConnection ( nc , false , missinggo . IpPortFromNetAddr ( nc . RemoteAddr ( ) ) , nc . RemoteAddr ( ) . Network ( ) )
2015-03-18 15:28:13 +08:00
c . Discovery = peerSourceIncoming
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 ) {
2018-07-25 11:41:50 +08:00
cl . lock ( )
defer cl . 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 {
2018-11-04 13:56:55 +08:00
Conn net . Conn
Network string
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 {
2018-06-15 12:30:31 +08:00
torrent . Add ( "successful dials" , 1 )
2017-08-16 15:05:05 +08:00
} else {
2018-06-15 12:30:31 +08:00
torrent . Add ( "unsuccessful dials" , 1 )
2014-11-17 15:44:06 +08:00
}
2014-11-17 13:27:01 +08:00
}
2017-11-08 02:14:13 +08:00
func reducedDialTimeout ( minDialTimeout , max time . Duration , halfOpenLimit int , pendingPeers int ) ( ret time . Duration ) {
2014-11-19 11:53:00 +08:00
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
}
2015-08-02 02:04:42 +08:00
// Returns a connection over UTP or TCP, whichever is first to connect.
2019-08-15 08:17:39 +08:00
func ( cl * Client ) dialFirst ( ctx context . Context , addr string ) ( res dialResult ) {
{
t := perf . NewTimer ( perf . CallerName ( 0 ) )
defer func ( ) {
if res . Conn == nil {
t . Mark ( fmt . Sprintf ( "returned no conn (context: %v)" , ctx . Err ( ) ) )
} else {
t . Mark ( "returned conn over " + res . Network )
}
} ( )
}
2017-08-16 15:05:05 +08:00
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 )
2018-04-12 09:41:07 +08:00
func ( ) {
2018-07-25 11:41:50 +08:00
cl . lock ( )
defer cl . unlock ( )
2018-04-12 09:41:07 +08:00
cl . eachListener ( func ( s socket ) bool {
2019-06-21 12:50:49 +08:00
func ( ) {
network := s . Addr ( ) . Network ( )
if ! peerNetworkEnabled ( parseNetworkString ( network ) , cl . config ) {
return
}
2018-11-04 13:56:55 +08:00
left ++
2019-07-19 14:17:38 +08:00
//cl.logger.Printf("dialing %s on %s/%s", addr, s.Addr().Network(), s.Addr())
2018-11-04 13:56:55 +08:00
go func ( ) {
2019-06-21 12:50:49 +08:00
resCh <- dialResult {
cl . dialFromSocket ( ctx , s , addr ) ,
network ,
2018-11-04 13:56:55 +08:00
}
} ( )
2019-06-21 12:50:49 +08:00
} ( )
2018-04-12 09:41:07 +08:00
return true
} )
} ( )
2015-03-18 15:28:13 +08:00
// Wait for a successful connection.
2018-06-15 20:42:05 +08:00
func ( ) {
defer perf . ScopeTimer ( ) ( )
for ; left > 0 && res . Conn == nil ; left -- {
res = <- resCh
}
} ( )
2018-04-12 09:41:07 +08:00
// There are still incompleted dials.
go func ( ) {
for ; left > 0 ; left -- {
conn := ( <- resCh ) . Conn
if conn != nil {
conn . Close ( )
2014-04-03 20:16:59 +08:00
}
2017-09-15 10:56:15 +08:00
}
2018-04-12 09:41:07 +08:00
} ( )
if res . Conn != nil {
go torrent . Add ( fmt . Sprintf ( "network dialed first: %s" , res . Conn . RemoteAddr ( ) . Network ( ) ) , 1 )
2017-09-15 10:56:15 +08:00
}
2019-07-19 14:17:38 +08:00
//if res.Conn != nil {
// cl.logger.Printf("first connection for %s from %s/%s", addr, res.Conn.LocalAddr().Network(), res.Conn.LocalAddr().String())
//} else {
// cl.logger.Printf("failed to dial %s", addr)
//}
2018-11-04 13:56:55 +08:00
return res
2015-03-18 15:28:13 +08:00
}
2019-06-21 12:50:49 +08:00
func ( cl * Client ) dialFromSocket ( ctx context . Context , s socket , addr string ) net . Conn {
network := s . Addr ( ) . Network ( )
cte := cl . config . ConnTracker . Wait (
ctx ,
conntrack . Entry { network , s . Addr ( ) . String ( ) , addr } ,
"dial torrent client" ,
0 ,
)
// Try to avoid committing to a dial if the context is complete as it's difficult to determine
// which dial errors allow us to forget the connection tracking entry handle.
if ctx . Err ( ) != nil {
if cte != nil {
cte . Forget ( )
}
return nil
}
c , err := s . dial ( ctx , addr )
// 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 )
}
countDialResult ( err )
if c == nil {
if err != nil && forgettableDialError ( err ) {
cte . Forget ( )
} else {
cte . Done ( )
}
return nil
}
return closeWrapper { c , func ( ) error {
err := c . Close ( )
cte . Done ( )
return err
} }
}
2018-11-28 07:32:08 +08:00
func forgettableDialError ( err error ) bool {
return strings . Contains ( err . Error ( ) , "no suitable address found" )
}
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 )
2018-02-04 09:59:23 +08:00
t . openNewConns ( )
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.
2018-11-16 07:35:30 +08:00
func ( cl * Client ) handshakesConnection ( ctx context . Context , nc net . Conn , t * Torrent , encryptHeader bool , remoteAddr IpPort , network string ) ( c * connection , err error ) {
2018-11-04 13:56:55 +08:00
c = cl . newConnection ( nc , true , remoteAddr , network )
2017-09-13 16:20:20 +08:00
c . headerEncrypted = encryptHeader
2017-11-08 02:14:13 +08:00
ctx , cancel := context . WithTimeout ( ctx , cl . config . HandshakesTimeout )
2017-08-16 15:05:05 +08:00
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
}
2019-07-19 14:15:46 +08:00
err = cl . initiateHandshakes ( c , t )
2015-08-02 02:04:42 +08:00
return
}
2018-04-12 09:41:07 +08:00
// Returns nil connection and nil error if no connection could be established
// for valid reasons.
2019-07-19 14:15:46 +08:00
func ( cl * Client ) establishOutgoingConnEx ( t * Torrent , addr IpPort , obfuscatedHeader bool ) ( * connection , error ) {
2019-08-11 11:17:47 +08:00
dialCtx , cancel := context . WithTimeout ( context . Background ( ) , func ( ) time . Duration {
2019-07-19 12:46:48 +08:00
cl . rLock ( )
defer cl . rUnlock ( )
return t . dialTimeout ( )
} ( ) )
defer cancel ( )
2019-08-11 11:17:47 +08:00
dr := cl . dialFirst ( dialCtx , addr . String ( ) )
2018-11-04 13:56:55 +08:00
nc := dr . Conn
2018-04-12 09:41:07 +08:00
if nc == nil {
2019-08-11 11:17:47 +08:00
if dialCtx . Err ( ) != nil {
return nil , xerrors . Errorf ( "dialing: %w" , dialCtx . Err ( ) )
2018-04-12 09:41:07 +08:00
}
2019-07-19 14:15:46 +08:00
return nil , errors . New ( "dial failed" )
}
2019-08-11 11:17:47 +08:00
c , err := cl . handshakesConnection ( context . Background ( ) , nc , t , obfuscatedHeader , addr , dr . Network )
2019-07-19 14:15:46 +08:00
if err != nil {
nc . Close ( )
}
return c , err
2018-04-12 09:41:07 +08:00
}
2017-09-15 10:56:15 +08:00
2015-03-18 15:28:13 +08:00
// Returns nil connection and nil error if no connection could be established
// for valid reasons.
2018-11-16 07:35:30 +08:00
func ( cl * Client ) establishOutgoingConn ( t * Torrent , addr IpPort ) ( c * connection , err error ) {
2018-11-04 13:12:16 +08:00
torrent . Add ( "establish outgoing connection" , 1 )
2019-07-19 11:23:36 +08:00
obfuscatedHeaderFirst := cl . config . HeaderObfuscationPolicy . Preferred
2019-07-19 12:46:48 +08:00
c , err = cl . establishOutgoingConnEx ( t , addr , obfuscatedHeaderFirst )
2019-07-19 14:15:46 +08:00
if err == nil {
2018-06-12 18:16:17 +08:00
torrent . Add ( "initiated conn with preferred header obfuscation" , 1 )
2015-03-18 15:28:13 +08:00
return
}
2019-07-19 14:15:46 +08:00
//cl.logger.Printf("error establishing connection to %s (obfuscatedHeader=%t): %v", addr, obfuscatedHeaderFirst, err)
2019-07-19 11:23:36 +08:00
if cl . config . HeaderObfuscationPolicy . RequirePreferred {
// We should have just tried with the preferred header obfuscation. If it was required,
// there's nothing else to try.
2015-06-08 16:16:01 +08:00
return
}
2018-04-12 09:41:07 +08:00
// Try again with encryption if we didn't earlier, or without if we did.
2019-07-19 12:46:48 +08:00
c , err = cl . establishOutgoingConnEx ( t , addr , ! obfuscatedHeaderFirst )
2019-07-19 14:15:46 +08:00
if err == nil {
2018-06-12 18:16:17 +08:00
torrent . Add ( "initiated conn with fallback header obfuscation" , 1 )
2017-09-15 10:56:15 +08:00
}
2019-07-19 14:15:46 +08:00
//cl.logger.Printf("error establishing fallback connection to %v: %v", addr, err)
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.
2018-11-16 07:35:30 +08:00
func ( cl * Client ) outgoingConnection ( t * Torrent , addr IpPort , ps peerSource ) {
2018-11-02 20:09:52 +08:00
cl . dialRateLimiter . Wait ( context . Background ( ) )
2016-04-19 12:11:11 +08:00
c , err := cl . establishOutgoingConn ( t , addr )
2018-07-25 11:41:50 +08:00
cl . lock ( )
defer cl . unlock ( )
2015-03-18 15:28:13 +08:00
// Don't release lock between here and addConnection, unless it's for
// failure.
2018-11-04 13:56:55 +08:00
cl . noLongerHalfOpen ( t , addr . String ( ) )
2015-03-18 15:28:13 +08:00
if err != nil {
2016-04-19 12:11:11 +08:00
if cl . config . Debug {
2019-07-30 15:26:12 +08:00
cl . logger . Printf ( "error establishing outgoing connection to %v: %v" , addr , err )
2016-03-22 10:10:18 +08:00
}
2015-03-18 15:28:13 +08:00
return
}
defer c . Close ( )
c . Discovery = ps
2018-06-12 18:14:00 +08:00
cl . runHandshookConn ( 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 {
2018-04-12 09:41:07 +08:00
return cl . LocalPort ( )
2014-06-29 16:57:49 +08:00
}
2019-07-19 14:15:46 +08:00
func ( cl * Client ) initiateHandshakes ( c * connection , t * Torrent ) error {
2017-09-13 16:20:20 +08:00
if c . headerEncrypted {
2016-10-10 13:30:51 +08:00
var rw io . ReadWriter
2019-07-19 14:15:46 +08:00
var err error
2018-02-16 07:59:56 +08:00
rw , c . cryptoMethod , err = mse . InitiateHandshake (
2017-09-13 16:20:20 +08:00
struct {
io . Reader
io . Writer
} { c . r , c . w } ,
t . infoHash [ : ] ,
nil ,
2019-07-19 11:23:36 +08:00
cl . config . CryptoProvides ,
2017-09-13 16:20:20 +08:00
)
2016-10-10 13:30:51 +08:00
c . setRW ( rw )
2015-03-18 15:28:13 +08:00
if err != nil {
2019-07-19 14:15:46 +08:00
return xerrors . Errorf ( "header obfuscation handshake: %w" , err )
2014-09-14 01:45:38 +08:00
}
}
2019-07-19 14:15:46 +08:00
ih , err := cl . connBtHandshake ( c , & t . infoHash )
if err != nil {
return xerrors . Errorf ( "bittorrent protocol handshake: %w" , err )
}
2016-04-03 16:40:43 +08:00
if ih != t . infoHash {
2019-07-19 14:15:46 +08:00
return errors . New ( "bittorrent protocol handshake: peer infohash didn't match" )
2015-03-18 15:28:13 +08:00
}
2019-07-19 14:15:46 +08:00
return nil
2014-08-28 07:45:20 +08:00
}
2017-04-04 16:41:08 +08:00
// Calls f with any secret keys.
func ( cl * Client ) forSkeys ( f func ( [ ] byte ) bool ) {
2018-07-25 11:41:50 +08:00
cl . lock ( )
defer cl . unlock ( )
2019-07-19 11:07:40 +08:00
if false { // Emulate the bug from #114
var firstIh InfoHash
for ih := range cl . torrents {
firstIh = ih
break
}
for range cl . torrents {
if ! f ( firstIh [ : ] ) {
break
}
}
return
}
2017-04-04 16:41:08 +08:00
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 ) {
2018-06-15 20:42:05 +08:00
defer perf . ScopeTimerErr ( & err ) ( )
2017-09-13 16:20:20 +08:00
var rw io . ReadWriter
2019-07-19 11:23:36 +08:00
rw , c . headerEncrypted , c . cryptoMethod , err = handleEncryption ( c . rw ( ) , cl . forSkeys , cl . config . HeaderObfuscationPolicy , cl . config . CryptoSelector )
2017-09-13 16:20:20 +08:00
c . setRW ( rw )
2018-07-25 15:11:56 +08:00
if err == nil || err == mse . ErrNoSecretKeyMatch {
if c . headerEncrypted {
torrent . Add ( "handshakes received encrypted" , 1 )
} else {
torrent . Add ( "handshakes received unencrypted" , 1 )
}
} else {
torrent . Add ( "handshakes received with error while handling encryption" , 1 )
}
2017-09-13 16:20:20 +08:00
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
}
2019-07-19 11:23:36 +08:00
if cl . config . HeaderObfuscationPolicy . RequirePreferred && c . headerEncrypted != cl . config . HeaderObfuscationPolicy . Preferred {
err = errors . New ( "connection not have required header obfuscation" )
2016-09-16 10:42:41 +08:00
return
}
2019-07-19 14:15:46 +08:00
ih , err := cl . connBtHandshake ( c , nil )
2015-02-09 21:17:59 +08:00
if err != nil {
2019-07-19 14:15:46 +08:00
err = xerrors . Errorf ( "during bt handshake: %w" , err )
2015-03-18 15:28:13 +08:00
return
2015-03-13 03:21:13 +08:00
}
2018-07-25 11:41:50 +08:00
cl . lock ( )
2015-03-18 15:28:13 +08:00
t = cl . torrents [ ih ]
2018-07-25 11:41:50 +08:00
cl . unlock ( )
2015-03-18 15:28:13 +08:00
return
}
2019-07-19 14:15:46 +08:00
func ( cl * Client ) connBtHandshake ( c * connection , ih * metainfo . Hash ) ( ret metainfo . Hash , err error ) {
res , err := pp . Handshake ( c . rw ( ) , ih , cl . peerID , cl . extensionBytes )
if err != nil {
2015-03-13 03:21:13 +08:00
return
}
2016-04-04 11:01:31 +08:00
ret = res . Hash
2018-07-07 09:31:29 +08:00
c . PeerExtensionBytes = res . PeerExtensionBits
2018-01-06 12:50:45 +08:00
c . PeerID = res . PeerID
2015-03-18 15:28:13 +08:00
c . completedHandshake = time . Now ( )
return
}
2016-05-16 17:50:10 +08:00
func ( cl * Client ) runReceivedConn ( c * connection ) {
2017-11-08 02:14:13 +08:00
err := c . conn . SetDeadline ( time . Now ( ) . Add ( cl . config . 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 {
2018-06-15 20:42:05 +08:00
log . Fmsg (
"error receiving handshakes: %s" , err ,
) . AddValue (
debugLogValue ,
) . Add (
2018-11-04 13:56:55 +08:00
"network" , c . network ,
2018-06-15 20:42:05 +08:00
) . Log ( cl . logger )
torrent . Add ( "error receiving handshake" , 1 )
2018-07-25 11:41:50 +08:00
cl . lock ( )
2018-11-04 13:56:55 +08:00
cl . onBadAccept ( c . remoteAddr )
2018-07-25 11:41:50 +08:00
cl . unlock ( )
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 {
2018-06-15 20:42:05 +08:00
torrent . Add ( "received handshake for unloaded torrent" , 1 )
2018-07-25 11:41:50 +08:00
cl . lock ( )
2018-11-04 13:56:55 +08:00
cl . onBadAccept ( c . remoteAddr )
2018-07-25 11:41:50 +08:00
cl . unlock ( )
2014-11-17 03:54:00 +08:00
return
}
2018-06-15 20:42:05 +08:00
torrent . Add ( "received handshake for loaded torrent" , 1 )
2018-07-25 11:41:50 +08:00
cl . lock ( )
defer cl . unlock ( )
2018-06-12 18:14:00 +08:00
cl . runHandshookConn ( c , t )
2015-03-18 15:28:13 +08:00
}
2018-06-12 18:14:00 +08:00
func ( cl * Client ) runHandshookConn ( c * connection , t * Torrent ) {
2018-06-10 07:18:52 +08:00
c . setTorrent ( t )
2018-02-02 16:07:20 +08:00
if c . PeerID == cl . peerID {
2018-06-12 18:14:00 +08:00
if c . outgoing {
2018-02-02 16:07:20 +08: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 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 )
2018-02-12 21:48:21 +08:00
if connIsIpv6 ( c . conn ) {
torrent . Add ( "completed handshake over ipv6" , 1 )
}
2018-06-12 18:14:00 +08:00
if err := t . addConnection ( c ) ; err != nil {
log . Fmsg ( "error adding connection: %s" , err ) . AddValues ( c , debugLogValue ) . Log ( t . logger )
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 {
2019-01-16 02:18:30 +08:00
cl . logger . Printf ( "error during connection main read loop: %s" , err )
2015-03-18 15:28:13 +08:00
}
}
2018-07-14 09:28:54 +08:00
// See the order given in Transmission's tr_peerMsgsNew.
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 {
2018-07-10 10:20:36 +08:00
msg := pp . ExtendedHandshakeMessage {
M : map [ pp . ExtensionName ] pp . ExtensionNumber {
pp . ExtensionNameMetadata : metadataExtendedId ,
} ,
V : cl . config . ExtendedHandshakeClientVersion ,
Reqq : 64 , // TODO: Really?
2018-11-04 13:56:55 +08:00
YourIp : pp . CompactIp ( conn . remoteAddr . IP ) ,
2019-07-19 11:23:36 +08:00
Encryption : cl . config . HeaderObfuscationPolicy . Preferred || ! cl . config . HeaderObfuscationPolicy . RequirePreferred ,
2018-07-10 10:20:36 +08:00
Port : cl . incomingPeerPort ( ) ,
MetadataSize : torrent . metadataSize ( ) ,
2018-07-11 22:00:07 +08:00
// TODO: We can figured these out specific to the socket
// used.
Ipv4 : pp . CompactIp ( cl . config . PublicIp4 . To4 ( ) ) ,
Ipv6 : cl . config . PublicIp6 . To16 ( ) ,
2015-04-20 15:30:22 +08:00
}
2018-07-10 10:20:36 +08:00
if ! cl . config . DisablePEX {
msg . M [ pp . ExtensionNamePex ] = pexExtendedId
2014-06-28 17:38:31 +08:00
}
2018-07-10 10:20:36 +08:00
return bencode . MustMarshal ( msg )
2014-06-26 22:57:07 +08:00
} ( ) ,
} )
}
2018-07-14 09:28:54 +08:00
func ( ) {
if conn . fastEnabled ( ) {
if torrent . haveAllPieces ( ) {
conn . Post ( pp . Message { Type : pp . HaveAll } )
conn . sentHaves . AddRange ( 0 , bitmap . BitIndex ( conn . t . NumPieces ( ) ) )
return
} else if ! torrent . haveAnyPieces ( ) {
conn . Post ( pp . Message { Type : pp . HaveNone } )
conn . sentHaves . Clear ( )
return
}
}
conn . PostBitfield ( )
} ( )
2018-04-12 09:41:07 +08:00
if conn . PeerExtensionBytes . SupportsDHT ( ) && cl . extensionBytes . SupportsDHT ( ) && cl . haveDhtServer ( ) {
2014-08-25 20:12:16 +08:00
conn . Post ( pp . Message {
Type : pp . Port ,
2018-04-12 09:41:07 +08:00
Port : cl . dhtPort ( ) ,
2014-08-25 20:12:16 +08:00
} )
}
2013-09-30 19:51:08 +08:00
}
2018-04-12 09:41:07 +08: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 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 )
2018-02-12 21:21:28 +08:00
if _ , ok := err . ( bencode . ErrUnusedTrailingBytes ) ; ok {
} else if err != nil {
return fmt . Errorf ( "error unmarshalling bencode: %s" , err )
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 :
2018-07-15 08:09:58 +08:00
c . allStats ( add ( 1 , func ( cs * ConnStats ) * Count { return & cs . MetadataChunksRead } ) )
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 . 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
}
}
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 ,
2018-04-04 15:59:28 +08:00
peers : prioritizedPeers {
2018-04-14 19:44:41 +08:00
om : btree . New ( 32 ) ,
2018-04-04 15:59:28 +08:00
getPrio : func ( p Peer ) peerPriority {
2018-04-14 19:43:08 +08:00
return bep40PriorityIgnoreError ( cl . publicAddr ( p . IP ) , p . addr ( ) )
2018-04-04 15:59:28 +08:00
} ,
} ,
conns : make ( map [ * connection ] struct { } , 2 * cl . config . EstablishedConnsPerTorrent ) ,
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 ,
2017-11-08 02:14:13 +08:00
maxEstablishedConns : cl . config . EstablishedConnsPerTorrent ,
2017-08-17 23:51:02 +08:00
networkingEnabled : true ,
2018-08-25 14:43:28 +08:00
requestStrategy : 2 ,
2017-11-08 16:31:10 +08:00
metadataChanged : sync . Cond {
2018-07-25 11:41:50 +08:00
L : cl . locker ( ) ,
2017-11-08 16:31:10 +08:00
} ,
2018-06-30 19:10:48 +08:00
duplicateRequestTimeout : 1 * time . Second ,
2014-06-26 22:57:07 +08:00
}
2019-08-21 18:44:12 +08:00
t . logger = cl . logger . WithValues ( t )
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 ) {
2018-07-25 11:41:50 +08:00
cl . lock ( )
defer cl . unlock ( )
2016-05-09 12:37:29 +08:00
t , ok := cl . torrents [ infoHash ]
if ok {
return
}
new = true
2018-06-16 14:34:35 +08:00
2017-03-16 22:24:54 +08:00
t = cl . newTorrent ( infoHash , specStorage )
2018-04-12 09:41:07 +08:00
cl . eachDhtServer ( func ( s * dht . Server ) {
go t . dhtAnnouncer ( s )
} )
2016-05-09 13:47:39 +08:00
cl . torrents [ infoHash ] = t
2018-06-16 14:34:35 +08:00
cl . clearAcceptLimits ( )
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
}
2018-07-25 11:41:50 +08:00
cl . lock ( )
defer cl . 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
}
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
}
2018-02-04 16:10:25 +08:00
if ! t . haveAllPieces ( ) {
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 {
2018-07-25 11:41:50 +08:00
cl . lock ( )
defer cl . unlock ( )
2016-04-19 12:11:11 +08:00
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 {
2018-07-25 11:41:50 +08:00
cl . lock ( )
defer cl . unlock ( )
2016-11-27 11:26:45 +08:00
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
2018-04-12 09:41:07 +08:00
func ( cl * Client ) DhtServers ( ) [ ] * dht . Server {
return cl . dhtServers
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 ) {
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 {
2019-01-16 02:18:30 +08:00
cl . logger . Printf ( "won't add DHT node with bad IP: %q" , hmp . Host )
2016-02-24 18:56:50 +08:00
continue
}
2016-05-17 14:40:08 +08:00
ni := krpc . NodeInfo {
2018-02-11 12:13:00 +08:00
Addr : krpc . NodeAddr {
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
}
2018-04-12 09:41:07 +08:00
cl . eachDhtServer ( func ( s * dht . Server ) {
s . 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
2018-11-16 07:35:30 +08:00
func ( cl * Client ) newConnection ( nc net . Conn , outgoing bool , remoteAddr IpPort , network string ) ( c * connection ) {
2016-10-10 13:55:56 +08:00
c = & connection {
2018-02-03 12:09:38 +08:00
conn : nc ,
2018-06-12 18:14:00 +08:00
outgoing : outgoing ,
2016-10-10 13:55:56 +08:00
Choked : true ,
PeerChoked : true ,
PeerMaxRequests : 250 ,
2018-02-03 12:09:38 +08:00
writeBuffer : new ( bytes . Buffer ) ,
2018-11-04 13:56:55 +08:00
remoteAddr : remoteAddr ,
network : network ,
2016-10-10 13:55:56 +08:00
}
2018-07-25 11:41:50 +08:00
c . writerCond . L = cl . locker ( )
2018-06-12 18:21:53 +08:00
c . setRW ( connStatsReadWriter { nc , c } )
2018-01-28 12:42:37 +08:00
c . r = & rateLimitedReader {
2018-06-16 14:30:04 +08:00
l : cl . config . DownloadRateLimiter ,
2018-01-28 12:42:37 +08:00
r : 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 ) {
2018-07-25 11:41:50 +08:00
cl . lock ( )
defer cl . 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 ,
} } )
}
2018-04-04 15:59:28 +08:00
func firstNotNil ( ips ... net . IP ) net . IP {
for _ , ip := range ips {
if ip != nil {
return ip
}
}
return nil
}
2018-04-12 09:41:07 +08: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 15:59:28 +08: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 09:41:07 +08:00
return firstNotNil (
cl . config . PublicIp4 ,
cl . findListenerIp ( func ( ip net . IP ) bool { return ip . To4 ( ) != nil } ) ,
)
2018-04-04 15:59:28 +08:00
} else {
2018-04-12 09:41:07 +08:00
return firstNotNil (
cl . config . PublicIp6 ,
cl . findListenerIp ( func ( ip net . IP ) bool { return ip . To4 ( ) == nil } ) ,
)
2018-04-04 15:59:28 +08:00
}
}
2018-04-12 09:41:07 +08: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 15:59:28 +08:00
// Our IP as a peer should see it.
2018-11-16 07:35:30 +08:00
func ( cl * Client ) publicAddr ( peer net . IP ) IpPort {
return IpPort { cl . publicIp ( peer ) , uint16 ( cl . incomingPeerPort ( ) ) }
2018-04-04 15:59:28 +08:00
}
2018-04-12 09:41:07 +08:00
func ( cl * Client ) ListenAddrs ( ) ( ret [ ] net . Addr ) {
2018-07-25 11:41:50 +08:00
cl . lock ( )
defer cl . unlock ( )
2018-04-12 09:41:07 +08:00
cl . eachListener ( func ( l socket ) bool {
ret = append ( ret , l . Addr ( ) )
return true
} )
return
}
2018-06-15 20:38:11 +08:00
2018-11-16 07:35:30 +08:00
func ( cl * Client ) onBadAccept ( addr IpPort ) {
2018-11-04 13:56:55 +08:00
ip := maskIpForAcceptLimiting ( addr . IP )
2018-06-15 20:38:11 +08:00
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 14:34:35 +08:00
func ( cl * Client ) clearAcceptLimits ( ) {
cl . acceptLimiter = nil
}
2018-06-15 20:38:11 +08:00
func ( cl * Client ) acceptLimitClearer ( ) {
for {
select {
2018-07-25 11:41:50 +08:00
case <- cl . closed . LockedChan ( cl . locker ( ) ) :
2018-06-15 20:38:11 +08:00
return
2018-06-22 15:43:02 +08:00
case <- time . After ( 15 * time . Minute ) :
2018-07-25 11:41:50 +08:00
cl . lock ( )
2018-06-16 14:34:35 +08:00
cl . clearAcceptLimits ( )
2018-07-25 11:41:50 +08:00
cl . unlock ( )
2018-06-15 20:38:11 +08:00
}
}
}
func ( cl * Client ) rateLimitAccept ( ip net . IP ) bool {
2018-06-16 14:37:13 +08:00
if cl . config . DisableAcceptRateLimiting {
return false
}
2018-06-22 15:43:02 +08:00
return cl . acceptLimiter [ ipStr ( maskIpForAcceptLimiting ( ip ) . String ( ) ) ] > 0
2018-06-15 20:38:11 +08:00
}
2018-07-25 11:41:50 +08:00
func ( cl * Client ) rLock ( ) {
cl . _mu . RLock ( )
}
func ( cl * Client ) rUnlock ( ) {
cl . _mu . RUnlock ( )
}
func ( cl * Client ) lock ( ) {
cl . _mu . Lock ( )
}
func ( cl * Client ) unlock ( ) {
cl . _mu . Unlock ( )
}
func ( cl * Client ) locker ( ) sync . Locker {
return clientLocker { cl }
}
type clientLocker struct {
* Client
}
func ( cl clientLocker ) Lock ( ) {
cl . lock ( )
}
func ( cl clientLocker ) Unlock ( ) {
cl . unlock ( )
}