BitTorrent peer write test

This commit is contained in:
liwei committed 2019-05-27 19:18:28 +08:00
1 parent 41ff983b73
commit 03fbdcda60
15 files changed
+649 -188

No files matched your search

+4 -1
View File
@@ -1,2 +1,5 @@
## gopeed
A fast download client,support HTTP&P2P.
A fast download client,support HTTP&P2P.
## 参考
[https://wiki.theory.org/index.php/BitTorrentSpecification#Peer_wire_protocol_.28TCP.29](https://wiki.theory.org/index.php/BitTorrentSpecification#Peer_wire_protocol_.28TCP.29)
+1 -12
View File
@@ -6,16 +6,5 @@ import (
func main() {
metaInfo, _ := bt.ParseFromFile("e:/Game.of.Thrones.S08E05.720p.WEB.H264-MEMENTO.torrent")
// metaInfo, _ := down.ParseFromFile("e:/test.torrent")
if len(metaInfo.AnnounceList) > 0 {
for _, announceArr := range metaInfo.AnnounceList {
if len(announceArr) > 0 {
for _, announce := range announceArr {
bt.DoTracker(announce, metaInfo)
}
}
}
} else {
bt.DoTracker(metaInfo.Announce, metaInfo)
}
metaInfo.Tracker()
}
+19 -4
View File
@@ -1,9 +1,24 @@
package main
import "fmt"
import (
"fmt"
"io"
"net"
)
func main() {
var b = -1
var n = uint32(b)
fmt.Println(n)
data := [68]byte{0x13, 0x42, 0x69, 0x74, 0x54, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x05, 0x2c, 0x37, 0xb2, 0x23, 0xe3, 0xaf, 0x73, 0xe7, 0xb0, 0xe7, 0xa0, 0x05, 0x03, 0x07, 0xe6, 0x61, 0xcf, 0x94, 0xe7, 0x0d, 0x2d, 0x55, 0x54, 0x33, 0x35, 0x35, 0x53, 0x2d, 0xaf, 0xb0, 0xec, 0xdc, 0xbf, 0xd1, 0x02, 0x93, 0xd6, 0xf4, 0x9b, 0x24}
conn, err := net.Dial("tcp", "58.179.218.77:47474")
if err != nil {
fmt.Println(err)
}
defer conn.Close()
conn.Write(data[:])
var read [68]byte
_, err = io.ReadFull(conn, read[:])
if err != nil {
fmt.Println(err)
}
fmt.Println(read)
}
-21
View File
@@ -1,21 +0,0 @@
package main
import (
"fmt"
"net"
)
func main() {
ip := net.ParseIP("127.0.0.1")
srcAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0}
dstAddr := &net.UDPAddr{IP: ip, Port: 9981}
conn, err := net.DialUDP("udp", srcAddr, dstAddr)
if err != nil {
fmt.Println(err)
}
defer conn.Close()
conn.Write([]byte("hello"))
conn.Write([]byte("test"))
conn.Read([]byte{})
fmt.Printf("<%s>\n", conn.RemoteAddr())
}
-27
View File
@@ -1,27 +0,0 @@
package main
import (
"fmt"
"net"
)
func main() {
conn, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.ParseIP("127.0.0.1"), Port: 9981})
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("Local: <%s> \n", conn.LocalAddr().String())
data := make([]byte, 1024)
for {
n, remoteAddr, err := conn.ReadFromUDP(data)
if err != nil {
fmt.Printf("error during read: %s", err)
}
fmt.Printf("<%s> %s\n", remoteAddr, data[:n])
_, err = conn.WriteToUDP([]byte("world"), remoteAddr)
if err != nil {
fmt.Printf(err.Error())
}
}
}
+41
View File
@@ -0,0 +1,41 @@
package main
import (
"bytes"
"encoding/binary"
"fmt"
)
type User struct {
Age uint32
Sex byte
Name [20]byte
}
type Buffer struct {
buf []byte
limit int
}
func NewBuffer(buf []byte) *Buffer {
return &Buffer{
buf: buf,
limit: 0,
}
}
func main() {
user := &User{1, 2, [20]byte{}}
buf := new(bytes.Buffer)
binary.Write(buf, binary.LittleEndian, user)
fmt.Println(buf.Bytes())
}
/*func (buffer Buffer) ReadByte() (byte, error) {
}
func (buffer Buffer) ReadByte() (byte, error)() {
}
*/
+25
View File
@@ -0,0 +1,25 @@
package bt
import (
"fmt"
)
type ErrorCode int
const (
ErrTimeout ErrorCode = -1
ErrResponse ErrorCode = -2
)
type TrackerError struct {
Code ErrorCode
Err error
}
func (te *TrackerError) Error() string {
return fmt.Sprintf("%s:%d", te.Err.Error(), te.Code)
}
func NewTrackerError(code ErrorCode, err error) *TrackerError {
return &TrackerError{code, err}
}
+258
View File
@@ -0,0 +1,258 @@
package bt
import (
"bufio"
"bytes"
"encoding/binary"
"fmt"
"io"
"net"
"strconv"
)
type MessageType byte
const (
ProtocolIdentifier = "BitTorrent protocol"
ProtocolIdentifierLength = 0x13
Choke MessageType = iota
Unchoke
Interested
NotInterested
Have
Bitfield
Request
Piece
Cancel
)
type Peer struct {
IP uint32
Port uint16
}
func (peer *Peer) Address() string {
bts := make([]byte, 4)
binary.BigEndian.PutUint32(bts, peer.IP)
return net.IP(bts).String() + ":" + strconv.Itoa(int(peer.Port))
}
type Handshake struct {
Pstrlen byte
Pstr [19]byte
Reserved [8]byte
InfoHash [20]byte
PeerID [20]byte
}
type Message struct {
Length uint32
Type byte
Payload []byte
}
func NewHandshake(reserved [8]byte, infoHash [20]byte, peerID [20]byte) *Handshake {
var arr [ProtocolIdentifierLength]byte
copy(arr[:], ProtocolIdentifier)
return &Handshake{
Pstrlen: ProtocolIdentifierLength,
Pstr: arr,
Reserved: reserved,
InfoHash: infoHash,
PeerID: peerID,
}
}
func (handshake *Handshake) encode() ([]byte, error) {
writer := new(bytes.Buffer)
err := binary.Write(writer, binary.BigEndian, handshake)
if err != nil {
return nil, err
}
return writer.Bytes(), nil
}
func (handshake *Handshake) decode(buf []byte) error {
reader := bytes.NewReader(buf)
err := binary.Read(reader, binary.BigEndian, handshake)
if err != nil {
return err
}
return nil
}
func (peer *Peer) DoDownload(metaInfo *MetaInfo, peerId [20]byte) error {
if peer.Port == 0 {
return fmt.Errorf("error port %d", peer.Port)
}
conn, err := net.Dial("tcp", peer.Address())
if err != nil {
return err
}
defer conn.Close()
err = doHandshake(peer, metaInfo, peerId, conn)
if err != nil {
return err
}
scanner := bufio.NewScanner(conn)
scanner.Split(splitMessage)
for scanner.Scan() {
buf := scanner.Bytes()
message := decodeMessage(buf)
// keep-alive message
if message.Length == 0 {
} else {
switch MessageType(buf[4]) {
case Choke:
break
case Unchoke:
break
case Interested:
break
case NotInterested:
break
case Have:
break
case Bitfield:
break
case Request:
break
case Piece:
break
case Cancel:
break
}
}
}
/*var (
// This client is choking the peer
amChocking = true
// This client is interested in the peer
amInterested = false
// Peer is choking this client
peerChocking = true
// Peer is interested in this client
peerInterested = false
)
// Receive message
var cacheBuf []byte
buf := make([]byte, 8192)
for {
scanner := bufio.NewScanner(conn)
n, err := conn.Read(buf)
if n > 0 {
if len(cacheBuf) > 0 {
buf = append(cacheBuf, buf...)
}
msg, err := decodeMessage(buf, n)
if err != nil {
if err == NMD {
cacheBuf = make([]byte, n)
copy(cacheBuf, buf[0:n])
}
return err
}
msgLength := binary.BigEndian.Uint32(buf)
// keep-alive message
if msgLength == 0 {
} else {
switch MessageType(buf[4]) {
case Choke:
peerChocking = true
break
case Unchoke:
peerChocking = false
break
case Interested:
peerInterested = true
break
case NotInterested:
peerInterested = false
break
case Have:
break
case Bitfield:
break
case Request:
break
case Piece:
break
case Cancel:
break
}
}
}
if err != nil {
if err == io.EOF {
return nil
}
return err
}
}*/
return nil
}
// Handshake of Peer wire protocol
// Per https://wiki.theory.org/index.php/BitTorrentSpecification#Handshake
func doHandshake(peer *Peer, metaInfo *MetaInfo, peerId [20]byte, conn net.Conn) error {
reserved := [8]byte{}
reserved[5] = 0x10
reserved[6] = 0x0
reserved[7] = 0x5
handshakeReq := NewHandshake(reserved, metaInfo.InfoHash, peerId)
buf, err := handshakeReq.encode()
if err != nil {
return err
}
conn.Write(buf)
var read [68]byte
_, err = io.ReadFull(conn, read[:])
if err != nil {
return err
}
handshakeRes := new(Handshake)
err = handshakeRes.decode(read[:])
if err != nil {
return err
}
if handshakeRes.InfoHash != handshakeReq.InfoHash {
return err
}
return nil
}
func splitMessage(data []byte, atEOF bool) (advance int, token []byte, err error) {
if !atEOF && len(data) > 4 {
length := int(binary.BigEndian.Uint32(data))
if len(data)-4 >= length {
return length + 4, data[:length+4], nil
}
}
return
}
func decodeMessage(buf []byte) *Message {
msg := &Message{}
msg.Length = binary.BigEndian.Uint32(buf)
// keep-alive message
if msg.Length > 0 {
msg.Type = buf[4]
msg.Payload = buf[5:]
}
return msg
}
func doBitfield(peer *Peer, metaInfo *MetaInfo, conn net.Conn) {
}
+157
View File
@@ -0,0 +1,157 @@
package bt
import (
"encoding/binary"
"fmt"
"log"
"testing"
)
func TestDoDownload(t *testing.T) {
metaInfo, err := ParseFromFile("testdata/Game.of.Thrones.S08E05.720p.WEB.H264-MEMENTO.torrent")
if err != nil {
log.Fatal(err)
}
peers, err := metaInfo.Tracker()
if err != nil {
log.Fatal(err)
}
testPeer := peers[0]
fmt.Println(testPeer.Address())
peerId, err := GenPeerID()
if err != nil {
log.Fatal(err)
}
type fields struct {
IP uint32
Port uint16
}
type args struct {
metaInfo *MetaInfo
peerId [20]byte
}
tests := []struct {
name string
fields fields
args args
wantErr bool
}{
{
"GOTS08E05",
fields{
testPeer.IP,
testPeer.Port,
},
args{
metaInfo,
peerId,
},
false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
peer := &Peer{
IP: tt.fields.IP,
Port: tt.fields.Port,
}
if err := peer.DoDownload(tt.args.metaInfo, tt.args.peerId); (err != nil) != tt.wantErr {
t.Errorf("Peer.DoDownload() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}
func TestFindPeer(t *testing.T) {
metaInfo, err := ParseFromFile("testdata/Game.of.Thrones.S08E05.720p.WEB.H264-MEMENTO.torrent")
if err != nil {
log.Fatal(err)
}
peers, err := metaInfo.Tracker()
if err != nil {
log.Fatal(err)
}
// peerId, err := GenPeerID()
peerId, err := [20]byte{0x2d, 0x55, 0x54, 0x33, 0x35, 0x35, 0x53, 0x2d, 0xaf, 0xb0, 0xec, 0xdc, 0xbf, 0xd1, 0x02, 0x93, 0xd6, 0xf4, 0x9b, 0x24}, nil
if err != nil {
log.Fatal(err)
}
ch := make(chan Peer)
for i, peer := range peers {
go func(i int, peer Peer) {
fmt.Println(peer.Address())
err := peer.DoDownload(metaInfo, peerId)
if err == nil {
ch <- peer
} else {
fmt.Printf("%d:%v\n", i, err)
}
}(i, peer)
}
peer := <-ch
fmt.Println(peer.Address())
}
func TestDoDownloadSpecialPeer(t *testing.T) {
metaInfo, err := ParseFromFile("testdata/Game.of.Thrones.S08E05.720p.WEB.H264-MEMENTO.torrent")
if err != nil {
log.Fatal(err)
}
// 101.188.129.156:14475
testPeer := Peer{
binary.BigEndian.Uint32([]byte{101, 188, 129, 156}),
14475,
}
fmt.Println(testPeer.Address())
peerId, err := GenPeerID()
if err != nil {
log.Fatal(err)
}
type fields struct {
IP uint32
Port uint16
}
type args struct {
metaInfo *MetaInfo
peerId [20]byte
}
tests := []struct {
name string
fields fields
args args
wantErr bool
}{
{
"GOTS08E05",
fields{
testPeer.IP,
testPeer.Port,
},
args{
metaInfo,
peerId,
},
false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
peer := &Peer{
IP: tt.fields.IP,
Port: tt.fields.Port,
}
if err := peer.DoDownload(tt.args.metaInfo, tt.args.peerId); (err != nil) != tt.wantErr {
t.Errorf("Peer.DoDownload() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}
+128 -95
View File
@@ -32,7 +32,7 @@ const (
8 32-bit integer action 0 // connect
12 32-bit integer transaction_id
16
Detail see https://www.libtorrent.org/udp_tracker_protocol.html#connecting
Per https://www.libtorrent.org/udp_tracker_protocol.html#connecting
*/
type UdpConnectRequest struct {
ProtocolId uint64
@@ -93,7 +93,7 @@ func NewUdpConnectResponse(buf []byte) *UdpConnectResponse {
92 32-bit integer num_want -1 // default
96 16-bit integer port
98
Detail see https://www.libtorrent.org/udp_tracker_protocol.html#announcing
Per https://www.libtorrent.org/udp_tracker_protocol.html#announcing
*/
type UdpAnnounceRequest struct {
ConnectionId uint64
@@ -147,6 +147,7 @@ func (req *UdpAnnounceRequest) encode() []byte {
20 + 6 * n 32-bit integer IP address
24 + 6 * n 16-bit integer TCP port
20 + 6 * N
Per https://www.libtorrent.org/udp_tracker_protocol.html#announcing
*/
type UdpAnnounceResponse struct {
Action uint32
@@ -154,8 +155,7 @@ type UdpAnnounceResponse struct {
Interval uint32
Leechers uint32
Seeders uint32
IP []uint32
Port []uint16
Peers []Peer
}
func NewUdpAnnounceResponse(buf []byte) *UdpAnnounceResponse {
@@ -167,48 +167,33 @@ func NewUdpAnnounceResponse(buf []byte) *UdpAnnounceResponse {
Seeders: binary.BigEndian.Uint32(buf[16:20]),
}
count := (len(buf) - 20) / 6
response.IP = make([]uint32, count, count)
response.Port = make([]uint16, count, count)
response.Peers = make([]Peer, count, count)
for i := 0; i < count; i++ {
begin := 20 + 6*i
response.IP[i] = binary.BigEndian.Uint32(buf[begin : begin+4])
response.Port[i] = binary.BigEndian.Uint16(buf[begin+4 : begin+6])
ipBegin := 20 + 6*i
portBegin := ipBegin + 4
response.Peers[i] = Peer{
IP: binary.BigEndian.Uint32(buf[ipBegin:portBegin]),
Port: binary.BigEndian.Uint16(buf[portBegin : portBegin+2]),
}
}
return response
}
type UdpTrackerContent struct {
URL *url.URL
MetaInfo *MetaInfo
Conn *net.UDPConn
ConnectRequest *UdpConnectRequest
ConnectResponse *UdpConnectResponse
AnnounceRequest *UdpAnnounceRequest
AnnounceResponse *UdpAnnounceResponse
}
func NewUdpTrackerContent(url *url.URL, metaInfo *MetaInfo) *UdpTrackerContent {
return &UdpTrackerContent{
URL: url,
MetaInfo: metaInfo,
}
}
func (content *UdpTrackerContent) connect() error {
host, portStr, err := net.SplitHostPort(content.URL.Host)
func dial(trackerUrl *url.URL) (*net.UDPConn, error) {
host, portStr, err := net.SplitHostPort(trackerUrl.Host)
if err != nil {
fmt.Println(err)
return err
return nil, err
}
port, err := strconv.ParseInt(portStr, 10, 32)
if err != nil {
fmt.Println(err)
return err
return nil, err
}
ip, err := lookupIP(host, content.URL.Scheme)
ip, err := lookupIP(host, trackerUrl.Scheme)
if err != nil {
fmt.Println(err)
return err
return nil, err
}
srcAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0}
@@ -216,87 +201,99 @@ func (content *UdpTrackerContent) connect() error {
IP: ip,
Port: int(port),
}
conn, err := net.DialUDP(content.URL.Scheme, srcAddr, dstAddr)
if err != nil {
fmt.Println(err)
return err
}
// Connect
request := NewUdpConnectRequest()
var response *UdpConnectResponse
for n := 0; n < udpConnectRetries; n++ {
buf := request.Encode()
conn.Write(buf)
// 15 * 2 ^ n seconds
timeout := udpConnectTimeout * math.Pow(2, float64(n))
conn.SetReadDeadline(time.Now().Add(time.Second * time.Duration(timeout)))
len, err := conn.Read(buf)
if len == 16 && err == nil {
response = NewUdpConnectResponse(buf)
break
}
}
if response == nil {
conn.Close()
return errors.New("UDP tracker connect error")
}
if response.Action != udpActionConnect || request.TransactionId != response.TransactionId {
conn.Close()
return errors.New("UDP tracker connect response error")
}
content.Conn = conn
content.ConnectRequest = request
content.ConnectResponse = response
return nil
return net.DialUDP(trackerUrl.Scheme, srcAddr, dstAddr)
}
func (content *UdpTrackerContent) announce() error {
request := NewUdpAnnounceRequest(content.ConnectResponse.ConnectionId)
request.InfoHash = content.MetaInfo.InfoHash
peerID, err := genPeerID()
func connect(conn *net.UDPConn, timeout int64) (response *UdpConnectResponse, err error) {
request := NewUdpConnectRequest()
buf := request.Encode()
conn.SetReadDeadline(time.Now().Add(time.Second * time.Duration(timeout)))
conn.Write(buf)
len, err := conn.Read(buf)
if err != nil {
return
}
if len != 16 {
err = NewTrackerError(ErrResponse, errors.New("invalid response"))
return
}
response = NewUdpConnectResponse(buf)
return
}
func announce(conn *net.UDPConn, timeout int64, connectionId uint64, metaInfo *MetaInfo) (response *UdpAnnounceResponse, err error) {
request := NewUdpAnnounceRequest(connectionId)
request.InfoHash = metaInfo.InfoHash
peerID, err := GenPeerID()
if err != nil {
fmt.Println(err)
return err
return
}
request.PeerID = peerID
request.Downloaded = 0
request.Uploaded = 0
request.Left = content.MetaInfo.GetTotalSize() - request.Downloaded
request.Left = metaInfo.GetTotalSize() - request.Downloaded
request.Event = 0
request.IP = 0
request.Key = 0
request.NumWant = 50
request.Port = 6882
encode := request.encode()
content.Conn.Write(encode)
conn.SetReadDeadline(time.Now().Add(time.Second * time.Duration(timeout)))
conn.Write(encode)
buf := make([]byte, 512)
len, err := content.Conn.Read(buf)
len, err := conn.Read(buf)
if err != nil {
fmt.Println(err)
return err
return
}
response := NewUdpAnnounceResponse(buf[:len])
fmt.Println(response)
return nil
response = NewUdpAnnounceResponse(buf[:len])
return
}
func DoTracker(announce string, metaInfo *MetaInfo) {
func (metaInfo *MetaInfo) Tracker() (peers []Peer, err error) {
if len(metaInfo.AnnounceList) > 0 {
for _, announceArr := range metaInfo.AnnounceList {
if len(announceArr) > 0 {
for _, announce := range announceArr {
peers, err = doTracker(announce, metaInfo)
if err == nil {
return
}
}
}
}
} else {
peers, err = doTracker(metaInfo.Announce, metaInfo)
if err == nil {
return
}
}
return
}
func doTracker(announce string, metaInfo *MetaInfo) (peers []Peer, err error) {
if announce != "" {
url, _ := url.Parse(announce)
switch url.Scheme {
case "http", "https":
// TODO UDP test
break
httpTracker(url, metaInfo)
return httpTracker(url, metaInfo)
case "udp", "udp4", "udp6":
udpTracker(url, metaInfo)
return udpTracker(url, metaInfo)
default:
return nil, errors.New("unsupported protocol")
}
}
return nil, errors.New("empty announce")
}
func genPeerID() ([20]byte, error) {
peerId := [20]byte{'G', 'P', '0', '0', '1'}
_, err := rand.Read(peerId[5:])
// 生成Peer ID,规则为前三位固定字母(-GP)+SemVer(xyz),后面随机生成
// 参考:https://wiki.theory.org/index.php/BitTorrentSpecification#peer_id
func GenPeerID() ([20]byte, error) {
peerId := [20]byte{'-', 'G', 'P', '0', '0', '1'}
_, err := rand.Read(peerId[6:])
if err != nil {
return peerId, err
}
@@ -304,13 +301,12 @@ func genPeerID() ([20]byte, error) {
}
// http://bittorrent.org/beps/bep_0003.html#trackers
func httpTracker(url *url.URL, metaInfo *MetaInfo) {
func httpTracker(url *url.URL, metaInfo *MetaInfo) (peers []Peer, err error) {
query := url.Query()
query.Add("info_hash", string(metaInfo.InfoHash[:]))
// Generate peer ID
peerID, err := genPeerID()
peerID, err := GenPeerID()
if err != nil {
fmt.Println(err)
return
}
query.Add("peer_id", string(peerID[:]))
@@ -321,39 +317,76 @@ func httpTracker(url *url.URL, metaInfo *MetaInfo) {
url.RawQuery = query.Encode()
request, err := http.NewRequest("GET", url.String(), nil)
if err != nil {
fmt.Println(err)
return
}
var httpClient = &http.Client{
Timeout: time.Second * time.Duration(15),
}
request.Header.Set("User-Agent", "gopeed/0.0.1")
fmt.Println("request:" + url.String())
response, err := httpClient.Do(request)
if err != nil {
fmt.Println(err)
return
}
defer response.Body.Close()
resp, err := ioutil.ReadAll(response.Body)
if err != nil {
if err != io.EOF {
fmt.Println(err)
return
}
}
fmt.Println(string(resp))
// TODO Parse HTTP tracker response
fmt.Println(resp)
return nil, nil
}
// http://bittorrent.org/beps/bep_0015.html
func udpTracker(url *url.URL, metaInfo *MetaInfo) {
content := NewUdpTrackerContent(url, metaInfo)
err := content.connect()
func udpTracker(url *url.URL, metaInfo *MetaInfo) (peers []Peer, err error) {
conn, err := dial(url)
if err != nil {
fmt.Println(err)
return
}
content.announce()
announceResponse, err := func() (announceResponse *UdpAnnounceResponse, err error) {
var connectResponse *UdpConnectResponse
// 0:connect 1:announce
state := 0
// 访问超时最多重试8次,当有请求成功则将重试次数重置为0
for n := 0; n < udpConnectRetries; n++ {
// 15 * 2 ^ n seconds
timeout := int64(udpConnectTimeout * math.Pow(2, float64(n)))
switch state {
case 0:
connectResponse, err = connect(conn, timeout)
if err != nil {
if oe, ok := err.(*net.OpError); ok && oe.Timeout() {
break
} else {
return
}
}
n = -1
state = 1
break
case 1:
announceResponse, err = announce(conn, timeout, connectResponse.ConnectionId, metaInfo)
if err != nil {
if oe, ok := err.(*net.OpError); ok && oe.Timeout() {
break
} else {
return
}
}
return
}
}
return
}()
if err != nil {
return
}
return announceResponse.Peers, nil
}
func lookupIP(host string, scheme string) (ip net.IP, err error) {
+4 -4
View File
@@ -33,7 +33,7 @@ func Resolve(request *Request) (*Response, error) {
}
defer response.Body.Close()
if response.StatusCode != 200 && response.StatusCode != 206 {
return nil, fmt.Errorf("Response status error:%d", response.StatusCode)
return nil, fmt.Errorf("response status error:%d", response.StatusCode)
}
ret := &Response{}
// Get file name by "Content-Disposition"
@@ -165,10 +165,10 @@ func downChunk(request *Request, file *os.File, start int64, end int64, waitGrou
buf := make([]byte, 8192)
writeIndex := int64(start)
for {
len, err := httpResponse.Body.Read(buf)
if len > 0 {
n, err := httpResponse.Body.Read(buf)
if n > 0 {
fileLock.Lock()
writeSize, err := file.WriteAt(buf[0:len], writeIndex)
writeSize, err := file.WriteAt(buf[0:n], writeIndex)
fileLock.Unlock()
if err != nil {
fmt.Println(err)
+11 -15
View File
@@ -104,28 +104,24 @@ func TestResolve(t *testing.T) {
}
func TestTemp(t *testing.T) {
f, err := os.Create("e:/data/test.data")
f, err := os.Create("e:/testbt/test.data")
if err != nil {
log.Fatal(err)
}
s := time.Now().UnixNano()
if err := f.Truncate(1024 * 1024 * 1024 * 1); err != nil {
if err := f.Truncate(1024 * 1024 * 512); err != nil {
log.Fatal(err)
}
fmt.Printf("use %d\n", time.Now().UnixNano()-s)
bts := []byte{1, 2, 3, 4, 5, 6, 7, 8, 9}
s := time.Now().UnixNano()
f.Write(bts)
fmt.Printf("write from 0 use: %d\n", time.Now().UnixNano()-s)
s = time.Now().UnixNano()
f.Write([]byte{1})
fmt.Printf("use %d\n", time.Now().UnixNano()-s)
s = time.Now().UnixNano()
f.Seek(1024*1024*512, 0)
fmt.Printf("use %d\n", time.Now().UnixNano()-s)
s = time.Now().UnixNano()
f.Write([]byte{2})
fmt.Printf("use %d\n", time.Now().UnixNano()-s)
s = time.Now().UnixNano()
f.Write([]byte{3})
fmt.Printf("use %d\n", time.Now().UnixNano()-s)
f.Seek(1024*1024*128, 0)
f.Write(bts)
fmt.Printf("write from 128M use %d\n", time.Now().UnixNano()-s)
s = time.Now().UnixNano()
f.Write(bts)
fmt.Printf("write from 128M+9b use %d\n", time.Now().UnixNano()-s)
}
func fileMd5(filePath string) string {
+1 -4
View File
@@ -2,7 +2,4 @@ module gopeed
go 1.12
require (
github.com/marksamman/bencode v0.0.0-20150821143521-dc84f26e086e
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09
)
require github.com/marksamman/bencode v0.0.0-20150821143521-dc84f26e086e
-5
View File
@@ -1,7 +1,2 @@
github.com/marksamman/bencode v0.0.0-20150821143521-dc84f26e086e h1:KMs6SK8iDSR1+ZzOK10L5wGPpWDByyvOe5nrqk51g2U=
github.com/marksamman/bencode v0.0.0-20150821143521-dc84f26e086e/go.mod h1:+AHfJo5+69p+fjvMJTmYajNP9rFBHQcaTDFmuXRRATI=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09 h1:KaQtG+aDELoNmXYas3TVkGNYRuq8JQ1aa7LJt8EXVyo=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=