2013-09-26 17:49:15 +08:00
package torrent
import (
2013-09-30 19:51:08 +08:00
"bufio"
2014-09-11 12:20:47 +08:00
"bytes"
2013-09-29 06:11:24 +08:00
"crypto/rand"
2015-03-12 17:06:23 +08:00
"encoding/hex"
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
"log"
"net"
2015-03-10 23:41:41 +08:00
"net/url"
2015-03-18 15:21:00 +08:00
"strconv"
2014-09-14 01:50:15 +08:00
"strings"
2013-10-20 22:07:01 +08:00
"time"
2014-03-20 13:58:09 +08:00
2015-08-06 06:56:36 +08:00
"github.com/anacrolix/missinggo"
2016-03-06 14:26:04 +08:00
"github.com/anacrolix/missinggo/pproffd"
2015-09-06 10:35:56 +08:00
"github.com/anacrolix/missinggo/pubsub"
2016-07-12 14:40:14 +08:00
"github.com/anacrolix/missinggo/slices"
2015-03-20 20:52:53 +08:00
"github.com/anacrolix/sync"
2015-03-26 14:18:08 +08:00
"github.com/anacrolix/utp"
2016-05-19 15:15:10 +08:00
"github.com/dustin/go-humanize"
2015-03-26 14:18:08 +08:00
2015-04-28 13:24:17 +08:00
"github.com/anacrolix/torrent/bencode"
2015-03-20 13:37:44 +08:00
"github.com/anacrolix/torrent/dht"
2016-05-17 14:40:08 +08:00
"github.com/anacrolix/torrent/dht/krpc"
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
)
2014-03-16 23:30:10 +08:00
// Currently doesn't really queue, but should in the future.
2016-04-03 16:40:43 +08:00
func ( cl * Client ) queuePieceCheck ( t * Torrent , pieceIndex int ) {
2016-04-03 14:50:53 +08:00
piece := & t . pieces [ pieceIndex ]
2014-03-20 01:30:08 +08:00
if piece . QueuedForHash {
2013-10-20 22:07:01 +08:00
return
}
2014-03-20 01:30:08 +08:00
piece . QueuedForHash = true
2016-04-04 13:28:25 +08:00
t . publishPieceChange ( pieceIndex )
go cl . verifyPiece ( t , pieceIndex )
2013-10-20 22:07:01 +08:00
}
2015-02-24 22:34:57 +08:00
// Queue a piece check if one isn't already queued, and the piece has never
// been checked before.
2016-04-03 16:40:43 +08:00
func ( cl * Client ) queueFirstHash ( t * Torrent , piece int ) {
2016-04-03 14:50:53 +08:00
p := & t . pieces [ piece ]
2015-03-10 23:41:21 +08:00
if p . EverHashed || p . Hashing || p . QueuedForHash || t . pieceComplete ( piece ) {
2014-09-14 01:50:15 +08:00
return
}
2016-01-04 19:34:24 +08:00
cl . queuePieceCheck ( t , piece )
2014-09-14 01:50:15 +08:00
}
2016-05-03 12:58:26 +08:00
// Clients contain zero or more Torrents. A Client manages a blocklist, the
2015-06-03 11:30:55 +08:00
// TCP/UDP protocol ports, and DHT as desired.
2013-10-06 15:01:39 +08:00
type Client struct {
2016-05-11 19:11:52 +08:00
halfOpenLimit int
peerID [ 20 ] byte
// The net.Addr.String part that should be common to all active listeners.
listenAddr string
tcpListener net . Listener
2015-04-27 12:05:27 +08:00
utpSock * utp . Socket
dHT * dht . Server
2015-09-23 16:25:22 +08:00
ipBlockList iplist . Ranger
2015-04-27 12:05:27 +08:00
config Config
extensionBytes peerExtensionBytes
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 { }
2015-02-25 11:48:39 +08:00
2016-09-02 13:10:57 +08:00
defaultStorage * storage . Client
2013-09-29 06:11:24 +08:00
2016-03-05 16:36:21 +08:00
mu sync . RWMutex
event sync . Cond
closed missinggo . Event
2013-10-20 22:07:01 +08:00
2016-04-04 11:01:31 +08:00
torrents map [ metainfo . Hash ] * Torrent
2015-02-25 08:25:22 +08:00
}
2014-08-25 03:24:18 +08:00
2016-07-29 22:37:52 +08:00
func ( cl * Client ) BadPeerIPs ( ) [ ] string {
cl . mu . RLock ( )
defer cl . mu . RUnlock ( )
return slices . FromMapKeys ( cl . badPeerIPs ) . ( [ ] string )
}
2016-04-19 12:11:11 +08:00
func ( cl * Client ) IPBlockList ( ) iplist . Ranger {
cl . mu . Lock ( )
defer cl . mu . Unlock ( )
return cl . ipBlockList
2013-09-26 17:49:15 +08:00
}
2016-04-19 12:11:11 +08:00
func ( cl * Client ) SetIPBlockList ( list iplist . Ranger ) {
cl . mu . Lock ( )
defer cl . mu . Unlock ( )
cl . ipBlockList = list
if cl . dHT != nil {
cl . dHT . SetIPBlockList ( list )
2014-11-30 10:33:17 +08:00
}
2014-11-29 09:41:53 +08:00
}
2016-04-19 12:11:11 +08:00
func ( cl * Client ) PeerID ( ) string {
return string ( cl . peerID [ : ] )
2014-11-17 03:54:43 +08:00
}
2016-05-11 19:11:52 +08:00
type torrentAddr string
func ( me torrentAddr ) Network ( ) string { return "" }
func ( me torrentAddr ) String ( ) string { return string ( me ) }
func ( cl * Client ) ListenAddr ( ) net . Addr {
if cl . listenAddr == "" {
return nil
2014-11-17 03:16:26 +08:00
}
2016-05-11 19:11:52 +08:00
return torrentAddr ( cl . listenAddr )
2014-08-21 16:07:06 +08:00
}
2016-04-03 16:40:43 +08:00
func ( cl * Client ) sortedTorrents ( ) ( ret [ ] * Torrent ) {
2016-07-29 22:37:52 +08:00
return slices . Sort ( slices . FromMapElems ( cl . torrents ) , func ( l , r metainfo . Hash ) bool {
return l . AsString ( ) < r . AsString ( )
} ) . ( [ ] * Torrent )
2014-11-19 11:56:50 +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 ) {
w := bufio . NewWriter ( _w )
defer w . Flush ( )
2015-02-25 11:52:19 +08:00
if addr := cl . ListenAddr ( ) ; addr != nil {
2016-07-29 22:37:52 +08:00
fmt . Fprintf ( w , "Listening on %s\n" , addr )
2015-02-25 11:52:19 +08:00
} else {
2015-03-10 23:39:01 +08:00
fmt . Fprintln ( w , "Not listening!" )
2015-02-25 11:52:19 +08:00
}
2016-07-29 22:37:52 +08:00
fmt . Fprintf ( w , "Peer ID: %+q\n" , cl . PeerID ( ) )
fmt . Fprintf ( w , "Banned IPs: %d\n" , len ( cl . BadPeerIPs ( ) ) )
if dht := cl . DHT ( ) ; dht != nil {
dhtStats := dht . Stats ( )
2015-08-03 22:31:53 +08:00
fmt . Fprintf ( w , "DHT nodes: %d (%d good, %d banned)\n" , dhtStats . Nodes , dhtStats . GoodNodes , dhtStats . BadNodes )
2016-07-29 22:37:52 +08:00
fmt . Fprintf ( w , "DHT Server ID: %x\n" , dht . ID ( ) )
fmt . Fprintf ( w , "DHT port: %d\n" , missinggo . AddrPort ( dht . Addr ( ) ) )
2015-04-01 14:29:55 +08:00
fmt . Fprintf ( w , "DHT announces: %d\n" , dhtStats . ConfirmedAnnounces )
fmt . Fprintf ( w , "Outstanding transactions: %d\n" , dhtStats . OutstandingTransactions )
2014-07-22 23:50:49 +08:00
}
2016-07-29 22:37:52 +08:00
fmt . Fprintf ( w , "# Torrents: %d\n" , len ( cl . Torrents ( ) ) )
2014-07-16 15:07:28 +08:00
fmt . Fprintln ( w )
2016-07-29 22:48:15 +08:00
for _ , t := range slices . Sort ( append ( [ ] * Torrent ( nil ) , cl . Torrents ( ) ... ) , func ( l , r * Torrent ) bool {
2016-07-29 22:37:52 +08:00
return l . InfoHash ( ) . AsString ( ) < r . InfoHash ( ) . AsString ( )
} ) . ( [ ] * Torrent ) {
if t . Name ( ) == "" {
2014-11-19 04:32:51 +08:00
fmt . Fprint ( w , "<unknown name>" )
} else {
2016-07-29 22:37:52 +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" )
2016-07-29 22:37:52 +08:00
if t . Info ( ) != nil {
fmt . Fprintf ( w , "%f%% of %d bytes (%s)" , 100 * ( 1 - float64 ( t . BytesMissing ( ) ) / 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
}
}
2016-05-11 19:11:52 +08:00
func listenUTP ( networkSuffix , addr string ) ( * utp . Socket , error ) {
return utp . NewSocket ( "udp" + networkSuffix , addr )
}
func listenTCP ( networkSuffix , addr string ) ( net . Listener , error ) {
return net . Listen ( "tcp" + networkSuffix , addr )
}
func listenBothSameDynamicPort ( networkSuffix , host string ) ( tcpL net . Listener , utpSock * utp . Socket , listenedAddr string , err error ) {
for {
tcpL , err = listenTCP ( networkSuffix , net . JoinHostPort ( host , "0" ) )
if err != nil {
return
}
listenedAddr = tcpL . Addr ( ) . String ( )
utpSock , err = listenUTP ( networkSuffix , listenedAddr )
if err == nil {
return
}
tcpL . Close ( )
if ! strings . Contains ( err . Error ( ) , "address already in use" ) {
return
}
}
}
2016-05-24 17:45:42 +08:00
// Listen to enabled protocols, ensuring ports match.
2016-05-11 19:11:52 +08:00
func listen ( tcp , utp bool , networkSuffix , addr string ) ( tcpL net . Listener , utpSock * utp . Socket , listenedAddr string , err error ) {
if addr == "" {
addr = ":50007"
}
2016-08-30 12:19:29 +08:00
if tcp && utp {
var host string
var port int
host , port , err = missinggo . ParseHostPort ( addr )
if err != nil {
return
}
if port == 0 {
// If both protocols are active, they need to have the same port.
return listenBothSameDynamicPort ( networkSuffix , host )
}
2016-05-11 19:11:52 +08:00
}
2016-05-24 17:45:42 +08:00
defer func ( ) {
if err != nil {
listenedAddr = ""
}
} ( )
2016-05-11 19:11:52 +08:00
if tcp {
tcpL , err = listenTCP ( networkSuffix , addr )
if err != nil {
return
}
2016-05-24 17:45:42 +08:00
defer func ( ) {
if err != nil {
tcpL . Close ( )
}
} ( )
2016-05-24 13:18:04 +08:00
listenedAddr = tcpL . Addr ( ) . String ( )
2016-05-11 19:11:52 +08:00
}
if utp {
utpSock , err = listenUTP ( networkSuffix , addr )
2016-05-24 17:45:42 +08:00
if err != nil {
2016-05-24 13:24:29 +08:00
return
2016-05-11 19:11:52 +08:00
}
2016-05-24 13:18:04 +08:00
listenedAddr = utpSock . Addr ( ) . String ( )
2016-05-11 19:11:52 +08:00
}
return
}
2015-06-03 11:30:55 +08:00
// Creates a new client.
2014-08-21 16:07:06 +08:00
func NewClient ( cfg * Config ) ( cl * Client , err error ) {
if cfg == nil {
cfg = & Config { }
2013-10-14 22:39:12 +08:00
}
2014-08-21 16:07:06 +08:00
2015-04-01 11:30:22 +08:00
defer func ( ) {
if err != nil {
cl = nil
}
} ( )
2014-08-21 16:07:06 +08:00
cl = & Client {
2016-07-05 14:23:17 +08:00
halfOpenLimit : defaultHalfOpenConnsPerTorrent ,
2016-03-28 17:38:30 +08:00
config : * cfg ,
2015-03-18 15:29:51 +08:00
dopplegangerAddrs : make ( map [ string ] struct { } ) ,
2016-04-04 11:01:31 +08:00
torrents : make ( map [ metainfo . Hash ] * Torrent ) ,
2014-08-21 16:07:06 +08:00
}
2016-03-30 16:11:55 +08:00
missinggo . CopyExact ( & cl . extensionBytes , defaultExtensionBytes )
2014-08-21 16:07:06 +08:00
cl . event . L = & cl . mu
2016-09-02 13:10:57 +08:00
storageImpl := cfg . DefaultStorage
if storageImpl == nil {
storageImpl = storage . NewFile ( cfg . DataDir )
2015-02-25 12:41:13 +08:00
}
2016-09-02 13:10:57 +08:00
cl . defaultStorage = storage . NewClient ( storageImpl )
2015-08-03 23:07:22 +08:00
if cfg . IPBlocklist != nil {
cl . ipBlockList = cfg . IPBlocklist
2014-12-02 06:39:09 +08:00
}
2014-11-17 03:54:43 +08:00
if cfg . PeerID != "" {
2016-03-30 16:11:55 +08:00
missinggo . CopyExact ( & cl . peerID , cfg . PeerID )
2014-11-17 03:54:43 +08:00
} else {
2015-03-08 14:28:14 +08:00
o := copy ( cl . peerID [ : ] , bep20 )
2014-11-17 03:54:43 +08:00
_ , err = rand . Read ( cl . peerID [ o : ] )
if err != nil {
panic ( "error generating peer id" )
}
2013-09-29 06:11:24 +08:00
}
2014-08-21 16:07:06 +08:00
2016-05-11 19:11:52 +08:00
cl . tcpListener , cl . utpSock , cl . listenAddr , err = listen (
! cl . config . DisableTCP ,
! cl . config . DisableUTP ,
func ( ) string {
2015-08-05 00:41:50 +08:00
if cl . config . DisableIPv6 {
2016-05-11 19:11:52 +08:00
return "4"
2015-08-05 00:41:50 +08:00
} else {
2016-05-11 19:11:52 +08:00
return ""
2015-08-05 00:41:50 +08:00
}
2016-05-11 19:11:52 +08:00
} ( ) ,
cl . config . ListenAddr )
if err != nil {
return
2014-11-17 03:29:31 +08:00
}
2016-05-11 19:11:52 +08:00
if cl . tcpListener != nil {
go cl . acceptConnections ( cl . tcpListener , false )
}
if cl . utpSock != nil {
2015-01-10 21:16:19 +08:00
go cl . acceptConnections ( cl . utpSock , true )
2014-03-17 22:44:22 +08:00
}
2014-08-21 16:07:06 +08:00
if ! cfg . NoDHT {
2014-11-29 02:13:08 +08:00
dhtCfg := cfg . DHTConfig
2015-08-03 22:43:46 +08:00
if dhtCfg . IPBlocklist == nil {
dhtCfg . IPBlocklist = cl . ipBlockList
2014-11-20 10:02:20 +08:00
}
2016-05-24 17:46:24 +08:00
dhtCfg . Addr = firstNonEmptyString ( dhtCfg . Addr , cl . listenAddr , cl . config . ListenAddr )
2015-01-10 21:16:19 +08:00
if dhtCfg . Conn == nil && cl . utpSock != nil {
2015-10-03 22:02:14 +08:00
dhtCfg . Conn = cl . utpSock
2014-11-29 02:13:08 +08:00
}
2016-01-16 21:12:53 +08:00
cl . dHT , err = dht . NewServer ( & dhtCfg )
2014-08-21 16:07:06 +08:00
if err != nil {
return
}
}
return
2014-03-17 22:44:22 +08:00
}
2016-05-24 17:46:24 +08:00
func firstNonEmptyString ( ss ... string ) string {
for _ , s := range ss {
if s != "" {
return s
}
}
return ""
}
2014-04-09 00:36:05 +08:00
// Stops the client. All connections to peers are closed and all activity will
// come to a halt.
2016-04-19 12:11:11 +08:00
func ( cl * Client ) Close ( ) {
cl . mu . Lock ( )
defer cl . mu . Unlock ( )
cl . closed . Set ( )
if cl . dHT != nil {
cl . dHT . Close ( )
}
2016-05-11 19:11:52 +08:00
if cl . utpSock != nil {
2016-07-23 22:24:44 +08:00
cl . utpSock . CloseNow ( )
2016-05-11 19:11:52 +08:00
}
if cl . tcpListener != nil {
cl . tcpListener . Close ( )
2014-11-21 14:07:04 +08:00
}
2016-04-19 12:11:11 +08:00
for _ , t := range cl . torrents {
2015-02-09 21:12:29 +08:00
t . close ( )
2014-03-18 19:39:33 +08:00
}
2016-04-19 12:11:11 +08:00
cl . event . Broadcast ( )
2014-03-18 19:39:33 +08:00
}
2014-12-01 17:27:11 +08:00
var ipv6BlockRange = iplist . Range { Description : "non-IPv4 address" }
2015-10-18 21:00:26 +08:00
func ( cl * Client ) ipBlockRange ( ip net . IP ) ( r iplist . Range , blocked bool ) {
2014-11-29 09:41:53 +08:00
if cl . ipBlockList == nil {
2014-11-30 10:33:17 +08:00
return
2014-11-29 09:41:53 +08:00
}
2015-04-01 14:36:51 +08:00
ip4 := ip . To4 ( )
2015-10-18 21:00:26 +08:00
// If blocklists are enabled, then block non-IPv4 addresses, because
// blocklists do not yet support IPv6.
2015-04-01 14:36:51 +08:00
if ip4 == nil {
2015-11-13 19:33:50 +08:00
if missinggo . CryHeard ( ) {
log . Printf ( "blocking non-IPv4 address: %s" , ip )
}
2015-10-18 21:00:26 +08:00
r = ipv6BlockRange
blocked = true
2014-12-01 17:27:11 +08:00
return
}
2015-10-18 21:00:26 +08:00
return cl . ipBlockList . Lookup ( ip4 )
2014-11-29 09:41:53 +08:00
}
2015-03-18 15:36:27 +08:00
func ( cl * Client ) waitAccept ( ) {
for {
for _ , t := range cl . torrents {
2016-07-05 14:23:17 +08:00
if t . wantConns ( ) {
2015-03-18 15:36:27 +08:00
return
}
}
2016-03-05 16:36:21 +08:00
if cl . closed . IsSet ( ) {
2015-08-03 23:15:09 +08:00
return
}
2015-03-18 15:36:27 +08:00
cl . event . Wait ( )
}
}
2014-11-17 03:29:31 +08:00
func ( cl * Client ) acceptConnections ( l net . Listener , utp bool ) {
2016-07-05 22:38:43 +08:00
cl . mu . Lock ( )
defer cl . mu . Unlock ( )
2014-03-17 22:44:22 +08:00
for {
2015-03-18 15:36:27 +08:00
cl . waitAccept ( )
2016-07-05 22:38:43 +08:00
cl . mu . Unlock ( )
2014-11-17 03:29:31 +08:00
conn , err := l . Accept ( )
2016-03-06 14:26:04 +08:00
conn = pproffd . WrapNetConn ( conn )
2016-07-05 22:38:43 +08:00
cl . mu . Lock ( )
2016-03-05 16:36:21 +08:00
if cl . closed . IsSet ( ) {
2014-07-03 23:44:15 +08:00
if conn != nil {
conn . Close ( )
}
2014-03-18 19:39:33 +08:00
return
}
2014-03-17 22:44:22 +08:00
if err != nil {
log . Print ( err )
2016-03-05 16:36:21 +08:00
// I think something harsher should happen here? Our accept
// routine just fucked off.
2014-03-17 22:44:22 +08:00
return
}
2015-06-29 22:35:47 +08:00
if utp {
acceptUTP . Add ( 1 )
} else {
acceptTCP . Add ( 1 )
}
2016-05-24 00:09:47 +08:00
reject := cl . badPeerIPPort (
missinggo . AddrIP ( conn . RemoteAddr ( ) ) ,
missinggo . AddrPort ( conn . RemoteAddr ( ) ) )
if reject {
2015-06-29 22:35:47 +08:00
acceptReject . Add ( 1 )
2014-12-26 14:18:36 +08:00
conn . Close ( )
2014-11-29 09:41:53 +08:00
continue
}
2015-03-18 15:28:13 +08:00
go cl . incomingConnection ( conn , utp )
}
}
func ( cl * Client ) incomingConnection ( nc net . Conn , utp bool ) {
defer nc . Close ( )
if tc , ok := nc . ( * net . TCPConn ) ; ok {
tc . SetLinger ( 0 )
}
2016-07-12 14:42:04 +08:00
c := newConnection ( nc , & cl . mu )
2015-03-18 15:28:13 +08:00
c . Discovery = peerSourceIncoming
c . uTP = utp
2016-05-16 17:50:10 +08:00
cl . runReceivedConn ( c )
2013-09-26 17:49:15 +08:00
}
2015-03-20 07:52:01 +08:00
// Returns a handle to the given torrent, if it's present in the client.
2016-04-04 11:01:31 +08:00
func ( cl * Client ) Torrent ( ih metainfo . Hash ) ( t * Torrent , ok bool ) {
2015-03-18 15:28:13 +08:00
cl . mu . Lock ( )
defer cl . mu . Unlock ( )
2016-04-03 16:40:43 +08:00
t , ok = cl . torrents [ ih ]
2015-03-18 15:28:13 +08:00
return
}
2016-04-19 12:11:11 +08:00
func ( cl * Client ) torrent ( ih metainfo . Hash ) * Torrent {
return cl . torrents [ ih ]
2013-09-29 06:11:24 +08:00
}
2014-11-17 13:27:01 +08:00
type dialResult struct {
2015-03-18 15:28:13 +08:00
Conn net . Conn
UTP bool
2014-11-17 13:27:01 +08:00
}
2016-04-03 16:40:43 +08:00
func doDial ( dial func ( addr string , t * Torrent ) ( net . Conn , error ) , ch chan dialResult , utp bool , addr string , t * Torrent ) {
2015-03-18 15:28:13 +08:00
conn , err := dial ( addr , t )
2014-11-18 08:04:33 +08:00
if err != nil {
2014-12-26 14:18:36 +08:00
if conn != nil {
conn . Close ( )
}
2014-11-18 08:04:33 +08:00
conn = nil // Pedantic
}
2014-11-17 13:27:01 +08:00
ch <- dialResult { conn , utp }
2014-11-17 15:44:06 +08:00
if err == nil {
successfulDials . Add ( 1 )
return
}
unsuccessfulDials . Add ( 1 )
2014-11-17 13:27:01 +08:00
}
2014-11-19 11:53:00 +08:00
func reducedDialTimeout ( max time . Duration , halfOpenLimit int , pendingPeers int ) ( ret time . Duration ) {
ret = max / time . Duration ( ( pendingPeers + halfOpenLimit ) / halfOpenLimit )
if ret < minDialTimeout {
ret = minDialTimeout
}
return
2014-11-18 08:04:09 +08:00
}
2015-09-17 10:54:03 +08:00
// Returns whether an address is known to connect to a client with our own ID.
2016-04-19 12:11:11 +08:00
func ( cl * Client ) dopplegangerAddr ( addr string ) bool {
_ , ok := cl . dopplegangerAddrs [ addr ]
2015-03-18 15:29:51 +08:00
return ok
}
2014-07-22 19:45:12 +08:00
// Start the process of connecting to the given peer for the given torrent if
// appropriate.
2016-04-19 12:11:11 +08:00
func ( cl * Client ) initiateConn ( peer Peer , t * Torrent ) {
if peer . Id == cl . peerID {
2013-09-29 06:11:24 +08:00
return
}
2016-05-24 00:09:47 +08:00
if cl . badPeerIPPort ( peer . IP , peer . Port ) {
2014-11-17 03:30:44 +08:00
return
2014-08-28 07:35:13 +08:00
}
2016-05-24 00:09:47 +08:00
addr := net . JoinHostPort ( peer . IP . String ( ) , fmt . Sprintf ( "%d" , peer . Port ) )
if t . addrActive ( addr ) {
2014-11-29 09:41:53 +08:00
return
}
2016-04-03 14:50:53 +08:00
t . halfOpen [ addr ] = struct { } { }
2016-04-19 12:11:11 +08:00
go cl . outgoingConnection ( t , addr , peer . Source )
2015-03-18 15:28:13 +08:00
}
2016-04-19 12:11:11 +08:00
func ( cl * Client ) dialTimeout ( t * Torrent ) time . Duration {
cl . mu . Lock ( )
2016-04-03 14:50:53 +08:00
pendingPeers := len ( t . peers )
2016-04-19 12:11:11 +08:00
cl . mu . Unlock ( )
return reducedDialTimeout ( nominalDialTimeout , cl . halfOpenLimit , pendingPeers )
2015-03-18 15:28:13 +08:00
}
2016-04-19 12:11:11 +08:00
func ( cl * Client ) dialTCP ( addr string , t * Torrent ) ( c net . Conn , err error ) {
c , err = net . DialTimeout ( "tcp" , addr , cl . dialTimeout ( t ) )
2015-03-18 15:28:13 +08:00
if err == nil {
c . ( * net . TCPConn ) . SetLinger ( 0 )
}
2016-06-20 15:51:40 +08:00
c = pproffd . WrapNetConn ( c )
2015-03-18 15:28:13 +08:00
return
}
2016-04-19 12:11:11 +08:00
func ( cl * Client ) dialUTP ( addr string , t * Torrent ) ( c net . Conn , err error ) {
return cl . utpSock . DialTimeout ( addr , cl . dialTimeout ( t ) )
2015-03-18 15:28:13 +08:00
}
2015-08-02 02:04:42 +08:00
// Returns a connection over UTP or TCP, whichever is first to connect.
2016-04-19 12:11:11 +08:00
func ( cl * Client ) dialFirst ( addr string , t * Torrent ) ( conn net . Conn , utp bool ) {
2015-03-18 15:28:13 +08:00
// Initiate connections via TCP and UTP simultaneously. Use the first one
// that succeeds.
left := 0
2016-04-19 12:11:11 +08:00
if ! cl . config . DisableUTP {
2015-03-18 15:28:13 +08:00
left ++
}
2016-04-19 12:11:11 +08:00
if ! cl . config . DisableTCP {
2015-03-18 15:28:13 +08:00
left ++
}
resCh := make ( chan dialResult , left )
2016-04-19 12:11:11 +08:00
if ! cl . config . DisableUTP {
go doDial ( cl . dialUTP , resCh , true , addr , t )
2015-03-18 15:28:13 +08:00
}
2016-04-19 12:11:11 +08:00
if ! cl . config . DisableTCP {
go doDial ( cl . dialTCP , resCh , false , addr , t )
2015-03-18 15:28:13 +08:00
}
var res dialResult
// Wait for a successful connection.
for ; left > 0 && res . Conn == nil ; left -- {
res = <- resCh
}
if left > 0 {
// There are still incompleted dials.
2014-04-03 20:16:59 +08:00
go func ( ) {
2015-03-18 15:28:13 +08:00
for ; left > 0 ; left -- {
conn := ( <- resCh ) . Conn
if conn != nil {
conn . Close ( )
}
2014-04-03 20:16:59 +08:00
}
} ( )
2015-03-18 15:28:13 +08:00
}
conn = res . Conn
utp = res . UTP
return
}
2016-04-19 12:11:11 +08:00
func ( cl * Client ) noLongerHalfOpen ( t * Torrent , addr string ) {
2016-04-03 14:50:53 +08:00
if _ , ok := t . halfOpen [ addr ] ; ! ok {
2015-03-18 15:28:13 +08:00
panic ( "invariant broken" )
}
2016-04-03 14:50:53 +08:00
delete ( t . halfOpen , addr )
2016-04-19 12:11:11 +08:00
cl . openNewConns ( t )
2015-03-18 15:28:13 +08:00
}
2016-03-02 20:27:46 +08:00
// Performs initiator handshakes and returns a connection. Returns nil
// *connection if no connection for valid reasons.
2016-04-19 12:11:11 +08:00
func ( cl * Client ) handshakesConnection ( nc net . Conn , t * Torrent , encrypted , utp bool ) ( c * connection , err error ) {
2016-07-12 14:42:04 +08:00
c = newConnection ( nc , & cl . mu )
2015-08-02 02:04:42 +08:00
c . encrypted = encrypted
c . uTP = utp
err = nc . SetDeadline ( time . Now ( ) . Add ( handshakesTimeout ) )
if err != nil {
return
}
2016-04-19 12:11:11 +08:00
ok , err := cl . initiateHandshakes ( c , t )
2015-08-02 02:04:42 +08:00
if ! ok {
c = nil
}
return
}
2015-03-18 15:28:13 +08:00
// Returns nil connection and nil error if no connection could be established
// for valid reasons.
2016-04-19 12:11:11 +08:00
func ( cl * Client ) establishOutgoingConn ( t * Torrent , addr string ) ( c * connection , err error ) {
nc , utp := cl . dialFirst ( addr , t )
2015-03-18 15:28:13 +08:00
if nc == nil {
return
}
2016-09-16 10:42:41 +08:00
encryptFirst := ! cl . config . DisableEncryption && ! cl . config . PreferNoEncryption
c , err = cl . handshakesConnection ( nc , t , encryptFirst , utp )
2015-03-18 15:28:13 +08:00
if err != nil {
nc . Close ( )
return
} else if c != nil {
return
}
nc . Close ( )
2016-09-16 10:42:41 +08:00
if cl . config . DisableEncryption || cl . config . ForceEncryption {
// There's no alternate encryption case to try.
2015-06-08 16:16:01 +08:00
return
}
2016-09-16 10:42:41 +08:00
// Try again with encryption if we didn't earlier, or without if we did,
// using whichever protocol type worked last time.
2015-03-18 15:28:13 +08:00
if utp {
2016-04-19 12:11:11 +08:00
nc , err = cl . dialUTP ( addr , t )
2015-03-18 15:28:13 +08:00
} else {
2016-04-19 12:11:11 +08:00
nc , err = cl . dialTCP ( addr , t )
2015-03-18 15:28:13 +08:00
}
if err != nil {
err = fmt . Errorf ( "error dialing for unencrypted connection: %s" , err )
return
}
2016-09-16 10:42:41 +08:00
c , err = cl . handshakesConnection ( nc , t , ! encryptFirst , utp )
2016-03-02 20:27:46 +08:00
if err != nil || c == nil {
2015-03-18 15:28:13 +08:00
nc . Close ( )
}
return
}
2014-11-17 13:27:01 +08:00
2015-03-18 15:28:13 +08:00
// Called to dial out and run a connection. The addr we're given is already
// considered half-open.
2016-04-19 12:11:11 +08:00
func ( cl * Client ) outgoingConnection ( t * Torrent , addr string , ps peerSource ) {
c , err := cl . establishOutgoingConn ( t , addr )
cl . mu . Lock ( )
defer cl . mu . Unlock ( )
2015-03-18 15:28:13 +08:00
// Don't release lock between here and addConnection, unless it's for
// failure.
2016-04-19 12:11:11 +08:00
cl . noLongerHalfOpen ( t , addr )
2015-03-18 15:28:13 +08:00
if err != nil {
2016-04-19 12:11:11 +08:00
if cl . config . Debug {
2016-03-22 10:10:18 +08:00
log . Printf ( "error establishing outgoing connection: %s" , err )
}
2015-03-18 15:28:13 +08:00
return
}
if c == nil {
return
}
defer c . Close ( )
c . Discovery = ps
2016-05-16 17:50:10 +08:00
cl . runInitiatedHandshookConn ( c , t )
2013-09-29 06:11:24 +08:00
}
2014-11-17 03:16:26 +08:00
// The port number for incoming peer connections. 0 if the client isn't
// listening.
2014-06-29 16:57:49 +08:00
func ( cl * Client ) incomingPeerPort ( ) int {
2016-05-11 19:11:52 +08:00
if cl . listenAddr == "" {
2014-06-29 16:57:49 +08:00
return 0
}
2016-05-11 19:11:52 +08:00
_ , port , err := missinggo . ParseHostPort ( cl . listenAddr )
if err != nil {
panic ( err )
}
return port
2014-06-29 16:57:49 +08:00
}
2014-11-17 03:16:26 +08: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 19:45:12 +08:00
func addrCompactIP ( addr net . Addr ) ( string , error ) {
2014-11-17 03:16:26 +08: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 19:45:12 +08:00
}
2014-11-17 03:16:26 +08:00
return string ( v4 ) , nil
2014-07-22 19:45:12 +08:00
}
2014-11-17 03:16:26 +08:00
return string ( ip . To16 ( ) ) , nil
2014-07-22 19:45:12 +08:00
}
2015-03-13 03:21:13 +08:00
func handshakeWriter ( w io . Writer , bb <- chan [ ] byte , done chan <- error ) {
2014-08-21 16:12:49 +08:00
var err error
for b := range bb {
_ , err = w . Write ( b )
if err != nil {
break
}
}
done <- err
}
2015-03-12 17:04:44 +08:00
type (
peerExtensionBytes [ 8 ] byte
peerID [ 20 ] byte
)
2014-08-21 16:12:49 +08:00
2016-04-19 12:11:11 +08:00
func ( pex * peerExtensionBytes ) SupportsExtended ( ) bool {
return pex [ 5 ] & 0x10 != 0
2015-03-13 03:21:13 +08:00
}
2016-04-19 12:11:11 +08:00
func ( pex * peerExtensionBytes ) SupportsDHT ( ) bool {
return pex [ 7 ] & 0x01 != 0
2015-03-13 03:21:13 +08:00
}
2016-04-19 12:11:11 +08:00
func ( pex * peerExtensionBytes ) SupportsFast ( ) bool {
return pex [ 7 ] & 0x04 != 0
2015-03-13 03:21:13 +08:00
}
2014-08-21 16:12:49 +08:00
type handshakeResult struct {
peerExtensionBytes
peerID
2016-04-04 11:01:31 +08:00
metainfo . Hash
2014-08-21 16:12:49 +08:00
}
2015-02-09 21:16:01 +08: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 11:01:31 +08:00
func handshake ( sock io . ReadWriter , ih * metainfo . Hash , peerID [ 20 ] byte , extensions peerExtensionBytes ) ( res handshakeResult , ok bool , err error ) {
2014-08-21 16:12:49 +08: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 19:01:56 +08:00
defer func ( ) {
2014-08-21 16:12:49 +08: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 15:28:13 +08:00
err = fmt . Errorf ( "error writing: %s" , err )
2014-08-21 16:12:49 +08:00
}
2014-03-20 19:01:56 +08:00
} ( )
2014-08-21 16:12:49 +08:00
post := func ( bb [ ] byte ) {
select {
case postCh <- bb :
default :
panic ( "mustn't block while posting" )
}
2014-03-20 21:14:17 +08:00
}
2014-08-21 16:12:49 +08:00
post ( [ ] byte ( pp . Protocol ) )
2015-03-13 03:21:13 +08:00
post ( extensions [ : ] )
2014-08-21 16:12:49 +08: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 22:07:01 +08:00
if err != nil {
2014-08-21 16:12:49 +08:00
err = nil
2013-10-14 22:39:12 +08:00
return
2013-09-29 14:45:17 +08:00
}
2014-05-21 16:01:58 +08:00
if string ( b [ : 20 ] ) != pp . Protocol {
2013-09-29 14:45:17 +08:00
return
}
2016-03-30 16:11:55 +08:00
missinggo . CopyExact ( & res . peerExtensionBytes , b [ 20 : 28 ] )
2016-04-04 11:01:31 +08:00
missinggo . CopyExact ( & res . Hash , b [ 28 : 48 ] )
2016-03-30 16:11:55 +08:00
missinggo . CopyExact ( & res . peerID , b [ 48 : 68 ] )
2015-03-12 17:06:23 +08:00
peerExtensions . Add ( hex . EncodeToString ( res . peerExtensionBytes [ : ] ) , 1 )
2014-08-21 16:12:49 +08:00
2015-03-12 17:06:23 +08: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 16:12:49 +08:00
if ih == nil { // We were waiting for the peer to tell us what they wanted.
2016-04-04 11:01:31 +08:00
post ( res . Hash [ : ] )
2014-08-21 16:12:49 +08:00
post ( peerID [ : ] )
2013-09-29 14:45:17 +08:00
}
2014-08-21 16:12:49 +08:00
ok = true
return
}
2015-02-21 11:58:28 +08:00
// Wraps a raw connection and provides the interface we want for using the
// connection in the message loop.
2015-03-18 15:28:13 +08:00
type deadlineReader struct {
nc net . Conn
r io . Reader
2014-08-28 07:45:20 +08:00
}
2016-04-19 12:11:11 +08:00
func ( r deadlineReader ) Read ( b [ ] byte ) ( n int , err error ) {
2014-11-20 10:02:20 +08:00
// Keep-alives should be received every 2 mins. Give a bit of gracetime.
2016-04-19 12:11:11 +08:00
err = r . nc . SetReadDeadline ( time . Now ( ) . Add ( 150 * time . Second ) )
2014-08-28 07:45:20 +08:00
if err != nil {
2015-01-21 21:42:13 +08:00
err = fmt . Errorf ( "error setting read deadline: %s" , err )
2014-08-28 07:45:20 +08:00
}
2016-04-19 12:11:11 +08:00
n , err = r . r . Read ( b )
2015-02-21 11:58:28 +08:00
// Convert common errors into io.EOF.
2015-03-18 15:28:13 +08: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
}
type readWriter struct {
io . Reader
io . Writer
}
func maybeReceiveEncryptedHandshake ( rw io . ReadWriter , skeys [ ] [ ] byte ) ( ret io . ReadWriter , encrypted bool , err error ) {
var protocol [ len ( pp . Protocol ) ] byte
_ , err = io . ReadFull ( rw , protocol [ : ] )
2014-09-14 01:45:38 +08:00
if err != nil {
2015-03-18 15:28:13 +08:00
return
}
ret = readWriter {
io . MultiReader ( bytes . NewReader ( protocol [ : ] ) , rw ) ,
rw ,
}
if string ( protocol [ : ] ) == pp . Protocol {
return
}
encrypted = true
ret , err = mse . ReceiveHandshake ( ret , skeys )
return
}
func ( cl * Client ) receiveSkeys ( ) ( ret [ ] [ ] byte ) {
for ih := range cl . torrents {
ret = append ( ret , ih [ : ] )
}
return
}
2016-04-19 12:11:11 +08:00
func ( cl * Client ) initiateHandshakes ( c * connection , t * Torrent ) ( ok bool , err error ) {
2015-03-18 15:28:13 +08:00
if c . encrypted {
2016-04-03 16:40:43 +08:00
c . rw , err = mse . InitiateHandshake ( c . rw , t . infoHash [ : ] , nil )
2015-03-18 15:28:13 +08:00
if err != nil {
return
2014-09-14 01:45:38 +08:00
}
}
2016-04-19 12:11:11 +08:00
ih , ok , err := cl . connBTHandshake ( c , & t . infoHash )
2016-04-03 16:40:43 +08:00
if ih != t . infoHash {
2015-03-18 15:28:13 +08:00
ok = false
}
2014-08-28 07:45:20 +08:00
return
}
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 ) {
2015-03-18 15:28:13 +08:00
cl . mu . Lock ( )
skeys := cl . receiveSkeys ( )
cl . mu . Unlock ( )
2015-04-20 15:30:22 +08:00
if ! cl . config . DisableEncryption {
c . rw , c . encrypted , err = maybeReceiveEncryptedHandshake ( c . rw , skeys )
if err != nil {
if err == mse . ErrNoSecretKeyMatch {
err = nil
}
return
2015-03-18 15:28:13 +08:00
}
2014-08-28 08:06:57 +08:00
}
2016-09-16 10:42:41 +08:00
if cl . config . ForceEncryption && ! c . encrypted {
err = errors . New ( "connection not encrypted" )
return
}
2015-03-18 15:28:13 +08:00
ih , ok , err := cl . connBTHandshake ( c , nil )
2015-02-09 21:17:59 +08:00
if err != nil {
2015-06-28 14:39:04 +08:00
err = fmt . Errorf ( "error during bt handshake: %s" , err )
2015-02-09 21:17:59 +08:00
return
}
2015-03-18 15:28:13 +08:00
if ! ok {
return
2015-03-13 03:21:13 +08:00
}
2015-03-18 15:28:13 +08:00
cl . mu . Lock ( )
t = cl . torrents [ ih ]
cl . mu . Unlock ( )
return
}
// Returns !ok if handshake failed for valid reasons.
2016-04-04 11:01:31 +08:00
func ( cl * Client ) connBTHandshake ( c * connection , ih * metainfo . Hash ) ( ret metainfo . Hash , ok bool , err error ) {
2015-03-18 15:28:13 +08:00
res , ok , err := handshake ( c . rw , ih , cl . peerID , cl . extensionBytes )
if err != nil || ! ok {
2015-03-13 03:21:13 +08:00
return
}
2016-04-04 11:01:31 +08:00
ret = res . Hash
2015-03-18 15:28:13 +08:00
c . PeerExtensionBytes = res . peerExtensionBytes
c . PeerID = res . peerID
c . completedHandshake = time . Now ( )
return
}
2016-05-16 17:50:10 +08:00
func ( cl * Client ) runInitiatedHandshookConn ( c * connection , t * Torrent ) {
2015-03-18 15:28:13 +08:00
if c . PeerID == cl . peerID {
connsToSelf . Add ( 1 )
addr := c . conn . RemoteAddr ( ) . String ( )
cl . dopplegangerAddrs [ addr ] = struct { } { }
return
2014-08-28 07:45:20 +08:00
}
2016-05-16 17:50:10 +08:00
cl . runHandshookConn ( c , t )
2015-03-18 15:28:13 +08:00
}
2016-05-16 17:50:10 +08:00
func ( cl * Client ) runReceivedConn ( c * connection ) {
err := c . conn . SetDeadline ( time . Now ( ) . Add ( handshakesTimeout ) )
2014-08-21 16:12:49 +08:00
if err != nil {
2016-05-16 17:50:10 +08:00
panic ( err )
2014-08-21 16:12:49 +08:00
}
2015-03-18 15:28:13 +08:00
t , err := cl . receiveHandshakes ( c )
if err != nil {
2016-05-16 17:50:10 +08:00
if cl . config . Debug {
log . Printf ( "error receiving handshakes: %s" , err )
}
2014-08-21 16:12:49 +08:00
return
2013-09-29 14:45:17 +08:00
}
2015-03-18 15:28:13 +08:00
if t == nil {
2014-11-17 03:54:00 +08:00
return
}
2015-03-18 15:28:13 +08:00
cl . mu . Lock ( )
defer cl . mu . Unlock ( )
if c . PeerID == cl . peerID {
2016-05-24 00:09:47 +08:00
// Because the remote address is not necessarily the same as its
// client's torrent listen address, we won't record the remote address
// as a doppleganger. Instead, the initiator can record *us* as the
// doppleganger.
2014-08-21 16:12:49 +08:00
return
}
2016-05-16 17:50:10 +08:00
cl . runHandshookConn ( c , t )
2015-03-18 15:28:13 +08:00
}
2016-05-16 17:50:10 +08:00
func ( cl * Client ) runHandshookConn ( c * connection , t * Torrent ) {
2015-03-18 15:28:13 +08:00
c . conn . SetWriteDeadline ( time . Time { } )
c . rw = readWriter {
deadlineReader { c . conn , c . rw } ,
c . rw ,
}
2015-08-02 02:06:22 +08:00
completedHandshakeConnectionFlags . Add ( c . connectionFlags ( ) , 1 )
2016-07-05 14:23:17 +08:00
if ! t . addConnection ( c ) {
2014-03-16 23:30:10 +08:00
return
}
2016-05-11 19:44:55 +08:00
defer t . dropConnection ( c )
2016-05-07 16:56:44 +08:00
go c . writer ( time . Minute )
2015-03-18 15:28:13 +08:00
cl . sendInitialMessages ( c , t )
2016-09-11 12:32:56 +08:00
err := c . mainReadLoop ( )
2016-05-16 17:50:10 +08:00
if err != nil && cl . config . Debug {
log . Printf ( "error during connection loop: %s" , err )
2015-03-18 15:28:13 +08:00
}
}
2016-04-19 12:11:11 +08:00
func ( cl * Client ) sendInitialMessages ( conn * connection , torrent * Torrent ) {
if conn . PeerExtensionBytes . SupportsExtended ( ) && cl . extensionBytes . SupportsExtended ( ) {
2014-06-26 22:57:07 +08:00
conn . Post ( pp . Message {
Type : pp . Extended ,
ExtendedID : pp . HandshakeExtendedID ,
ExtendedPayload : func ( ) [ ] byte {
2014-06-28 17:38:31 +08:00
d := map [ string ] interface { } {
2015-03-25 12:49:27 +08:00
"m" : func ( ) ( ret map [ string ] int ) {
ret = make ( map [ string ] int , 2 )
ret [ "ut_metadata" ] = metadataExtendedId
2016-04-19 12:11:11 +08:00
if ! cl . config . DisablePEX {
2015-03-25 12:49:27 +08:00
ret [ "ut_pex" ] = pexExtendedId
}
return
} ( ) ,
2015-03-25 12:42:14 +08:00
"v" : extendedHandshakeClientVersion ,
2014-08-25 20:12:50 +08:00
// No upload queue is implemented yet.
2015-05-15 06:39:53 +08:00
"reqq" : 64 ,
2015-04-20 15:30:22 +08:00
}
2016-04-19 12:11:11 +08:00
if ! cl . config . DisableEncryption {
2015-04-20 15:30:22 +08:00
d [ "e" ] = 1
2014-06-28 17:38:31 +08:00
}
if torrent . metadataSizeKnown ( ) {
d [ "metadata_size" ] = torrent . metadataSize ( )
}
2016-04-19 12:11:11 +08:00
if p := cl . incomingPeerPort ( ) ; p != 0 {
2014-06-29 16:57:49 +08:00
d [ "p" ] = p
}
2015-03-13 03:21:13 +08:00
yourip , err := addrCompactIP ( conn . remoteAddr ( ) )
2014-07-22 19:45:12 +08:00
if err != nil {
log . Printf ( "error calculating yourip field value in extension handshake: %s" , err )
} else {
d [ "yourip" ] = yourip
}
2014-07-24 11:43:45 +08:00
// log.Printf("sending %v", d)
2014-06-28 17:38:31 +08:00
b , err := bencode . Marshal ( d )
2014-06-26 22:57:07 +08:00
if err != nil {
panic ( err )
}
return b
} ( ) ,
} )
}
2013-10-20 22:07:01 +08:00
if torrent . haveAnyPieces ( ) {
2016-01-04 19:37:49 +08:00
conn . Bitfield ( torrent . bitfield ( ) )
2016-04-19 12:11:11 +08:00
} else if cl . extensionBytes . SupportsFast ( ) && conn . PeerExtensionBytes . SupportsFast ( ) {
2015-03-13 03:21:13 +08:00
conn . Post ( pp . Message {
Type : pp . HaveNone ,
} )
2013-10-20 22:07:01 +08:00
}
2016-04-19 12:11:11 +08:00
if conn . PeerExtensionBytes . SupportsDHT ( ) && cl . extensionBytes . SupportsDHT ( ) && cl . dHT != nil {
2014-08-25 20:12:16 +08:00
conn . Post ( pp . Message {
Type : pp . Port ,
2016-04-19 12:11:11 +08:00
Port : uint16 ( missinggo . AddrPort ( cl . dHT . Addr ( ) ) ) ,
2014-08-25 20:12:16 +08:00
} )
}
2013-09-30 19:51:08 +08:00
}
2016-04-19 12:11:11 +08:00
func ( cl * Client ) peerUnchoked ( torrent * Torrent , conn * connection ) {
2016-01-24 12:21:17 +08:00
conn . updateRequests ( )
2013-09-30 19:51:08 +08:00
}
2016-04-03 16:40:43 +08:00
func ( cl * Client ) connCancel ( t * Torrent , cn * connection , r request ) ( ok bool ) {
2014-05-23 19:01:05 +08:00
ok = cn . Cancel ( r )
if ok {
2014-08-24 01:10:47 +08:00
postedCancels . Add ( 1 )
2014-05-23 19:01:05 +08:00
}
return
}
2016-04-03 16:40:43 +08:00
func ( cl * Client ) connDeleteRequest ( t * Torrent , cn * connection , r request ) bool {
2014-05-23 19:01:05 +08:00
if ! cn . RequestPending ( r ) {
2015-06-22 17:48:30 +08:00
return false
2014-05-23 19:01:05 +08:00
}
delete ( cn . Requests , r )
2015-06-22 17:48:30 +08:00
return true
2014-05-23 19:01:05 +08:00
}
2014-08-21 16:12:49 +08:00
// Process incoming ut_metadata message.
2016-07-23 22:34:40 +08:00
func ( cl * Client ) gotMetadataExtensionMsg ( payload [ ] byte , t * Torrent , c * connection ) error {
2014-06-28 17:38:31 +08:00
var d map [ string ] int
2016-07-23 22:34:40 +08:00
err := bencode . Unmarshal ( payload , & d )
2014-06-28 17:38:31 +08:00
if err != nil {
2016-07-23 22:34:40 +08:00
return fmt . Errorf ( "error unmarshalling payload: %s: %q" , err , payload )
2014-06-28 17:38:31 +08:00
}
msgType , ok := d [ "msg_type" ]
if ! ok {
2016-07-23 22:34:40 +08:00
return errors . New ( "missing msg_type field" )
2014-06-28 17:38:31 +08:00
}
piece := d [ "piece" ]
switch msgType {
case pp . DataMetadataExtensionMsgType :
2016-05-03 12:59:54 +08:00
if ! c . requestedMetadataPiece ( piece ) {
2016-07-23 22:34:40 +08:00
return fmt . Errorf ( "got unexpected piece %d" , piece )
2014-06-28 17:38:31 +08:00
}
2016-05-03 12:59:54 +08:00
c . metadataRequests [ piece ] = false
2014-11-19 11:57:27 +08:00
begin := len ( payload ) - metadataPieceSize ( d [ "total_size" ] , piece )
if begin < 0 || begin >= len ( payload ) {
2016-07-23 22:34:40 +08:00
return fmt . Errorf ( "data has bad offset in payload: %d" , begin )
2015-03-27 12:36:59 +08:00
}
2015-03-20 07:52:01 +08:00
t . saveMetadataPiece ( piece , payload [ begin : ] )
2014-12-01 17:32:17 +08:00
c . UsefulChunksReceived ++
c . lastUsefulChunkReceived = time . Now ( )
2016-07-23 22:34:40 +08:00
return t . maybeCompleteMetadata ( )
2014-06-28 17:38:31 +08:00
case pp . RequestMetadataExtensionMsgType :
2015-02-25 12:42:47 +08:00
if ! t . haveMetadataPiece ( piece ) {
c . Post ( t . newMetadataExtensionMessage ( c , pp . RejectMetadataExtensionMsgType , d [ "piece" ] , nil ) )
2016-07-23 22:34:40 +08:00
return nil
2014-06-28 17:38:31 +08:00
}
2014-08-21 16:12:49 +08:00
start := ( 1 << 14 ) * piece
2016-04-03 14:50:53 +08:00
c . Post ( t . newMetadataExtensionMessage ( c , pp . DataMetadataExtensionMsgType , piece , t . metadataBytes [ start : start + t . metadataPieceSize ( piece ) ] ) )
2016-07-23 22:34:40 +08:00
return nil
2014-06-28 17:38:31 +08:00
case pp . RejectMetadataExtensionMsgType :
2016-07-23 22:34:40 +08:00
return nil
2014-06-28 17:38:31 +08:00
default :
2016-07-23 22:34:40 +08:00
return errors . New ( "unknown msg_type value" )
2014-06-28 17:38:31 +08:00
}
}
2016-04-19 12:11:11 +08:00
func ( cl * Client ) upload ( t * Torrent , c * connection ) {
if cl . config . NoUpload {
2015-06-16 14:57:47 +08:00
return
}
if ! c . PeerInterested {
return
}
2016-05-11 19:44:55 +08:00
seeding := t . seeding ( )
2015-07-15 13:29:53 +08:00
if ! seeding && ! t . connHasWantedPieces ( c ) {
2015-06-16 14:57:47 +08:00
return
}
another :
2015-07-15 13:29:53 +08:00
for seeding || c . chunksSent < c . UsefulChunksReceived + 6 {
2015-06-16 14:57:47 +08:00
c . Unchoke ( )
for r := range c . PeerRequests {
2016-04-19 12:11:11 +08:00
err := cl . sendChunk ( t , c , r )
2015-06-16 14:57:47 +08:00
if err != nil {
2016-07-06 12:03:11 +08:00
i := int ( r . Index )
if t . pieceComplete ( i ) {
t . updatePieceCompletion ( i )
if ! t . pieceComplete ( i ) {
// We had the piece, but not anymore.
break another
}
2016-02-26 19:12:13 +08:00
}
2016-07-06 12:03:11 +08:00
log . Printf ( "error sending chunk %+v to peer: %s" , r , err )
2016-02-21 14:22:55 +08:00
// If we failed to send a chunk, choke the peer to ensure they
// flush all their requests. We've probably dropped a piece,
// but there's no way to communicate this to the peer. If they
// ask for it again, we'll kick them to allow us to send them
// an updated bitfield.
break another
2015-06-16 14:57:47 +08:00
}
delete ( c . PeerRequests , r )
goto another
}
return
}
c . Choke ( )
}
2016-04-19 12:11:11 +08:00
func ( cl * Client ) sendChunk ( t * Torrent , c * connection , r request ) error {
2015-09-17 10:50:29 +08:00
// Count the chunk being sent, even if it isn't.
2015-06-16 14:57:47 +08:00
b := make ( [ ] byte , r . Length )
2016-04-03 14:50:53 +08:00
p := t . info . Piece ( int ( r . Index ) )
2016-02-21 00:32:59 +08:00
n , err := t . readAt ( b , p . Offset ( ) + int64 ( r . Begin ) )
2015-06-16 14:57:47 +08:00
if n != len ( b ) {
2016-02-20 11:40:28 +08:00
if err == nil {
panic ( "expected error" )
}
return err
2015-06-16 14:57:47 +08:00
}
c . Post ( pp . Message {
Type : pp . Piece ,
Index : r . Index ,
Begin : r . Begin ,
Piece : b ,
} )
2016-02-21 14:22:55 +08:00
c . chunksSent ++
2015-06-16 14:57:47 +08:00
uploadChunksPosted . Add ( 1 )
c . lastChunkSent = time . Now ( )
return nil
}
2016-04-19 12:11:11 +08:00
func ( cl * Client ) openNewConns ( t * Torrent ) {
2016-05-22 20:45:08 +08:00
defer t . updateWantPeersEvent ( )
2016-04-03 14:50:53 +08:00
for len ( t . peers ) != 0 {
2016-07-05 14:23:17 +08:00
if ! t . wantConns ( ) {
2014-12-03 15:07:50 +08:00
return
2014-08-28 07:39:27 +08:00
}
2016-04-19 12:11:11 +08:00
if len ( t . halfOpen ) >= cl . halfOpenLimit {
2014-12-03 15:07:50 +08:00
return
2014-11-21 14:09:55 +08:00
}
var (
2016-01-06 09:19:49 +08:00
k peersKey
2014-11-21 14:09:55 +08:00
p Peer
)
2016-04-03 14:50:53 +08:00
for k , p = range t . peers {
2014-11-21 14:09:55 +08:00
break
2013-09-29 06:11:24 +08:00
}
2016-04-03 14:50:53 +08:00
delete ( t . peers , k )
2016-04-19 12:11:11 +08:00
cl . initiateConn ( p , t )
2013-09-29 06:11:24 +08:00
}
}
2016-05-24 00:09:47 +08:00
func ( cl * Client ) badPeerIPPort ( ip net . IP , port int ) bool {
if port == 0 {
return true
}
if cl . dopplegangerAddr ( net . JoinHostPort ( ip . String ( ) , strconv . FormatInt ( int64 ( port ) , 10 ) ) ) {
return true
}
if _ , ok := cl . ipBlockRange ( ip ) ; ok {
return true
}
if _ , ok := cl . badPeerIPs [ ip . String ( ) ] ; ok {
return true
}
return false
2013-09-29 06:11:24 +08:00
}
2016-07-05 14:23:17 +08:00
// Return a Torrent ready for insertion into a Client.
2016-05-09 12:37:29 +08:00
func ( cl * Client ) newTorrent ( ih metainfo . Hash ) ( t * Torrent ) {
2016-04-03 16:40:43 +08:00
t = & Torrent {
2016-05-09 12:37:29 +08:00
cl : cl ,
2016-04-03 16:40:43 +08:00
infoHash : ih ,
2015-07-15 13:31:18 +08:00
chunkSize : defaultChunkSize ,
2016-04-03 14:50:53 +08:00
peers : make ( map [ peersKey ] Peer ) ,
2014-08-25 04:01:05 +08:00
2016-04-03 14:50:53 +08:00
halfOpen : make ( map [ string ] struct { } ) ,
2015-09-06 10:33:22 +08:00
pieceStateChanges : pubsub . NewPubSub ( ) ,
2016-05-09 12:37:29 +08:00
2016-07-05 14:23:17 +08:00
storageOpener : cl . defaultStorage ,
maxEstablishedConns : defaultEstablishedConnsPerTorrent ,
2014-06-26 22:57:07 +08:00
}
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 ) {
cl . mu . Lock ( )
defer cl . mu . Unlock ( )
t , ok := cl . torrents [ infoHash ]
if ok {
return
}
new = true
t = cl . newTorrent ( infoHash )
2016-05-09 13:47:39 +08:00
if cl . dHT != nil {
2016-07-23 20:38:31 +08:00
go t . dhtAnnouncer ( )
2016-05-09 13:47:39 +08:00
}
cl . torrents [ infoHash ] = t
2016-05-23 08:19:14 +08:00
t . updateWantPeersEvent ( )
2016-07-07 12:49:18 +08:00
// Tickle Client.waitAccept, new torrent may want conns.
cl . event . Broadcast ( )
2016-05-09 12:37:29 +08:00
return
}
2015-03-27 23:50:55 +08:00
// Add or merge a torrent spec. If the torrent is already present, the
// trackers will be merged with the existing ones. If the Info isn't yet
// known, it will be set. The display name is replaced if the new spec
// provides one. Returns new if the torrent wasn't already in the client.
2016-04-03 16:40:43 +08:00
func ( cl * Client ) AddTorrentSpec ( spec * TorrentSpec ) ( t * Torrent , new bool , err error ) {
2016-05-09 12:37:29 +08:00
t , new = cl . AddTorrentInfoHash ( spec . InfoHash )
2015-03-18 15:32:31 +08:00
if spec . DisplayName != "" {
2016-05-09 13:47:39 +08:00
t . SetDisplayName ( spec . DisplayName )
2015-03-18 15:32:31 +08:00
}
2016-08-26 18:29:05 +08:00
if spec . InfoBytes != nil {
err = t . SetInfoBytes ( spec . InfoBytes )
2016-05-09 13:47:39 +08:00
if err != nil {
return
}
2013-10-20 22:07:01 +08:00
}
2016-05-09 13:47:39 +08:00
cl . mu . Lock ( )
defer cl . mu . Unlock ( )
2016-05-09 21:00:20 +08:00
if spec . ChunkSize != 0 {
t . chunkSize = pp . Integer ( spec . ChunkSize )
}
2015-03-27 23:50:55 +08:00
t . addTrackers ( spec . Trackers )
2016-04-03 20:06:25 +08:00
t . maybeNewConns ( )
2014-06-26 22:57:07 +08:00
return
}
2014-05-21 15:37:31 +08:00
2016-04-19 12:11:11 +08:00
func ( cl * Client ) dropTorrent ( infoHash metainfo . Hash ) ( err error ) {
t , ok := cl . torrents [ infoHash ]
2014-07-22 23:54:11 +08:00
if ! ok {
err = fmt . Errorf ( "no such torrent" )
return
}
2015-02-09 21:12:29 +08:00
err = t . close ( )
2014-07-22 23:54:11 +08:00
if err != nil {
panic ( err )
}
2016-04-19 12:11:11 +08:00
delete ( cl . torrents , infoHash )
2014-07-22 23:54:11 +08:00
return
}
2016-05-22 20:45:08 +08:00
func ( cl * Client ) prepareTrackerAnnounceUnlocked ( announceURL string ) ( blocked bool , urlToUse string , host string , err error ) {
_url , err := url . Parse ( announceURL )
2015-03-10 23:41:41 +08:00
if err != nil {
return
}
2016-05-22 20:45:08 +08:00
hmp := missinggo . SplitHostMaybePort ( _url . Host )
if hmp . Err != nil {
err = hmp . Err
return
2015-03-10 23:41:41 +08:00
}
2016-05-22 20:45:08 +08:00
addr , err := net . ResolveIPAddr ( "ip" , hmp . Host )
2015-03-10 23:41:41 +08:00
if err != nil {
return
}
2015-10-18 21:00:26 +08:00
cl . mu . RLock ( )
_ , blocked = cl . ipBlockRange ( addr . IP )
cl . mu . RUnlock ( )
2016-05-22 20:45:08 +08:00
host = _url . Host
hmp . Host = addr . String ( )
_url . Host = hmp . String ( )
urlToUse = _url . String ( )
2015-03-10 23:41:41 +08:00
return
}
2014-03-16 23:30:10 +08:00
func ( cl * Client ) allTorrentsCompleted ( ) bool {
for _ , t := range cl . torrents {
2014-09-15 01:25:53 +08:00
if ! t . haveInfo ( ) {
return false
}
2015-02-25 12:42:47 +08:00
if t . numPiecesCompleted ( ) != t . numPieces ( ) {
2014-03-16 23:30:10 +08:00
return false
}
}
return true
}
2014-04-09 00:36:05 +08:00
// Returns true when all torrents are completely downloaded and false if the
2014-06-29 22:22:05 +08:00
// client is stopped before that.
2016-04-19 12:11:11 +08:00
func ( cl * Client ) WaitAll ( ) bool {
cl . mu . Lock ( )
defer cl . mu . Unlock ( )
for ! cl . allTorrentsCompleted ( ) {
if cl . closed . IsSet ( ) {
2014-04-09 00:36:05 +08:00
return false
}
2016-04-19 12:11:11 +08:00
cl . event . Wait ( )
2013-10-20 22:07:01 +08:00
}
2014-04-09 00:36:05 +08:00
return true
2013-09-26 17:49:15 +08:00
}
2014-08-28 07:32:49 +08:00
// Handle a received chunk from a peer.
2016-04-19 12:11:11 +08:00
func ( cl * Client ) downloadedChunk ( t * Torrent , c * connection , msg * pp . Message ) {
2015-06-22 17:48:30 +08:00
chunksReceived . Add ( 1 )
2014-08-21 23:33:13 +08:00
2014-05-21 16:01:58 +08:00
req := newRequest ( msg . Index , msg . Begin , pp . Integer ( len ( msg . Piece ) ) )
2014-05-21 15:40:54 +08:00
// Request has been satisfied.
2016-04-19 12:11:11 +08:00
if cl . connDeleteRequest ( t , c , req ) {
2016-01-24 12:21:17 +08:00
defer c . updateRequests ( )
2015-06-22 17:48:30 +08:00
} else {
unexpectedChunksReceived . Add ( 1 )
}
2014-05-21 15:40:54 +08:00
2016-01-13 14:11:59 +08:00
index := int ( req . Index )
2016-04-03 14:50:53 +08:00
piece := & t . pieces [ index ]
2015-03-10 23:39:01 +08:00
2014-05-21 15:40:54 +08:00
// Do we actually want this chunk?
2016-04-19 12:11:11 +08:00
if ! t . wantPiece ( req ) {
2015-06-22 17:48:30 +08:00
unwantedChunksReceived . Add ( 1 )
2014-09-11 18:30:13 +08:00
c . UnwantedChunksReceived ++
2016-01-28 02:54:48 +08:00
return
2014-05-21 15:40:54 +08:00
}
2014-08-28 07:32:49 +08:00
c . UsefulChunksReceived ++
c . lastUsefulChunkReceived = time . Now ( )
2016-04-19 12:11:11 +08:00
cl . upload ( t , c )
2015-06-16 14:57:47 +08:00
2016-01-28 02:54:48 +08:00
// Need to record that it hasn't been written yet, before we attempt to do
// anything with it.
piece . incrementPendingWrites ( )
2014-05-21 15:40:54 +08:00
// Record that we have the chunk.
2015-07-15 13:31:18 +08:00
piece . unpendChunkIndex ( chunkIndex ( req . chunkSpec , t . chunkSize ) )
2014-05-21 15:40:54 +08:00
2014-05-29 00:44:27 +08:00
// Cancel pending requests for this chunk.
2016-04-03 14:50:53 +08:00
for _ , c := range t . conns {
2016-04-19 12:11:11 +08:00
if cl . connCancel ( t , c , req ) {
2016-01-24 12:21:17 +08:00
c . updateRequests ( )
2014-05-29 00:44:27 +08:00
}
}
2016-04-19 12:11:11 +08:00
cl . mu . Unlock ( )
2016-05-17 00:12:06 +08:00
// Write the chunk out. Note that the upper bound on chunk writing
// concurrency will be the number of connections.
2016-01-28 02:54:48 +08:00
err := t . writeChunk ( int ( msg . Index ) , int64 ( msg . Begin ) , msg . Piece )
2016-04-19 12:11:11 +08:00
cl . mu . Lock ( )
2016-01-28 02:54:48 +08:00
piece . decrementPendingWrites ( )
if err != nil {
2016-04-03 14:36:24 +08:00
log . Printf ( "%s: error writing chunk %v: %s" , t , req , err )
2016-01-28 02:54:48 +08:00
t . pendRequest ( req )
2016-04-03 14:36:57 +08:00
t . updatePieceCompletion ( int ( msg . Index ) )
2016-01-28 02:54:48 +08:00
return
}
// It's important that the piece is potentially queued before we check if
// the piece is still wanted, because if it is queued, it won't be wanted.
if t . pieceAllDirty ( index ) {
2016-04-19 12:11:11 +08:00
cl . queuePieceCheck ( t , int ( req . Index ) )
2016-01-28 02:54:48 +08:00
}
if c . peerTouchedPieces == nil {
c . peerTouchedPieces = make ( map [ int ] struct { } )
}
c . peerTouchedPieces [ index ] = struct { } { }
2016-04-19 12:11:11 +08:00
cl . event . Broadcast ( )
2016-01-28 02:54:48 +08:00
t . publishPieceChange ( int ( req . Index ) )
return
2013-10-13 20:16:21 +08:00
}
2015-08-05 00:43:53 +08:00
// Return the connections that touched a piece, and clear the entry while
// doing it.
2016-04-19 12:11:11 +08:00
func ( cl * Client ) reapPieceTouches ( t * Torrent , piece int ) ( ret [ ] * connection ) {
2016-04-03 14:50:53 +08:00
for _ , c := range t . conns {
2015-08-05 00:43:53 +08:00
if _ , ok := c . peerTouchedPieces [ piece ] ; ok {
ret = append ( ret , c )
delete ( c . peerTouchedPieces , piece )
}
}
return
}
2016-04-19 12:11:11 +08:00
func ( cl * Client ) pieceHashed ( t * Torrent , piece int , correct bool ) {
2016-06-20 15:51:05 +08:00
if t . closed . IsSet ( ) {
return
}
2016-04-03 14:50:53 +08:00
p := & t . pieces [ piece ]
2015-06-28 14:41:51 +08:00
if p . EverHashed {
2015-08-05 00:43:53 +08:00
// Don't score the first time a piece is hashed, it could be an
// initial check.
2015-06-28 14:41:51 +08:00
if correct {
pieceHashedCorrect . Add ( 1 )
} else {
2016-04-03 14:36:24 +08:00
log . Printf ( "%s: piece %d (%x) failed hash" , t , piece , p . Hash )
2015-06-28 14:41:51 +08:00
pieceHashedNotCorrect . Add ( 1 )
}
2014-09-14 01:57:51 +08:00
}
2013-10-20 22:07:01 +08:00
p . EverHashed = true
2016-04-19 12:11:11 +08:00
touchers := cl . reapPieceTouches ( t , piece )
2015-02-27 09:45:55 +08:00
if correct {
2016-05-24 00:09:47 +08:00
for _ , c := range touchers {
c . goodPiecesDirtied ++
}
2016-03-28 17:38:30 +08:00
err := p . Storage ( ) . MarkComplete ( )
2015-06-02 22:03:43 +08:00
if err != nil {
2016-03-28 17:38:30 +08:00
log . Printf ( "%T: error completing piece %d: %s" , t . storage , piece , err )
2015-02-27 09:45:55 +08:00
}
2016-02-16 21:00:55 +08:00
t . updatePieceCompletion ( piece )
2015-08-05 00:43:53 +08:00
} else if len ( touchers ) != 0 {
2016-05-24 00:09:47 +08:00
log . Printf ( "dropping and banning %d conns that touched piece" , len ( touchers ) )
2015-08-05 00:43:53 +08:00
for _ , c := range touchers {
2016-05-24 00:09:47 +08:00
c . badPiecesDirtied ++
t . cl . banPeerIP ( missinggo . AddrIP ( c . remoteAddr ( ) ) )
2016-05-11 19:44:55 +08:00
t . dropConnection ( c )
2015-08-05 00:43:53 +08:00
}
2015-02-27 09:45:55 +08:00
}
2016-04-19 12:11:11 +08:00
cl . pieceChanged ( t , piece )
2015-03-10 23:41:21 +08:00
}
2016-04-19 12:11:11 +08:00
func ( cl * Client ) onCompletedPiece ( t * Torrent , piece int ) {
2016-01-31 22:46:28 +08:00
t . pendingPieces . Remove ( piece )
2016-02-22 00:23:49 +08:00
t . pendAllChunkSpecs ( piece )
2016-04-03 14:50:53 +08:00
for _ , conn := range t . conns {
2016-01-18 22:28:56 +08:00
conn . Have ( piece )
for r := range conn . Requests {
if int ( r . Index ) == piece {
conn . Cancel ( r )
}
2014-12-03 15:07:50 +08:00
}
2016-01-18 22:28:56 +08:00
// Could check here if peer doesn't have piece, but due to caching
// some peers may have said they have a piece but they don't.
2016-04-19 12:11:11 +08:00
cl . upload ( t , conn )
2016-01-18 22:28:56 +08:00
}
}
2016-04-19 12:11:11 +08:00
func ( cl * Client ) onFailedPiece ( t * Torrent , piece int ) {
2016-01-18 22:28:56 +08:00
if t . pieceAllDirty ( piece ) {
t . pendAllChunkSpecs ( piece )
2013-09-30 19:51:08 +08:00
}
2016-04-19 12:11:11 +08:00
if ! t . wantPieceIndex ( piece ) {
2016-01-18 22:28:56 +08:00
return
}
2016-04-19 12:11:11 +08:00
cl . openNewConns ( t )
2016-04-03 14:50:53 +08:00
for _ , conn := range t . conns {
2016-01-18 22:28:56 +08:00
if conn . PeerHasPiece ( piece ) {
2016-01-24 12:21:17 +08:00
conn . updateRequests ( )
2013-09-26 17:49:15 +08:00
}
}
2016-01-18 22:28:56 +08:00
}
2016-04-19 12:11:11 +08:00
func ( cl * Client ) pieceChanged ( t * Torrent , piece int ) {
2016-01-18 22:28:56 +08:00
correct := t . pieceComplete ( piece )
2016-04-19 12:11:11 +08:00
defer cl . event . Broadcast ( )
2016-01-18 22:28:56 +08:00
if correct {
2016-04-19 12:11:11 +08:00
cl . onCompletedPiece ( t , piece )
2016-01-18 22:28:56 +08:00
} else {
2016-04-19 12:11:11 +08:00
cl . onFailedPiece ( t , piece )
2016-01-18 22:28:56 +08:00
}
2016-08-30 13:41:26 +08:00
t . updatePiecePriority ( piece )
2013-10-02 15:57:59 +08:00
}
2013-09-30 19:51:08 +08:00
2016-04-03 16:40:43 +08:00
func ( cl * Client ) verifyPiece ( t * Torrent , piece int ) {
2014-03-20 01:30:08 +08:00
cl . mu . Lock ( )
2014-09-14 02:07:05 +08:00
defer cl . mu . Unlock ( )
2016-04-03 14:50:53 +08:00
p := & t . pieces [ piece ]
2016-03-28 17:38:30 +08:00
for p . Hashing || t . storage == nil {
2014-03-20 01:30:08 +08:00
cl . event . Wait ( )
}
2015-02-27 09:45:55 +08:00
p . QueuedForHash = false
2016-05-11 19:44:55 +08:00
if t . closed . IsSet ( ) || t . pieceComplete ( piece ) {
2016-02-08 18:38:30 +08:00
t . updatePiecePriority ( piece )
2014-07-22 23:54:11 +08:00
return
}
2014-03-20 01:30:08 +08:00
p . Hashing = true
2016-02-06 22:21:12 +08:00
t . publishPieceChange ( piece )
2014-03-20 01:30:08 +08:00
cl . mu . Unlock ( )
2016-01-04 19:34:24 +08:00
sum := t . hashPiece ( piece )
2013-10-20 22:07:01 +08:00
cl . mu . Lock ( )
2014-03-20 01:30:08 +08:00
p . Hashing = false
2016-01-04 19:34:24 +08:00
cl . pieceHashed ( t , piece , sum == p . Hash )
2013-09-26 17:49:15 +08:00
}
2013-10-06 15:01:39 +08:00
2015-03-08 14:28:14 +08:00
// Returns handles to all the torrents loaded in the Client.
2016-04-19 12:11:11 +08:00
func ( cl * Client ) Torrents ( ) ( ret [ ] * Torrent ) {
cl . mu . Lock ( )
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
}
2016-04-19 12:11:11 +08:00
cl . mu . Unlock ( )
2013-10-06 15:01:39 +08:00
return
}
2015-03-18 15:32:31 +08:00
2016-04-19 12:11:11 +08:00
func ( cl * Client ) AddMagnet ( uri string ) ( T * Torrent , err error ) {
2015-03-18 15:32:31 +08:00
spec , err := TorrentSpecFromMagnetURI ( uri )
if err != nil {
return
}
2016-04-19 12:11:11 +08:00
T , _ , err = cl . AddTorrentSpec ( spec )
2015-03-18 15:32:31 +08:00
return
}
2016-04-19 12:11:11 +08:00
func ( cl * Client ) AddTorrent ( mi * metainfo . MetaInfo ) ( T * Torrent , err error ) {
T , _ , err = cl . AddTorrentSpec ( TorrentSpecFromMetaInfo ( mi ) )
2016-02-24 18:56:50 +08:00
var ss [ ] string
2016-07-12 14:40:14 +08:00
slices . MakeInto ( & ss , mi . Nodes )
2016-04-19 12:11:11 +08:00
cl . AddDHTNodes ( ss )
2015-03-18 15:32:31 +08:00
return
}
2016-04-19 12:11:11 +08:00
func ( cl * Client ) AddTorrentFromFile ( filename string ) ( T * Torrent , err error ) {
2015-03-18 15:32:31 +08:00
mi , err := metainfo . LoadFromFile ( filename )
if err != nil {
return
}
2016-04-19 12:11:11 +08:00
return cl . AddTorrent ( mi )
2015-03-18 15:32:31 +08:00
}
2015-08-03 23:07:22 +08:00
2016-04-19 12:11:11 +08:00
func ( cl * Client ) DHT ( ) * dht . Server {
return cl . dHT
2015-08-03 23:07:22 +08:00
}
2016-02-24 18:56:50 +08:00
2016-04-19 12:11:11 +08:00
func ( cl * Client ) AddDHTNodes ( nodes [ ] string ) {
2016-02-24 18:56:50 +08:00
for _ , n := range nodes {
2016-03-15 18:32:47 +08:00
hmp := missinggo . SplitHostMaybePort ( n )
2016-02-24 18:56:50 +08:00
ip := net . ParseIP ( hmp . Host )
if ip == nil {
log . Printf ( "won't add DHT node with bad IP: %q" , hmp . Host )
continue
}
2016-05-17 14:40:08 +08:00
ni := krpc . NodeInfo {
Addr : & net . UDPAddr {
2016-02-24 18:56:50 +08:00
IP : ip ,
Port : hmp . Port ,
2016-05-17 14:40:08 +08:00
} ,
2016-02-24 18:56:50 +08:00
}
2016-04-19 12:11:11 +08:00
cl . DHT ( ) . AddNode ( ni )
2016-02-24 18:56:50 +08:00
}
}
2016-05-24 00:09:47 +08:00
func ( cl * Client ) banPeerIP ( ip net . IP ) {
if cl . badPeerIPs == nil {
cl . badPeerIPs = make ( map [ string ] struct { } )
}
cl . badPeerIPs [ ip . String ( ) ] = struct { } { }
}