mathRand "math/rand"
"net"
"os"
+ "strconv"
"strings"
"sync"
"syscall"
"time"
- "bitbucket.org/anacrolix/go.torrent/util/levelmu"
-
- "bitbucket.org/anacrolix/go.torrent/dht"
- . "bitbucket.org/anacrolix/go.torrent/util"
+ "github.com/h2so5/utp"
"github.com/anacrolix/libtorgo/metainfo"
"github.com/nsf/libtorgo/bencode"
+ "bitbucket.org/anacrolix/go.torrent/dht"
pp "bitbucket.org/anacrolix/go.torrent/peer_protocol"
"bitbucket.org/anacrolix/go.torrent/tracker"
_ "bitbucket.org/anacrolix/go.torrent/tracker/udp"
+ . "bitbucket.org/anacrolix/go.torrent/util"
+ "bitbucket.org/anacrolix/go.torrent/util/levelmu"
)
var (
dataDir string
halfOpenLimit int
peerID [20]byte
- listener net.Listener
+ listeners []net.Listener
disableTrackers bool
downloadStrategy DownloadStrategy
dHT *dht.Server
if cl.dHT != nil {
fmt.Fprintf(w, "DHT nodes: %d\n", cl.dHT.NumNodes())
fmt.Fprintf(w, "DHT Server ID: %x\n", cl.dHT.IDString())
+ fmt.Fprintf(w, "DHT port: %d\n", addrPort(cl.dHT.LocalAddr()))
+ fmt.Fprintf(w, "DHT announces: %d\n", cl.dHT.NumConfirmedAnnounces)
}
cl.downloadStrategy.WriteStatus(w)
fmt.Fprintln(w)
return t.Data.ReadAt(p, off)
}
+func dhtAddr(listen net.Addr) (s string, err error) {
+ host, port, err := net.SplitHostPort(listen.String())
+ if err != nil {
+ return
+ }
+ i64, err := strconv.ParseInt(port, 0, 0)
+ if err != nil {
+ return
+ }
+ s = net.JoinHostPort(host, strconv.FormatInt(i64+1, 10))
+ return
+}
+
func NewClient(cfg *Config) (cl *Client, err error) {
if cfg == nil {
cfg = &Config{}
cl.downloadStrategy = &DefaultDownloadStrategy{}
}
- cl.listener, err = net.Listen("tcp", cfg.ListenAddr)
- if err != nil {
- return
+ // Returns the laddr string to listen on for the next Listen call.
+ listenAddr := func() string {
+ if addr := cl.ListenAddr(); addr != nil {
+ return addr.String()
+ }
+ return cfg.ListenAddr
}
- if cl.listener != nil {
- go cl.acceptConnections()
+ var l net.Listener
+ if false {
+ l, err = net.Listen("tcp", listenAddr())
+ if err != nil {
+ return
+ }
+ cl.listeners = append(cl.listeners, l)
+ go cl.acceptConnections(l, false)
+ }
+ if true {
+ l, err = utp.Listen("utp", listenAddr())
+ if err != nil {
+ return
+ }
+ cl.listeners = append(cl.listeners, l)
+ go cl.acceptConnections(l, true)
}
-
if !cfg.NoDHT {
+ var dhtAddr_ string
+ dhtAddr_, err = dhtAddr(cl.ListenAddr())
+ if err != nil {
+ return
+ }
cl.dHT, err = dht.NewServer(&dht.ServerConfig{
- Addr: cfg.ListenAddr,
+ Addr: dhtAddr_,
})
if err != nil {
return
me.mu.Unlock()
}
-func (cl *Client) acceptConnections() {
+func (cl *Client) acceptConnections(l net.Listener, utp bool) {
for {
// We accept all connections immediately, because we don't what
// torrent they're for.
- conn, err := cl.listener.Accept()
+ conn, err := l.Accept()
select {
case <-cl.quit:
if conn != nil {
return
}
go func() {
- if err := cl.runConnection(conn, nil, peerSourceIncoming); err != nil {
+ if err := cl.runConnection(conn, nil, peerSourceIncoming, utp); err != nil {
log.Print(err)
}
}()
// Start the process of connecting to the given peer for the given torrent if
// appropriate.
-func (me *Client) initiateConn(peer Peer, torrent *torrent) {
+func (me *Client) initiateConn(peer Peer, t *torrent) {
if peer.Id == me.peerID {
return
}
// "address in use" error. It seems it's not possible to dial out from
// this address so that peers associate our local address with our
// listen address.
- conn, err := net.DialTimeout(addr.Network(), addr.String(), dialTimeout)
+ if false {
+ conn, err := net.DialTimeout("tcp", addr, dialTimeout)
+ } else {
+ conn, err := (&utp.Dialer{Timeout: dialTimeout}).Dial("utp", addr)
+ }
// Whether or not the connection attempt succeeds, the half open
// counter should be decremented, and new connection attempts made.
return
}
// log.Printf("connected to %s", conn.RemoteAddr())
- err = me.runConnection(conn, torrent, peer.Source)
+ err = me.runConnection(conn, t, peer.Source, true)
if err != nil {
log.Print(err)
}
return
}
-func (me *Client) runConnection(sock net.Conn, torrent *torrent, discovery peerSource) (err error) {
+func (me *Client) runConnection(sock net.Conn, torrent *torrent, discovery peerSource, uTP bool) (err error) {
if tcpConn, ok := sock.(*net.TCPConn); ok {
tcpConn.SetLinger(0)
}
}
sock.SetWriteDeadline(time.Time{})
sock = peerConn{sock}
- conn := newConnection(sock, hsRes.peerExtensionBytes, hsRes.peerID)
+ conn := newConnection(sock, hsRes.peerExtensionBytes, hsRes.peerID, uTP)
defer conn.Close()
conn.Discovery = discovery
if !me.addConnection(torrent, conn) {