2013-09-26 09:49:15 +00:00
package torrent
import (
2013-09-30 11:51:08 +00:00
"bufio"
2014-09-11 04:20:47 +00:00
"bytes"
2017-08-16 05:35:17 +00:00
"context"
2013-09-28 22:11:24 +00:00
"crypto/rand"
2015-03-12 09:06:23 +00:00
"encoding/hex"
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
"log"
"net"
2015-03-10 15:41:41 +00:00
"net/url"
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
2017-01-01 00:01:41 +00:00
"github.com/anacrolix/dht"
"github.com/anacrolix/dht/krpc"
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"
2016-05-19 07:15:10 +00:00
"github.com/dustin/go-humanize"
2016-10-10 03:58:29 +00:00
"golang.org/x/time/rate"
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
config Config
halfOpenLimit int
peerID [ 20 ] byte
defaultStorage * storage . Client
2017-06-01 12:57:08 +00:00
onClose [ ] func ( )
2016-05-11 11:11:52 +00:00
tcpListener net . Listener
2017-06-16 08:08:24 +00:00
utpSock utpSocket
2015-04-27 04:05:27 +00:00
dHT * 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
// The net.Addr.String part that should be common to all active listeners.
2016-10-10 06:29:39 +00:00
listenAddr string
uploadLimit * rate . Limiter
downloadLimit * rate . Limiter
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
2015-02-25 00:25:22 +00:00
}
2014-08-24 19:24:18 +00:00
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 )
}
2016-04-19 04:11:11 +00:00
func ( cl * Client ) IPBlockList ( ) iplist . Ranger {
cl . mu . Lock ( )
defer cl . mu . Unlock ( )
return cl . ipBlockList
2013-09-26 09:49:15 +00:00
}
2016-04-19 04:11:11 +00:00
func ( cl * Client ) SetIPBlockList ( list iplist . Ranger ) {
cl . mu . Lock ( )
defer cl . mu . Unlock ( )
cl . ipBlockList = list
if cl . dHT != nil {
cl . dHT . SetIPBlockList ( list )
2014-11-30 02:33:17 +00:00
}
2014-11-29 01:41:53 +00:00
}
2016-04-19 04:11:11 +00:00
func ( cl * Client ) PeerID ( ) string {
return string ( 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 ) }
func ( cl * Client ) ListenAddr ( ) net . Addr {
if cl . listenAddr == "" {
return nil
2014-11-16 19:16:26 +00:00
}
2016-05-11 11:11:52 +00:00
return torrentAddr ( cl . listenAddr )
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 ) {
2016-11-27 03:26:45 +00:00
cl . mu . Lock ( )
defer cl . mu . Unlock ( )
2014-11-19 03:56:50 +00:00
w := bufio . NewWriter ( _w )
defer w . Flush ( )
2015-02-25 03:52:19 +00:00
if addr := cl . ListenAddr ( ) ; addr != nil {
2016-07-29 14:37:52 +00:00
fmt . Fprintf ( w , "Listening on %s\n" , addr )
2015-02-25 03:52:19 +00:00
} else {
2015-03-10 15:39:01 +00:00
fmt . Fprintln ( w , "Not listening!" )
2015-02-25 03:52:19 +00:00
}
2016-07-29 14:37:52 +00:00
fmt . Fprintf ( w , "Peer ID: %+q\n" , cl . PeerID ( ) )
2016-11-27 03:26:45 +00:00
fmt . Fprintf ( w , "Banned IPs: %d\n" , len ( cl . badPeerIPsLocked ( ) ) )
2016-07-29 14:37:52 +00:00
if dht := cl . DHT ( ) ; dht != nil {
dhtStats := dht . Stats ( )
2015-08-03 14:31:53 +00:00
fmt . Fprintf ( w , "DHT nodes: %d (%d good, %d banned)\n" , dhtStats . Nodes , dhtStats . GoodNodes , dhtStats . BadNodes )
2016-07-29 14:37:52 +00:00
fmt . Fprintf ( w , "DHT Server ID: %x\n" , dht . ID ( ) )
fmt . Fprintf ( w , "DHT port: %d\n" , missinggo . AddrPort ( dht . Addr ( ) ) )
2015-04-01 06:29:55 +00:00
fmt . Fprintf ( w , "DHT announces: %d\n" , dhtStats . ConfirmedAnnounces )
fmt . Fprintf ( w , "Outstanding transactions: %d\n" , dhtStats . OutstandingTransactions )
2014-07-22 15:50:49 +00:00
}
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" )
2016-07-29 14:37:52 +00:00
if t . Info ( ) != nil {
2016-11-27 03:26:45 +00:00
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
}
}
2017-06-16 08:08:24 +00:00
func listenUTP ( networkSuffix , addr string ) ( utpSocket , error ) {
return NewUtpSocket ( "udp" + networkSuffix , addr )
2016-05-11 11:11:52 +00:00
}
func listenTCP ( networkSuffix , addr string ) ( net . Listener , error ) {
return net . Listen ( "tcp" + networkSuffix , addr )
}
2017-06-16 08:08:24 +00:00
func listenBothSameDynamicPort ( networkSuffix , host string ) ( tcpL net . Listener , utpSock utpSocket , listenedAddr string , err error ) {
2016-05-11 11:11:52 +00:00
for {
tcpL , err = listenTCP ( networkSuffix , net . JoinHostPort ( host , "0" ) )
if err != nil {
return
}
listenedAddr = tcpL . Addr ( ) . String ( )
utpSock , err = listenUTP ( networkSuffix , listenedAddr )
if err == nil {
return
}
tcpL . Close ( )
if ! strings . Contains ( err . Error ( ) , "address already in use" ) {
return
}
}
}
2016-05-24 09:45:42 +00:00
// Listen to enabled protocols, ensuring ports match.
2017-06-16 08:08:24 +00:00
func listen ( tcp , utp bool , networkSuffix , addr string ) ( tcpL net . Listener , utpSock utpSocket , listenedAddr string , err error ) {
2016-05-11 11:11:52 +00:00
if addr == "" {
addr = ":50007"
}
2016-08-30 04:19:29 +00:00
if tcp && utp {
var host string
var port int
host , port , err = missinggo . ParseHostPort ( addr )
if err != nil {
return
}
if port == 0 {
// If both protocols are active, they need to have the same port.
return listenBothSameDynamicPort ( networkSuffix , host )
}
2016-05-11 11:11:52 +00:00
}
2016-05-24 09:45:42 +00:00
defer func ( ) {
if err != nil {
listenedAddr = ""
}
} ( )
2016-05-11 11:11:52 +00:00
if tcp {
tcpL , err = listenTCP ( networkSuffix , addr )
if err != nil {
return
}
2016-05-24 09:45:42 +00:00
defer func ( ) {
if err != nil {
tcpL . Close ( )
}
} ( )
2016-05-24 05:18:04 +00:00
listenedAddr = tcpL . Addr ( ) . String ( )
2016-05-11 11:11:52 +00:00
}
if utp {
utpSock , err = listenUTP ( networkSuffix , addr )
2016-05-24 09:45:42 +00:00
if err != nil {
2016-05-24 05:24:29 +00:00
return
2016-05-11 11:11:52 +00:00
}
2016-05-24 05:18:04 +00:00
listenedAddr = utpSock . Addr ( ) . String ( )
2016-05-11 11:11:52 +00:00
}
return
}
2015-06-03 03:30:55 +00:00
// Creates a new client.
2014-08-21 08:07:06 +00:00
func NewClient ( cfg * Config ) ( cl * Client , err error ) {
if cfg == nil {
cfg = & Config { }
2013-10-14 14:39:12 +00:00
}
2014-08-21 08:07:06 +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 {
2016-07-05 06:23:17 +00:00
halfOpenLimit : defaultHalfOpenConnsPerTorrent ,
2016-03-28 09:38:30 +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
}
2017-06-01 12:57:08 +00:00
defer func ( ) {
if err == nil {
return
}
cl . Close ( )
} ( )
2016-10-10 03:58:29 +00:00
if cfg . UploadRateLimiter == nil {
cl . uploadLimit = rate . NewLimiter ( rate . Inf , 0 )
} else {
cl . uploadLimit = cfg . UploadRateLimiter
}
2016-10-10 06:29:39 +00:00
if cfg . DownloadRateLimiter == nil {
cl . downloadLimit = rate . NewLimiter ( rate . Inf , 0 )
} else {
cl . downloadLimit = cfg . DownloadRateLimiter
}
2016-03-30 08:11:55 +00:00
missinggo . CopyExact ( & cl . extensionBytes , defaultExtensionBytes )
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 {
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 {
2015-03-08 06:28:14 +00:00
o := copy ( cl . peerID [ : ] , 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
2016-05-11 11:11:52 +00:00
cl . tcpListener , cl . utpSock , cl . listenAddr , err = listen (
! cl . config . DisableTCP ,
! cl . config . DisableUTP ,
func ( ) string {
2015-08-04 16:41:50 +00:00
if cl . config . DisableIPv6 {
2016-05-11 11:11:52 +00:00
return "4"
2015-08-04 16:41:50 +00:00
} else {
2016-05-11 11:11:52 +00:00
return ""
2015-08-04 16:41:50 +00:00
}
2016-05-11 11:11:52 +00:00
} ( ) ,
cl . config . ListenAddr )
if err != nil {
return
2014-11-16 19:29:31 +00:00
}
2016-05-11 11:11:52 +00:00
if cl . tcpListener != nil {
go cl . acceptConnections ( cl . tcpListener , false )
}
if cl . utpSock != nil {
2015-01-10 13:16:19 +00:00
go cl . acceptConnections ( cl . utpSock , true )
2014-03-17 14:44:22 +00:00
}
2014-08-21 08:07:06 +00:00
if ! cfg . NoDHT {
2014-11-28 18:13:08 +00:00
dhtCfg := cfg . DHTConfig
2015-08-03 14:43:46 +00:00
if dhtCfg . IPBlocklist == nil {
dhtCfg . IPBlocklist = cl . ipBlockList
2014-11-20 02:02:20 +00:00
}
2017-07-20 14:40:49 +00:00
if dhtCfg . Conn == nil {
if cl . utpSock != nil {
dhtCfg . Conn = cl . utpSock
} else {
dhtCfg . Conn , err = net . ListenPacket ( "udp" , firstNonEmptyString ( cl . listenAddr , cl . config . ListenAddr ) )
if err != nil {
return
}
}
2014-11-28 18:13:08 +00:00
}
2016-11-26 13:05:19 +00:00
if dhtCfg . OnAnnouncePeer == nil {
dhtCfg . OnAnnouncePeer = cl . onDHTAnnouncePeer
}
2016-01-16 13:12:53 +00:00
cl . dHT , err = dht . NewServer ( & dhtCfg )
2014-08-21 08:07:06 +00:00
if err != nil {
return
}
2017-08-10 01:18:48 +00:00
go func ( ) {
if _ , err := cl . dHT . Bootstrap ( ) ; err != nil {
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 ""
}
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 ( )
if cl . dHT != nil {
cl . dHT . Close ( )
}
2016-05-11 11:11:52 +00:00
if cl . utpSock != nil {
2017-06-16 08:08:24 +00:00
cl . utpSock . Close ( )
2016-05-11 11:11:52 +00:00
}
if cl . tcpListener != nil {
cl . tcpListener . Close ( )
2014-11-21 06:07:04 +00:00
}
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
}
2014-12-01 09:27:11 +00:00
var ipv6BlockRange = iplist . Range { Description : "non-IPv4 address" }
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
}
2015-04-01 06:36:51 +00:00
ip4 := ip . To4 ( )
2015-10-18 13:00:26 +00:00
// If blocklists are enabled, then block non-IPv4 addresses, because
// blocklists do not yet support IPv6.
2015-04-01 06:36:51 +00:00
if ip4 == nil {
2015-11-13 11:33:50 +00:00
if missinggo . CryHeard ( ) {
log . Printf ( "blocking non-IPv4 address: %s" , ip )
}
2015-10-18 13:00:26 +00:00
r = ipv6BlockRange
blocked = true
2014-12-01 09:27:11 +00:00
return
}
2015-10-18 13:00:26 +00:00
return cl . ipBlockList . Lookup ( ip4 )
2014-11-29 01:41:53 +00:00
}
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 ( )
}
}
2014-11-16 19:29:31 +00:00
func ( cl * Client ) acceptConnections ( l net . Listener , utp bool ) {
2016-07-05 14:38:43 +00:00
cl . mu . Lock ( )
defer cl . mu . Unlock ( )
2014-03-17 14:44:22 +00:00
for {
2015-03-18 07:36:27 +00:00
cl . waitAccept ( )
2016-07-05 14:38:43 +00:00
cl . mu . Unlock ( )
2014-11-16 19:29:31 +00:00
conn , err := l . Accept ( )
2016-03-06 06:26:04 +00:00
conn = pproffd . WrapNetConn ( conn )
2016-07-05 14:38:43 +00:00
cl . mu . Lock ( )
2016-03-05 08:36:21 +00:00
if cl . closed . IsSet ( ) {
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
}
2015-06-29 14:35:47 +00:00
if utp {
acceptUTP . Add ( 1 )
} else {
acceptTCP . Add ( 1 )
}
2016-09-21 11:00:18 +00:00
if cl . config . Debug {
log . Printf ( "accepted connection from %s" , conn . RemoteAddr ( ) )
}
2016-05-23 16:09:47 +00:00
reject := cl . badPeerIPPort (
missinggo . AddrIP ( conn . RemoteAddr ( ) ) ,
missinggo . AddrPort ( conn . RemoteAddr ( ) ) )
if reject {
2016-09-21 11:00:18 +00:00
if cl . config . Debug {
log . Printf ( "rejecting connection from %s" , conn . RemoteAddr ( ) )
}
2015-06-29 14:35:47 +00:00
acceptReject . Add ( 1 )
2014-12-26 06:18:36 +00:00
conn . Close ( )
2014-11-29 01:41:53 +00:00
continue
}
2015-03-18 07:28:13 +00:00
go cl . incomingConnection ( conn , utp )
}
}
func ( cl * Client ) incomingConnection ( nc net . Conn , utp bool ) {
defer nc . Close ( )
if tc , ok := nc . ( * net . TCPConn ) ; ok {
tc . SetLinger ( 0 )
}
2016-10-10 05:55:56 +00:00
c := cl . newConnection ( nc )
2015-03-18 07:28:13 +00:00
c . Discovery = peerSourceIncoming
c . uTP = utp
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
UTP bool
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 {
successfulDials . Add ( 1 )
2017-08-16 07:05:05 +00:00
} else {
unsuccessfulDials . Add ( 1 )
2014-11-17 07:44:06 +00:00
}
2014-11-17 05:27:01 +00:00
}
2014-11-19 03:53:00 +00:00
func reducedDialTimeout ( max time . Duration , halfOpenLimit int , pendingPeers int ) ( ret time . Duration ) {
ret = max / time . Duration ( ( pendingPeers + halfOpenLimit ) / halfOpenLimit )
if ret < minDialTimeout {
ret = minDialTimeout
}
return
2014-11-18 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
}
2014-07-22 11:45:12 +00:00
// Start the process of connecting to the given peer for the given torrent if
// appropriate.
2016-04-19 04:11:11 +00:00
func ( cl * Client ) initiateConn ( peer Peer , t * Torrent ) {
if peer . Id == cl . peerID {
2013-09-28 22:11:24 +00:00
return
}
2016-05-23 16:09:47 +00:00
if cl . badPeerIPPort ( peer . IP , peer . Port ) {
2014-11-16 19:30:44 +00:00
return
2014-08-27 23:35:13 +00:00
}
2016-05-23 16:09:47 +00:00
addr := net . JoinHostPort ( peer . IP . String ( ) , fmt . Sprintf ( "%d" , peer . Port ) )
if t . addrActive ( addr ) {
2014-11-29 01:41:53 +00:00
return
}
2016-04-03 06:50:53 +00:00
t . halfOpen [ addr ] = struct { } { }
2016-04-19 04:11:11 +00:00
go cl . outgoingConnection ( t , addr , peer . Source )
2015-03-18 07:28:13 +00:00
}
2016-04-19 04:11:11 +00:00
func ( cl * Client ) dialTimeout ( t * Torrent ) time . Duration {
cl . mu . Lock ( )
2016-04-03 06:50:53 +00:00
pendingPeers := len ( t . peers )
2016-04-19 04:11:11 +00:00
cl . mu . Unlock ( )
return reducedDialTimeout ( nominalDialTimeout , cl . halfOpenLimit , pendingPeers )
2015-03-18 07:28:13 +00:00
}
2017-08-16 07:05:05 +00:00
func ( cl * Client ) dialTCP ( ctx context . Context , addr string ) ( c net . Conn , err error ) {
2017-08-16 05:48:30 +00:00
d := net . Dialer {
2017-08-16 07:05:05 +00:00
// LocalAddr: cl.tcpListener.Addr(),
2017-08-16 05:48:30 +00:00
}
2017-08-16 07:05:05 +00:00
c , err = d . DialContext ( ctx , "tcp" , addr )
countDialResult ( err )
2015-03-18 07:28:13 +00:00
if err == nil {
c . ( * net . TCPConn ) . SetLinger ( 0 )
}
2016-06-20 07:51:40 +00:00
c = pproffd . WrapNetConn ( c )
2015-03-18 07:28:13 +00:00
return
}
2017-08-16 07:05:05 +00:00
func ( cl * Client ) dialUTP ( ctx context . Context , addr string ) ( c net . Conn , err error ) {
c , err = cl . utpSock . DialContext ( ctx , addr )
countDialResult ( err )
return
2015-03-18 07:28:13 +00:00
}
2015-08-01 18:04:42 +00:00
// Returns a connection over UTP or TCP, whichever is first to connect.
2017-08-16 07:05:05 +00:00
func ( cl * Client ) dialFirst ( ctx context . Context , addr string ) ( conn net . Conn , utp bool ) {
ctx , cancel := context . WithCancel ( ctx )
// As soon as we return one connection, cancel the others.
defer cancel ( )
2015-03-18 07:28:13 +00:00
left := 0
resCh := make ( chan dialResult , left )
2016-04-19 04:11:11 +00:00
if ! cl . config . DisableUTP {
2017-08-16 00:32:25 +00:00
left ++
2017-08-16 07:05:05 +00:00
go func ( ) {
c , _ := cl . dialUTP ( ctx , addr )
resCh <- dialResult { c , true }
} ( )
2015-03-18 07:28:13 +00:00
}
2016-04-19 04:11:11 +00:00
if ! cl . config . DisableTCP {
2017-08-16 00:32:25 +00:00
left ++
2017-08-16 07:05:05 +00:00
go func ( ) {
c , _ := cl . dialTCP ( ctx , addr )
resCh <- dialResult { c , false }
} ( )
2015-03-18 07:28:13 +00:00
}
var res dialResult
// Wait for a successful connection.
for ; left > 0 && res . Conn == nil ; left -- {
res = <- resCh
}
if left > 0 {
// There are still incompleted dials.
2014-04-03 12:16:59 +00:00
go func ( ) {
2015-03-18 07:28:13 +00:00
for ; left > 0 ; left -- {
conn := ( <- resCh ) . Conn
if conn != nil {
conn . Close ( )
}
2014-04-03 12:16:59 +00:00
}
} ( )
2015-03-18 07:28:13 +00:00
}
conn = res . Conn
utp = res . UTP
return
}
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 )
2016-04-19 04:11:11 +00:00
cl . openNewConns ( t )
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.
2017-08-16 07:05:05 +00:00
func ( cl * Client ) handshakesConnection ( ctx context . Context , nc net . Conn , t * Torrent , encrypted , utp bool ) ( c * connection , err error ) {
2016-10-10 05:55:56 +00:00
c = cl . newConnection ( nc )
2015-08-01 18:04:42 +00:00
c . encrypted = encrypted
c . uTP = utp
2017-08-16 07:05:05 +00:00
ctx , cancel := context . WithTimeout ( ctx , handshakesTimeout )
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
}
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 ( )
nc , utp := cl . dialFirst ( ctx , addr )
2015-03-18 07:28:13 +00:00
if nc == nil {
return
}
2016-09-16 02:42:41 +00:00
encryptFirst := ! cl . config . DisableEncryption && ! cl . config . PreferNoEncryption
2017-08-16 07:05:05 +00:00
c , err = cl . handshakesConnection ( ctx , nc , t , encryptFirst , utp )
2015-03-18 07:28:13 +00:00
if err != nil {
nc . Close ( )
return
} else if c != nil {
return
}
nc . Close ( )
2016-09-16 02:42:41 +00:00
if cl . config . DisableEncryption || cl . config . ForceEncryption {
// There's no alternate encryption case to try.
2015-06-08 08:16:01 +00:00
return
}
2016-09-16 02:42:41 +00:00
// Try again with encryption if we didn't earlier, or without if we did,
// using whichever protocol type worked last time.
2015-03-18 07:28:13 +00:00
if utp {
2017-08-16 07:05:05 +00:00
nc , err = cl . dialUTP ( ctx , addr )
2015-03-18 07:28:13 +00:00
} else {
2017-08-16 07:05:05 +00:00
nc , err = cl . dialTCP ( ctx , addr )
2015-03-18 07:28:13 +00:00
}
if err != nil {
err = fmt . Errorf ( "error dialing for unencrypted connection: %s" , err )
return
}
2017-08-16 07:05:05 +00:00
c , err = cl . handshakesConnection ( ctx , nc , t , ! encryptFirst , utp )
2016-03-02 12:27:46 +00:00
if err != nil || c == nil {
2015-03-18 07:28:13 +00:00
nc . Close ( )
}
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
2016-05-16 09:50:10 +00:00
cl . runInitiatedHandshookConn ( 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 {
2016-05-11 11:11:52 +00:00
if cl . listenAddr == "" {
2014-06-29 08:57:49 +00:00
return 0
}
2016-05-11 11:11:52 +00:00
_ , port , err := missinggo . ParseHostPort ( cl . listenAddr )
if err != nil {
panic ( err )
}
return port
2014-06-29 08:57:49 +00:00
}
2014-11-16 19:16:26 +00:00
// Convert a net.Addr to its compact IP representation. Either 4 or 16 bytes
// per "yourip" field of http://www.bittorrent.org/beps/bep_0010.html.
2014-07-22 11:45:12 +00:00
func addrCompactIP ( addr net . Addr ) ( string , error ) {
2014-11-16 19:16:26 +00:00
host , _ , err := net . SplitHostPort ( addr . String ( ) )
if err != nil {
return "" , err
}
ip := net . ParseIP ( host )
if v4 := ip . To4 ( ) ; v4 != nil {
if len ( v4 ) != 4 {
panic ( v4 )
2014-07-22 11:45:12 +00:00
}
2014-11-16 19:16:26 +00:00
return string ( v4 ) , nil
2014-07-22 11:45:12 +00:00
}
2014-11-16 19:16:26 +00:00
return string ( ip . To16 ( ) ) , nil
2014-07-22 11:45:12 +00:00
}
2015-03-12 19:21:13 +00:00
func handshakeWriter ( w io . Writer , bb <- chan [ ] byte , done chan <- error ) {
2014-08-21 08:12:49 +00:00
var err error
for b := range bb {
_ , err = w . Write ( b )
if err != nil {
break
}
}
done <- err
}
2015-03-12 09:04:44 +00:00
type (
peerExtensionBytes [ 8 ] byte
peerID [ 20 ] byte
)
2014-08-21 08:12:49 +00:00
2016-04-19 04:11:11 +00:00
func ( pex * peerExtensionBytes ) SupportsExtended ( ) bool {
return pex [ 5 ] & 0x10 != 0
2015-03-12 19:21:13 +00:00
}
2016-04-19 04:11:11 +00:00
func ( pex * peerExtensionBytes ) SupportsDHT ( ) bool {
return pex [ 7 ] & 0x01 != 0
2015-03-12 19:21:13 +00:00
}
2016-04-19 04:11:11 +00:00
func ( pex * peerExtensionBytes ) SupportsFast ( ) bool {
return pex [ 7 ] & 0x04 != 0
2015-03-12 19:21:13 +00:00
}
2014-08-21 08:12:49 +00:00
type handshakeResult struct {
peerExtensionBytes
peerID
2016-04-04 03:01:31 +00:00
metainfo . Hash
2014-08-21 08:12:49 +00:00
}
2015-02-09 13:16:01 +00:00
// ih is nil if we expect the peer to declare the InfoHash, such as when the
// peer initiated the connection. Returns ok if the handshake was successful,
// and err if there was an unexpected condition other than the peer simply
// abandoning the handshake.
2016-04-04 03:01:31 +00:00
func handshake ( sock io . ReadWriter , ih * metainfo . Hash , peerID [ 20 ] byte , extensions peerExtensionBytes ) ( res handshakeResult , ok bool , err error ) {
2014-08-21 08:12:49 +00:00
// Bytes to be sent to the peer. Should never block the sender.
postCh := make ( chan [ ] byte , 4 )
// A single error value sent when the writer completes.
writeDone := make ( chan error , 1 )
// Performs writes to the socket and ensures posts don't block.
go handshakeWriter ( sock , postCh , writeDone )
2014-03-20 11:01:56 +00:00
defer func ( ) {
2014-08-21 08:12:49 +00:00
close ( postCh ) // Done writing.
if ! ok {
return
}
if err != nil {
panic ( err )
}
// Wait until writes complete before returning from handshake.
err = <- writeDone
if err != nil {
2015-03-18 07:28:13 +00:00
err = fmt . Errorf ( "error writing: %s" , err )
2014-08-21 08:12:49 +00:00
}
2014-03-20 11:01:56 +00:00
} ( )
2014-08-21 08:12:49 +00:00
post := func ( bb [ ] byte ) {
select {
case postCh <- bb :
default :
panic ( "mustn't block while posting" )
}
2014-03-20 13:14:17 +00:00
}
2014-08-21 08:12:49 +00:00
post ( [ ] byte ( pp . Protocol ) )
2015-03-12 19:21:13 +00:00
post ( extensions [ : ] )
2014-08-21 08:12:49 +00:00
if ih != nil { // We already know what we want.
post ( ih [ : ] )
post ( peerID [ : ] )
}
var b [ 68 ] byte
_ , err = io . ReadFull ( sock , b [ : 68 ] )
2013-10-20 14:07:01 +00:00
if err != nil {
2014-08-21 08:12:49 +00:00
err = nil
2013-10-14 14:39:12 +00:00
return
2013-09-29 06:45:17 +00:00
}
2014-05-21 08:01:58 +00:00
if string ( b [ : 20 ] ) != pp . Protocol {
2013-09-29 06:45:17 +00:00
return
}
2016-03-30 08:11:55 +00:00
missinggo . CopyExact ( & res . peerExtensionBytes , b [ 20 : 28 ] )
2016-04-04 03:01:31 +00:00
missinggo . CopyExact ( & res . Hash , b [ 28 : 48 ] )
2016-03-30 08:11:55 +00:00
missinggo . CopyExact ( & res . peerID , b [ 48 : 68 ] )
2015-03-12 09:06:23 +00:00
peerExtensions . Add ( hex . EncodeToString ( res . peerExtensionBytes [ : ] ) , 1 )
2014-08-21 08:12:49 +00:00
2015-03-12 09:06:23 +00:00
// TODO: Maybe we can just drop peers here if we're not interested. This
// could prevent them trying to reconnect, falsely believing there was
// just a problem.
2014-08-21 08:12:49 +00:00
if ih == nil { // We were waiting for the peer to tell us what they wanted.
2016-04-04 03:01:31 +00:00
post ( res . Hash [ : ] )
2014-08-21 08:12:49 +00:00
post ( peerID [ : ] )
2013-09-29 06:45:17 +00:00
}
2014-08-21 08:12:49 +00:00
ok = true
return
}
2015-02-21 03:58:28 +00:00
// Wraps a raw connection and provides the interface we want for using the
// connection in the message loop.
2015-03-18 07:28:13 +00:00
type deadlineReader struct {
nc net . Conn
r io . Reader
2014-08-27 23:45:20 +00:00
}
2016-04-19 04:11:11 +00:00
func ( r deadlineReader ) Read ( b [ ] byte ) ( n int , err error ) {
2014-11-20 02:02:20 +00:00
// Keep-alives should be received every 2 mins. Give a bit of gracetime.
2016-04-19 04:11:11 +00:00
err = r . nc . SetReadDeadline ( time . Now ( ) . Add ( 150 * time . Second ) )
2014-08-27 23:45:20 +00:00
if err != nil {
2015-01-21 13:42:13 +00:00
err = fmt . Errorf ( "error setting read deadline: %s" , err )
2014-08-27 23:45:20 +00:00
}
2016-04-19 04:11:11 +00:00
n , err = r . r . Read ( b )
2015-02-21 03:58:28 +00:00
// Convert common errors into io.EOF.
2015-03-18 07:28:13 +00:00
// if err != nil {
// if opError, ok := err.(*net.OpError); ok && opError.Op == "read" && opError.Err == syscall.ECONNRESET {
// err = io.EOF
// } else if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
// if n != 0 {
// panic(n)
// }
// err = io.EOF
// }
// }
return
}
2017-04-04 08:41:08 +00:00
func maybeReceiveEncryptedHandshake ( rw io . ReadWriter , skeys mse . SecretKeyIter ) ( ret io . ReadWriter , encrypted bool , err error ) {
2015-03-18 07:28:13 +00:00
var protocol [ len ( pp . Protocol ) ] byte
_ , err = io . ReadFull ( rw , protocol [ : ] )
2014-09-13 17:45:38 +00:00
if err != nil {
2015-03-18 07:28:13 +00:00
return
}
2016-10-10 05:30:51 +00:00
ret = struct {
io . Reader
io . Writer
} {
2015-03-18 07:28:13 +00:00
io . MultiReader ( bytes . NewReader ( protocol [ : ] ) , rw ) ,
rw ,
}
if string ( protocol [ : ] ) == pp . Protocol {
return
}
encrypted = true
2017-04-04 08:41:08 +00:00
ret , err = mse . ReceiveHandshakeLazy ( ret , skeys )
2015-03-18 07:28:13 +00:00
return
}
2016-04-19 04:11:11 +00:00
func ( cl * Client ) initiateHandshakes ( c * connection , t * Torrent ) ( ok bool , err error ) {
2015-03-18 07:28:13 +00:00
if c . encrypted {
2016-10-10 05:30:51 +00:00
var rw io . ReadWriter
rw , err = mse . InitiateHandshake ( struct {
io . Reader
io . Writer
} { c . r , c . w } , t . infoHash [ : ] , nil )
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 ) {
2015-04-20 07:30:22 +00:00
if ! cl . config . DisableEncryption {
2016-10-10 05:30:51 +00:00
var rw io . ReadWriter
2017-04-04 08:41:08 +00:00
rw , c . encrypted , err = maybeReceiveEncryptedHandshake ( c . rw ( ) , cl . forSkeys )
2016-10-10 05:30:51 +00:00
c . setRW ( rw )
2015-04-20 07:30:22 +00:00
if err != nil {
if err == mse . ErrNoSecretKeyMatch {
err = nil
}
return
2015-03-18 07:28:13 +00:00
}
2014-08-28 00:06:57 +00:00
}
2016-09-16 02:42:41 +00:00
if cl . config . ForceEncryption && ! c . encrypted {
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
c . PeerID = res . peerID
c . completedHandshake = time . Now ( )
return
}
2016-05-16 09:50:10 +00:00
func ( cl * Client ) runInitiatedHandshookConn ( c * connection , t * Torrent ) {
2015-03-18 07:28:13 +00:00
if c . PeerID == cl . peerID {
connsToSelf . Add ( 1 )
addr := c . conn . RemoteAddr ( ) . String ( )
cl . dopplegangerAddrs [ addr ] = struct { } { }
return
2014-08-27 23:45:20 +00:00
}
2017-05-10 03:04:31 +00:00
cl . runHandshookConn ( c , t , true )
2015-03-18 07:28:13 +00:00
}
2016-05-16 09:50:10 +00:00
func ( cl * Client ) runReceivedConn ( c * connection ) {
err := c . conn . SetDeadline ( time . Now ( ) . Add ( 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 {
2016-05-16 09:50:10 +00:00
if cl . config . Debug {
log . Printf ( "error receiving handshakes: %s" , err )
}
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 {
2014-11-16 19:54:00 +00:00
return
}
2015-03-18 07:28:13 +00:00
cl . mu . Lock ( )
defer cl . mu . Unlock ( )
if c . PeerID == cl . peerID {
2016-05-23 16:09:47 +00:00
// Because the remote address is not necessarily the same as its
// client's torrent listen address, we won't record the remote address
// as a doppleganger. Instead, the initiator can record *us* as the
// doppleganger.
2014-08-21 08:12:49 +00:00
return
}
2017-05-10 03:04:31 +00:00
cl . runHandshookConn ( c , t , false )
2015-03-18 07:28:13 +00:00
}
2017-05-10 03:04:31 +00:00
func ( cl * Client ) runHandshookConn ( c * connection , t * Torrent , outgoing bool ) {
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 )
2017-05-10 03:04:31 +00:00
if ! t . addConnection ( c , outgoing ) {
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 {
log . Printf ( "error during connection 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 ) {
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
} ( ) ,
2015-03-25 04:42:14 +00:00
"v" : 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
} ( ) ,
} )
}
2013-10-20 14:07:01 +00:00
if torrent . haveAnyPieces ( ) {
2016-01-04 11:37:49 +00:00
conn . Bitfield ( torrent . bitfield ( ) )
2016-04-19 04:11:11 +00:00
} else if cl . extensionBytes . SupportsFast ( ) && conn . PeerExtensionBytes . SupportsFast ( ) {
2015-03-12 19:21:13 +00:00
conn . Post ( pp . Message {
Type : pp . HaveNone ,
} )
2013-10-20 14:07:01 +00:00
}
2016-04-19 04:11:11 +00:00
if conn . PeerExtensionBytes . SupportsDHT ( ) && cl . extensionBytes . SupportsDHT ( ) && cl . dHT != nil {
2014-08-25 12:12:16 +00:00
conn . Post ( pp . Message {
Type : pp . Port ,
2016-04-19 04:11:11 +00:00
Port : uint16 ( missinggo . AddrPort ( cl . dHT . Addr ( ) ) ) ,
2014-08-25 12:12:16 +00:00
} )
}
2013-09-30 11:51:08 +00:00
}
2016-04-19 04:11:11 +00:00
func ( cl * Client ) peerUnchoked ( torrent * Torrent , conn * connection ) {
2016-01-24 04:21:17 +00:00
conn . updateRequests ( )
2013-09-30 11:51:08 +00:00
}
2016-04-03 08:40:43 +00:00
func ( cl * Client ) connCancel ( t * Torrent , cn * connection , r request ) ( ok bool ) {
2014-05-23 11:01:05 +00:00
ok = cn . Cancel ( r )
if ok {
2014-08-23 17:10:47 +00:00
postedCancels . Add ( 1 )
2014-05-23 11:01:05 +00:00
}
return
}
2016-04-03 08:40:43 +00:00
func ( cl * Client ) connDeleteRequest ( t * Torrent , cn * connection , r request ) bool {
2014-05-23 11:01:05 +00:00
if ! cn . RequestPending ( r ) {
2015-06-22 09:48:30 +00:00
return false
2014-05-23 11:01:05 +00:00
}
delete ( cn . Requests , r )
2015-06-22 09:48:30 +00:00
return true
2014-05-23 11:01:05 +00:00
}
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 )
2014-06-28 09:38:31 +00:00
if err != nil {
2016-07-23 14:34:40 +00:00
return fmt . Errorf ( "error unmarshalling payload: %s: %q" , err , payload )
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 : ] )
2014-12-01 09:32:17 +00:00
c . UsefulChunksReceived ++
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-04-19 04:11:11 +00:00
func ( cl * Client ) sendChunk ( t * Torrent , c * connection , r request ) error {
2015-09-17 02:50:29 +00:00
// Count the chunk being sent, even if it isn't.
2015-06-16 06:57:47 +00:00
b := make ( [ ] byte , r . Length )
2016-04-03 06:50:53 +00:00
p := t . info . Piece ( int ( r . Index ) )
2016-02-20 16:32:59 +00:00
n , err := t . readAt ( b , p . Offset ( ) + int64 ( r . Begin ) )
2015-06-16 06:57:47 +00:00
if n != len ( b ) {
2016-02-20 03:40:28 +00:00
if err == nil {
panic ( "expected error" )
}
return err
2015-06-16 06:57:47 +00:00
}
c . Post ( pp . Message {
Type : pp . Piece ,
Index : r . Index ,
Begin : r . Begin ,
Piece : b ,
} )
2016-02-21 06:22:55 +00:00
c . chunksSent ++
2015-06-16 06:57:47 +00:00
uploadChunksPosted . Add ( 1 )
c . lastChunkSent = time . Now ( )
return nil
}
2016-04-19 04:11:11 +00:00
func ( cl * Client ) openNewConns ( t * Torrent ) {
2016-05-22 12:45:08 +00:00
defer t . updateWantPeersEvent ( )
2016-04-03 06:50:53 +00:00
for len ( t . peers ) != 0 {
2016-07-05 06:23:17 +00:00
if ! t . wantConns ( ) {
2014-12-03 07:07:50 +00:00
return
2014-08-27 23:39:27 +00:00
}
2016-04-19 04:11:11 +00:00
if len ( t . halfOpen ) >= cl . halfOpenLimit {
2014-12-03 07:07:50 +00:00
return
2014-11-21 06:09:55 +00:00
}
var (
2016-01-06 01:19:49 +00:00
k peersKey
2014-11-21 06:09:55 +00:00
p Peer
)
2016-04-03 06:50:53 +00:00
for k , p = range t . peers {
2014-11-21 06:09:55 +00:00
break
2013-09-28 22:11:24 +00:00
}
2016-04-03 06:50:53 +00:00
delete ( t . peers , k )
2016-04-19 04:11:11 +00:00
cl . initiateConn ( p , t )
2013-09-28 22:11:24 +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 ,
peers : make ( map [ peersKey ] Peer ) ,
2016-11-23 00:48:44 +00:00
conns : make ( map [ * connection ] struct { } , 2 * defaultEstablishedConnsPerTorrent ) ,
2014-08-24 20:01:05 +00:00
2016-04-03 06:50:53 +00:00
halfOpen : make ( map [ string ] struct { } ) ,
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 ,
2016-07-05 06:23:17 +00:00
maxEstablishedConns : defaultEstablishedConnsPerTorrent ,
2014-06-26 14:57:07 +00:00
}
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
2017-03-16 14:24:54 +00:00
t = cl . newTorrent ( infoHash , specStorage )
2016-05-09 05:47:39 +00:00
if cl . dHT != nil {
2016-07-23 12:38:31 +00:00
go t . dhtAnnouncer ( )
2016-05-09 05:47:39 +00:00
}
cl . torrents [ infoHash ] = t
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
}
2016-05-22 12:45:08 +00:00
func ( cl * Client ) prepareTrackerAnnounceUnlocked ( announceURL string ) ( blocked bool , urlToUse string , host string , err error ) {
_url , err := url . Parse ( announceURL )
2015-03-10 15:41:41 +00:00
if err != nil {
return
}
2016-05-22 12:45:08 +00:00
hmp := missinggo . SplitHostMaybePort ( _url . Host )
if hmp . Err != nil {
err = hmp . Err
return
2015-03-10 15:41:41 +00:00
}
2016-05-22 12:45:08 +00:00
addr , err := net . ResolveIPAddr ( "ip" , hmp . Host )
2015-03-10 15:41:41 +00:00
if err != nil {
return
}
2015-10-18 13:00:26 +00:00
cl . mu . RLock ( )
_ , blocked = cl . ipBlockRange ( addr . IP )
cl . mu . RUnlock ( )
2016-05-22 12:45:08 +00:00
host = _url . Host
hmp . Host = addr . String ( )
_url . Host = hmp . String ( )
urlToUse = _url . String ( )
2015-03-10 15:41:41 +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
}
2015-02-25 04:42:47 +00:00
if t . numPiecesCompleted ( ) != t . numPieces ( ) {
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
2016-04-19 04:11:11 +00:00
func ( cl * Client ) DHT ( ) * dht . Server {
return cl . dHT
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 ) {
2017-06-29 01:49:55 +00:00
if cl . DHT ( ) == nil {
return
}
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 {
Addr : & net . UDPAddr {
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
}
2016-04-19 04:11:11 +00:00
cl . DHT ( ) . 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
func ( cl * Client ) newConnection ( nc net . Conn ) ( c * connection ) {
c = & connection {
conn : nc ,
Choked : true ,
PeerChoked : true ,
PeerMaxRequests : 250 ,
}
c . setRW ( connStatsReadWriter { nc , & cl . mu , c } )
2016-10-10 06:29:39 +00:00
c . r = rateLimitedReader { cl . downloadLimit , 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 ,
} } )
}