func announceHTTP(ar *AnnounceRequest, _url *url.URL, host string) (ret AnnounceResponse, err error) { _url = httptoo.CopyURL(_url) setAnnounceParams(_url, ar) req, err := http.NewRequest("GET", _url.String(), nil) req.Host = host resp, err := http.DefaultClient.Do(req) if err != nil { return } defer resp.Body.Close() var buf bytes.Buffer io.Copy(&buf, resp.Body) if resp.StatusCode != 200 { err = fmt.Errorf("response from tracker: %s: %s", resp.Status, buf.String()) return } var trackerResponse httpResponse err = bencode.Unmarshal(buf.Bytes(), &trackerResponse) if err != nil { err = fmt.Errorf("error decoding %q: %s", buf.Bytes(), err) return } if trackerResponse.FailureReason != "" { err = errors.New(trackerResponse.FailureReason) return } ret.Interval = trackerResponse.Interval ret.Leechers = trackerResponse.Incomplete ret.Seeders = trackerResponse.Complete ret.Peers, err = trackerResponse.UnmarshalPeers() return }
func TestUnmarshalGetPeersResponse(t *testing.T) { var msg Msg err := bencode.Unmarshal([]byte("d1:rd6:valuesl6:\x01\x02\x03\x04\x05\x066:\x07\x08\x09\x0a\x0b\x0ce5:nodes52:\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x02\x03\x04\x05\x06\x07\x08\x09\x02\x03\x04\x05\x06\x07\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x02\x03\x04\x05\x06\x07\x08\x09\x02\x03\x04\x05\x06\x07ee"), &msg) require.NoError(t, err) assert.Len(t, msg.R.Values, 2) assert.Len(t, msg.R.Nodes, 2) assert.Nil(t, msg.E) }
func (me *CompactPeer) UnmarshalBencode(b []byte) (err error) { var _b []byte err = bencode.Unmarshal(b, &_b) if err != nil { return } return me.UnmarshalBinary(_b) }
func TestUnmarshalPex(t *testing.T) { var pem peerExchangeMessage err := bencode.Unmarshal([]byte("d5:added12:\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0ce"), &pem) require.NoError(t, err) require.EqualValues(t, 2, len(pem.Added)) require.EqualValues(t, 1286, pem.Added[0].Port) require.EqualValues(t, 0x100*0xb+0xc, pem.Added[1].Port) }
// This allows bencode.Unmarshal to do better than a string or []byte. func (me *CompactIPv4Peers) UnmarshalBencode(b []byte) (err error) { var bb []byte err = bencode.Unmarshal(b, &bb) if err != nil { return } *me, err = UnmarshalIPv4CompactPeers(bb) return }
func (me *CompactPeers) UnmarshalBencode(bb []byte) (err error) { var b []byte err = bencode.Unmarshal(bb, &b) if err != nil { return } err = me.UnmarshalBinary(b) return }
// Called when metadata for a torrent becomes available. func (t *Torrent) setInfoBytes(b []byte) error { if t.haveInfo() { return nil } var ie *metainfo.InfoEx err := bencode.Unmarshal(b, &ie) if err != nil { return fmt.Errorf("error unmarshalling info bytes: %s", err) } if ie.Hash() != t.infoHash { return errors.New("info bytes have wrong hash") } err = validateInfo(&ie.Info) if err != nil { return fmt.Errorf("bad info: %s", err) } defer t.updateWantPeersEvent() t.info = ie t.cl.event.Broadcast() t.gotMetainfo.Set() t.storage, err = t.storageOpener.OpenTorrent(t.info) if err != nil { return fmt.Errorf("error opening torrent storage: %s", err) } t.length = 0 for _, f := range t.info.UpvertedFiles() { t.length += f.Length } t.metadataBytes = b t.metadataCompletedChunks = nil hashes := infoPieceHashes(&t.info.Info) t.pieces = make([]piece, len(hashes)) for i, hash := range hashes { piece := &t.pieces[i] piece.t = t piece.index = i piece.noPendingWrites.L = &piece.pendingWritesMutex missinggo.CopyExact(piece.Hash[:], hash) } for _, conn := range t.conns { if err := conn.setNumPieces(t.numPieces()); err != nil { log.Printf("closing connection: %s", err) conn.Close() } } for i := range t.pieces { t.updatePieceCompletion(i) t.pieces[i].QueuedForHash = true } go func() { for i := range t.pieces { t.verifyPiece(i) } }() return nil }
func testMarshalUnmarshalMsg(t *testing.T, m Msg, expected string) { b, err := bencode.Marshal(m) require.NoError(t, err) assert.Equal(t, expected, string(b)) var _m Msg err = bencode.Unmarshal([]byte(expected), &_m) assert.NoError(t, err) assert.EqualValues(t, m, _m) assert.EqualValues(t, m.R, _m.R) }
func (this *InfoEx) UnmarshalBencode(data []byte) error { this.Bytes = append(make([]byte, 0, len(data)), data...) h := sha1.New() _, err := h.Write(this.Bytes) if err != nil { panic(err) } this.Hash = new(Hash) missinggo.CopyExact(this.Hash, h.Sum(nil)) return bencode.Unmarshal(data, &this.Info) }
func (this *InfoEx) UnmarshalBencode(data []byte) error { this.Bytes = make([]byte, 0, len(data)) this.Bytes = append(this.Bytes, data...) h := sha1.New() _, err := h.Write(this.Bytes) if err != nil { panic(err) } this.Hash = h.Sum(nil) return bencode.Unmarshal(data, &this.Info) }
func TestUnmarshalPEXMsg(t *testing.T) { var m peerExchangeMessage if err := bencode.Unmarshal([]byte("d5:added12:\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0ce"), &m); err != nil { t.Fatal(err) } if len(m.Added) != 2 { t.FailNow() } if m.Added[0].Port != 0x506 { t.FailNow() } }
func (s *Server) processPacket(b []byte, addr Addr) { if len(b) < 2 || b[0] != 'd' || b[len(b)-1] != 'e' { // KRPC messages are bencoded dicts. readNotKRPCDict.Add(1) return } var d krpc.Msg err := bencode.Unmarshal(b, &d) if err != nil { readUnmarshalError.Add(1) func() { if se, ok := err.(*bencode.SyntaxError); ok { // The message was truncated. if int(se.Offset) == len(b) { return } // Some messages seem to drop to nul chars abrubtly. if int(se.Offset) < len(b) && b[se.Offset] == 0 { return } // The message isn't bencode from the first. if se.Offset == 0 { return } } // if missinggo.CryHeard() { // log.Printf("%s: received bad krpc message from %s: %s: %+q", s, addr, err, b) // } }() return } s.mu.Lock() defer s.mu.Unlock() if s.closed.IsSet() { return } if d.Y == "q" { readQuery.Add(1) s.handleQuery(addr, d) return } t := s.findResponseTransaction(d.T, addr) if t == nil { //log.Printf("unexpected message: %#v", d) return } node := s.getNode(addr, d.SenderID()) node.lastGotResponse = time.Now() // TODO: Update node ID as this is an authoritative packet. go t.handleResponse(d) s.deleteTransaction(t) }
// Called when metadata for a torrent becomes available. func (t *Torrent) setInfoBytes(b []byte) error { if t.haveInfo() { return nil } var ie *metainfo.InfoEx err := bencode.Unmarshal(b, &ie) if err != nil { return fmt.Errorf("error unmarshalling info bytes: %s", err) } if ie.Hash() != t.infoHash { return errors.New("info bytes have wrong hash") } err = validateInfo(&ie.Info) if err != nil { return fmt.Errorf("bad info: %s", err) } defer t.updateWantPeersEvent() t.info = ie t.displayName = "" // Save a few bytes lol. t.cl.event.Broadcast() t.gotMetainfo.Set() t.storage, err = t.storageOpener.OpenTorrent(t.info) if err != nil { return fmt.Errorf("error opening torrent storage: %s", err) } t.length = 0 for _, f := range t.info.UpvertedFiles() { t.length += f.Length } t.metadataBytes = b t.metadataCompletedChunks = nil t.makePieces() for _, conn := range t.conns { if err := conn.setNumPieces(t.numPieces()); err != nil { log.Printf("closing connection: %s", err) conn.Close() } } for i := range t.pieces { t.updatePieceCompletion(i) t.pieces[i].QueuedForHash = true } go func() { for i := range t.pieces { t.verifyPiece(i) } }() return nil }
func (e *KRPCError) UnmarshalBencode(_b []byte) (err error) { var _v interface{} err = bencode.Unmarshal(_b, &_v) if err != nil { return } switch v := _v.(type) { case []interface{}: e.Code = int(v[0].(int64)) e.Msg = v[1].(string) case string: e.Msg = v default: err = fmt.Errorf(`KRPC error bencode value has unexpected type: %T`, _v) } return }
func (me *httpClient) Announce(ar *AnnounceRequest) (ret AnnounceResponse, err error) { // retain query parameters from announce URL q := me.url.Query() q.Set("info_hash", string(ar.InfoHash[:])) q.Set("peer_id", string(ar.PeerId[:])) q.Set("port", fmt.Sprintf("%d", ar.Port)) q.Set("uploaded", strconv.FormatInt(ar.Uploaded, 10)) q.Set("downloaded", strconv.FormatInt(ar.Downloaded, 10)) q.Set("left", strconv.FormatUint(ar.Left, 10)) if ar.Event != None { q.Set("event", ar.Event.String()) } // http://stackoverflow.com/questions/17418004/why-does-tracker-server-not-understand-my-request-bittorrent-protocol q.Set("compact", "1") // According to https://wiki.vuze.com/w/Message_Stream_Encryption. q.Set("supportcrypto", "1") var reqURL url.URL = me.url reqURL.RawQuery = q.Encode() resp, err := http.Get(reqURL.String()) if err != nil { return } defer resp.Body.Close() buf := bytes.Buffer{} io.Copy(&buf, resp.Body) if resp.StatusCode != 200 { err = fmt.Errorf("response from tracker: %s: %s", resp.Status, buf.String()) return } var trackerResponse httpResponse err = bencode.Unmarshal(buf.Bytes(), &trackerResponse) if err != nil { err = fmt.Errorf("error decoding %q: %s", buf.Bytes(), err) return } if trackerResponse.FailureReason != "" { err = errors.New(trackerResponse.FailureReason) return } ret.Interval = trackerResponse.Interval ret.Leechers = trackerResponse.Incomplete ret.Seeders = trackerResponse.Complete ret.Peers, err = trackerResponse.UnmarshalPeers() return }
// Process incoming ut_metadata message. func (cl *Client) gotMetadataExtensionMsg(payload []byte, t *Torrent, c *connection) (err error) { var d map[string]int err = bencode.Unmarshal(payload, &d) if err != nil { err = fmt.Errorf("error unmarshalling payload: %s: %q", err, payload) return } msgType, ok := d["msg_type"] if !ok { err = errors.New("missing msg_type field") return } piece := d["piece"] switch msgType { case pp.DataMetadataExtensionMsgType: if !c.requestedMetadataPiece(piece) { err = fmt.Errorf("got unexpected piece %d", piece) return } c.metadataRequests[piece] = false begin := len(payload) - metadataPieceSize(d["total_size"], piece) if begin < 0 || begin >= len(payload) { err = fmt.Errorf("data has bad offset in payload: %d", begin) return } t.saveMetadataPiece(piece, payload[begin:]) c.UsefulChunksReceived++ c.lastUsefulChunkReceived = time.Now() t.maybeMetadataCompleted() case pp.RequestMetadataExtensionMsgType: if !t.haveMetadataPiece(piece) { c.Post(t.newMetadataExtensionMessage(c, pp.RejectMetadataExtensionMsgType, d["piece"], nil)) break } start := (1 << 14) * piece c.Post(t.newMetadataExtensionMessage(c, pp.DataMetadataExtensionMsgType, piece, t.metadataBytes[start:start+t.metadataPieceSize(piece)])) case pp.RejectMetadataExtensionMsgType: default: err = errors.New("unknown msg_type value") } return }
func (s *Server) processPacket(b []byte, addr dHTAddr) { var d Msg err := bencode.Unmarshal(b, &d) if err != nil { readUnmarshalError.Add(1) func() { if se, ok := err.(*bencode.SyntaxError); ok { // The message was truncated. if int(se.Offset) == len(b) { return } // Some messages seem to drop to nul chars abrubtly. if int(se.Offset) < len(b) && b[se.Offset] == 0 { return } // The message isn't bencode from the first. if se.Offset == 0 { return } } log.Printf("%s: received bad krpc message from %s: %s: %+q", s, addr, err, b) }() return } s.mu.Lock() defer s.mu.Unlock() if d["y"] == "q" { readQuery.Add(1) s.handleQuery(addr, d) return } t := s.findResponseTransaction(d.T(), addr) if t == nil { //log.Printf("unexpected message: %#v", d) return } node := s.getNode(addr, d.ID()) node.lastGotResponse = time.Now() // TODO: Update node ID as this is an authoritative packet. go t.handleResponse(d) s.deleteTransaction(t) }
func (i *CompactIPv4NodeInfo) UnmarshalBencode(_b []byte) (err error) { var b []byte err = bencode.Unmarshal(_b, &b) if err != nil { return } if len(b)%CompactIPv4NodeInfoLen != 0 { err = fmt.Errorf("bad length: %d", len(b)) return } for k := 0; k < len(b); k += CompactIPv4NodeInfoLen { var ni NodeInfo err = ni.UnmarshalCompactIPv4(b[k : k+CompactIPv4NodeInfoLen]) if err != nil { return } *i = append(*i, ni) } return }
func (me *CompactIPv4NodeInfo) UnmarshalBencode(_b []byte) (err error) { var b []byte err = bencode.Unmarshal(_b, &b) if err != nil { return } if len(b)%CompactIPv4NodeInfoLen != 0 { err = fmt.Errorf("bad length: %d", len(b)) return } for i := 0; i < len(b); i += CompactIPv4NodeInfoLen { var ni NodeInfo err = ni.UnmarshalCompactIPv4(b[i : i+CompactIPv4NodeInfoLen]) if err != nil { return } *me = append(*me, ni) } return }
func (me *Node) UnmarshalBencode(b []byte) (err error) { var iface interface{} err = bencode.Unmarshal(b, &iface) if err != nil { return } switch v := iface.(type) { case string: *me = Node(v) case []interface{}: func() { defer func() { r := recover() if r != nil { err = r.(error) } }() *me = Node(net.JoinHostPort(v[0].(string), strconv.FormatInt(v[1].(int64), 10))) }() default: err = fmt.Errorf("unsupported type: %T", iface) } return }
// Processes incoming bittorrent messages. The client lock is held upon entry // and exit. Returning will end the connection. func (cl *Client) connectionLoop(t *Torrent, c *connection) error { decoder := pp.Decoder{ R: bufio.NewReader(c.rw), MaxLength: 256 * 1024, } for { cl.mu.Unlock() var msg pp.Message err := decoder.Decode(&msg) cl.mu.Lock() if cl.closed.IsSet() || c.closed.IsSet() || err == io.EOF { return nil } if err != nil { return err } c.lastMessageReceived = time.Now() if msg.Keepalive { receivedKeepalives.Add(1) continue } receivedMessageTypes.Add(strconv.FormatInt(int64(msg.Type), 10), 1) switch msg.Type { case pp.Choke: c.PeerChoked = true c.Requests = nil // We can then reset our interest. c.updateRequests() case pp.Reject: cl.connDeleteRequest(t, c, newRequest(msg.Index, msg.Begin, msg.Length)) c.updateRequests() case pp.Unchoke: c.PeerChoked = false cl.peerUnchoked(t, c) case pp.Interested: c.PeerInterested = true cl.upload(t, c) case pp.NotInterested: c.PeerInterested = false c.Choke() case pp.Have: err = c.peerSentHave(int(msg.Index)) case pp.Request: if c.Choked { break } if !c.PeerInterested { err = errors.New("peer sent request but isn't interested") break } if !t.havePiece(msg.Index.Int()) { // This isn't necessarily them screwing up. We can drop pieces // from our storage, and can't communicate this to peers // except by reconnecting. requestsReceivedForMissingPieces.Add(1) err = errors.New("peer requested piece we don't have") break } if c.PeerRequests == nil { c.PeerRequests = make(map[request]struct{}, maxRequests) } c.PeerRequests[newRequest(msg.Index, msg.Begin, msg.Length)] = struct{}{} cl.upload(t, c) case pp.Cancel: req := newRequest(msg.Index, msg.Begin, msg.Length) if !c.PeerCancel(req) { unexpectedCancels.Add(1) } case pp.Bitfield: err = c.peerSentBitfield(msg.Bitfield) case pp.HaveAll: err = c.peerSentHaveAll() case pp.HaveNone: err = c.peerSentHaveNone() case pp.Piece: cl.downloadedChunk(t, c, &msg) case pp.Extended: switch msg.ExtendedID { case pp.HandshakeExtendedID: // TODO: Create a bencode struct for this. var d map[string]interface{} err = bencode.Unmarshal(msg.ExtendedPayload, &d) if err != nil { err = fmt.Errorf("error decoding extended message payload: %s", err) break } // log.Printf("got handshake from %q: %#v", c.Socket.RemoteAddr().String(), d) if reqq, ok := d["reqq"]; ok { if i, ok := reqq.(int64); ok { c.PeerMaxRequests = int(i) } } if v, ok := d["v"]; ok { c.PeerClientName = v.(string) } m, ok := d["m"] if !ok { err = errors.New("handshake missing m item") break } mTyped, ok := m.(map[string]interface{}) if !ok { err = errors.New("handshake m value is not dict") break } if c.PeerExtensionIDs == nil { c.PeerExtensionIDs = make(map[string]byte, len(mTyped)) } for name, v := range mTyped { id, ok := v.(int64) if !ok { log.Printf("bad handshake m item extension ID type: %T", v) continue } if id == 0 { delete(c.PeerExtensionIDs, name) } else { if c.PeerExtensionIDs[name] == 0 { supportedExtensionMessages.Add(name, 1) } c.PeerExtensionIDs[name] = byte(id) } } metadata_sizeUntyped, ok := d["metadata_size"] if ok { metadata_size, ok := metadata_sizeUntyped.(int64) if !ok { log.Printf("bad metadata_size type: %T", metadata_sizeUntyped) } else { err = t.setMetadataSize(metadata_size) if err != nil { err = fmt.Errorf("error setting metadata size to %d", metadata_size) break } } } if _, ok := c.PeerExtensionIDs["ut_metadata"]; ok { c.requestPendingMetadata() } case metadataExtendedId: err = cl.gotMetadataExtensionMsg(msg.ExtendedPayload, t, c) if err != nil { err = fmt.Errorf("error handling metadata extension message: %s", err) } case pexExtendedId: if cl.config.DisablePEX { break } var pexMsg peerExchangeMessage err = bencode.Unmarshal(msg.ExtendedPayload, &pexMsg) if err != nil { err = fmt.Errorf("error unmarshalling PEX message: %s", err) break } go func() { cl.mu.Lock() t.addPeers(func() (ret []Peer) { for i, cp := range pexMsg.Added { p := Peer{ IP: make([]byte, 4), Port: cp.Port, Source: peerSourcePEX, } if i < len(pexMsg.AddedFlags) && pexMsg.AddedFlags[i]&0x01 != 0 { p.SupportsEncryption = true } missinggo.CopyExact(p.IP, cp.IP[:]) ret = append(ret, p) } return }()) cl.mu.Unlock() }() default: err = fmt.Errorf("unexpected extended message ID: %v", msg.ExtendedID) } if err != nil { // That client uses its own extension IDs for outgoing message // types, which is incorrect. if bytes.HasPrefix(c.PeerID[:], []byte("-SD0100-")) || strings.HasPrefix(string(c.PeerID[:]), "-XL0012-") { return nil } } case pp.Port: if cl.dHT == nil { break } pingAddr, err := net.ResolveUDPAddr("", c.remoteAddr().String()) if err != nil { panic(err) } if msg.Port != 0 { pingAddr.Port = int(msg.Port) } cl.dHT.Ping(pingAddr) default: err = fmt.Errorf("received unknown message type: %#v", msg.Type) } if err != nil { return err } } }
func TestUnmarshalBadMetainfoNodes(t *testing.T) { var mi MetaInfo // Should barf on the integer in the nodes list. err := bencode.Unmarshal([]byte("d5:nodesl1:ai42eee"), &mi) require.Error(t, err) }
func (ie *InfoEx) UnmarshalBencode(data []byte) error { ie.Bytes = append([]byte(nil), data...) return bencode.Unmarshal(data, &ie.Info) }