func (t *TorrentSession) reload(metadata string) (err error) { var info InfoDict err = bencode.Unmarshal(bytes.NewReader([]byte(metadata)), &info) if err != nil { log.Println("Error when reloading torrent: ", err) return } t.M.Info = info err = t.load() return }
// Extract - Extracts DHTMessage from received packet func (dht *DHTClient) Extract(b []byte) (response DHTMessage, err error) { defer func() { if x := recover(); x != nil { Log(Error, "Bencode Unmarshal failed %q, %v", string(b), x) } }() var e2 error if e2 = bencode.Unmarshal(bytes.NewBuffer(b), &response); e2 == nil { err = nil return } Log(Debug, "Received from peer: %v %q", response, e2) return response, e2 }
// Read responses from bencode-speaking nodes. Return the appropriate data structure. func readResponse(p packetType) (response responseType, err error) { // The calls to bencode.Unmarshal() can be fragile. defer func() { if x := recover(); x != nil { log.V(3).Infof("DHT: !!! Recovering from panic() after bencode.Unmarshal %q, %v", string(p.b), x) } }() if e2 := bencode.Unmarshal(bytes.NewBuffer(p.b), &response); e2 == nil { err = nil return } else { log.V(3).Infof("DHT: unmarshal error, odd or partial data during UDP read? %v, err=%s", string(p.b), e2) return response, e2 } return }
func (ts *TorrentSession) reload(metadata string) (err error) { var info InfoDict err = bencode.Unmarshal(bytes.NewReader([]byte(metadata)), &info) if err != nil { log.Println("[", ts.M.Info.Name, "] Error when reloading torrent: ", err) return } ts.M.Info = info err = ts.load() if ts.flags.Cacher != nil && ts.fileStore != nil { ts.fileStore = ts.flags.Cacher.NewCache(ts.M.InfoHash, ts.totalPieces, ts.M.Info.PieceLength, ts.totalSize, ts.fileStore) } return }
func (t *TorrentSession) DoPex(msg []byte, p *peerState) { var message PexMessage err := bencode.Unmarshal(bytes.NewReader(msg), &message) if err != nil { log.Println("Error when parsing pex: ", err) return } for _, peer := range stringToPeers(message.Added) { t.hintNewPeer(peer) } // We don't use those yet, but this is possibly how we would //for _, flag := range stringToFlags(message.AddedF) { //log.Printf("Got flags: %#v", flag) //} }
func saveMetaInfo(metadata string) (err error) { var info InfoDict err = bencode.Unmarshal(bytes.NewReader([]byte(metadata)), &info) if err != nil { return } f, err := os.Create(info.Name + ".torrent") if err != nil { log.Println("Error when opening file for creation: ", err) return } defer f.Close() _, err = f.WriteString(metadata) return }
func (ts *TorrentSession) DoExtension(msg []byte, p *peerState) (err error) { var h ExtensionHandshake if msg[0] == EXTENSION_HANDSHAKE { err = bencode.Unmarshal(bytes.NewReader(msg[1:]), &h) if err != nil { log.Println("[", ts.M.Info.Name, "] Error when unmarshaling extension handshake") return err } p.theirExtensions = make(map[string]int) for name, code := range h.M { p.theirExtensions[name] = code } if ts.Session.HaveTorrent || ts.Session.ME != nil && ts.Session.ME.Transferring { return } // Fill metadata info if h.MetadataSize != uint(0) { nPieces := uint(math.Ceil(float64(h.MetadataSize) / float64(16*1024))) ts.Session.ME.Pieces = make([][]byte, nPieces) } if _, ok := p.theirExtensions["ut_metadata"]; ok { ts.Session.ME.Transferring = true p.sendMetadataRequest(0) } } else if ext, ok := ts.Session.OurExtensions[int(msg[0])]; ok { switch ext { case "ut_metadata": ts.DoMetadata(msg[1:], p) default: log.Println("[", ts.M.Info.Name, "] Unknown extension: ", ext) } } else { log.Println("[", ts.M.Info.Name, "] Unknown extension: ", int(msg[0])) } return nil }
func getTrackerInfo(dialer proxy.Dialer, url string) (tr *TrackerResponse, err error) { r, err := proxyHttpGet(dialer, url) if err != nil { return } defer r.Body.Close() if r.StatusCode >= 400 { data, _ := ioutil.ReadAll(r.Body) reason := "Bad Request " + string(data) log.Println(reason) err = errors.New(reason) return } var tr2 TrackerResponse err = bencode.Unmarshal(r.Body, &tr2) r.Body.Close() if err != nil { return } tr = &tr2 return }
func GetMetaInfo(dialer proxy.Dialer, torrent string) (metaInfo *MetaInfo, err error) { var input io.ReadCloser if strings.HasPrefix(torrent, "http:") { r, err := proxyHttpGet(dialer, torrent) if err != nil { return nil, err } input = r.Body } else if strings.HasPrefix(torrent, "magnet:") { magnet, err := parseMagnet(torrent) if err != nil { log.Println("Couldn't parse magnet: ", err) return nil, err } ih, err := dht.DecodeInfoHash(magnet.InfoHashes[0]) if err != nil { return nil, err } metaInfo = &MetaInfo{InfoHash: string(ih), AnnounceList: magnet.Trackers} //Gives us something to call the torrent until metadata can be procurred metaInfo.Info.Name = hex.EncodeToString([]byte(ih)) return metaInfo, err } else { if input, err = os.Open(torrent); err != nil { return } } // We need to calcuate the sha1 of the Info map, including every value in the // map. The easiest way to do this is to read the data using the Decode // API, and then pick through it manually. var m interface{} m, err = bencode.Decode(input) input.Close() if err != nil { err = errors.New("Couldn't parse torrent file phase 1: " + err.Error()) return } topMap, ok := m.(map[string]interface{}) if !ok { err = errors.New("Couldn't parse torrent file phase 2.") return } infoMap, ok := topMap["info"] if !ok { err = errors.New("Couldn't parse torrent file. info") return } var b bytes.Buffer if err = bencode.Marshal(&b, infoMap); err != nil { return } hash := sha1.New() hash.Write(b.Bytes()) var m2 MetaInfo err = bencode.Unmarshal(&b, &m2.Info) if err != nil { return } m2.InfoHash = string(hash.Sum(nil)) m2.Announce = getString(topMap, "announce") m2.AnnounceList = getSliceSliceString(topMap, "announce-list") m2.CreationDate = getString(topMap, "creation date") m2.Comment = getString(topMap, "comment") m2.CreatedBy = getString(topMap, "created by") m2.Encoding = strings.ToUpper(getString(topMap, "encoding")) metaInfo = &m2 return }
func (ts *TorrentSession) DoMetadata(msg []byte, p *peerState) { var message MetadataMessage err := bencode.Unmarshal(bytes.NewReader(msg), &message) if err != nil { log.Println("[", ts.M.Info.Name, "] Error when parsing metadata:", err) return } mt := message.MsgType switch mt { case METADATA_REQUEST: //TODO: Answer to metadata request case METADATA_DATA: if ts.Session.HaveTorrent { log.Println("[", ts.M.Info.Name, "] Received metadata we don't need, from", p.address) return } piece, err := getMetadataPiece(msg) if err != nil { log.Println("[", ts.M.Info.Name, "] Error when getting metadata piece: ", err) return } ts.Session.ME.Pieces[message.Piece] = piece finished := true for idx, data := range ts.Session.ME.Pieces { if len(data) == 0 { p.sendMetadataRequest(idx) finished = false } } if !finished { break } log.Println("[", ts.M.Info.Name, "] Finished downloading metadata!") var full bytes.Buffer for _, piece := range ts.Session.ME.Pieces { full.Write(piece) } b := full.Bytes() // Verify sha sha := sha1.New() sha.Write(b) actual := string(sha.Sum(nil)) if actual != ts.M.InfoHash { log.Printf("[ %s ] Invalid metadata; got %x\n", ts.M.Info.Name, actual) } metadata := string(b) err = saveMetaInfo(metadata) if err != nil { return } ts.reload(metadata) case METADATA_REJECT: log.Printf("[ %s ] %s didn't want to send piece %d\n", ts.M.Info.Name, p.address, message.Piece) default: log.Println("[", ts.M.Info.Name, "] Didn't understand metadata extension type: ", mt) } }
func (t *TorrentSession) DoMetadata(msg []byte, p *peerState) { // We need a buffered reader because the raw data is put directly // after the bencoded data, and a simple reader will get all its bytes // eaten. A buffered reader will keep a reference to where the // bdecoding ended. br := bufio.NewReader(bytes.NewReader(msg)) var message MetadataMessage err := bencode.Unmarshal(br, &message) if err != nil { log.Println("Error when parsing metadata: ", err) return } mt := message.MsgType switch mt { case METADATA_REQUEST: //TODO: Answer to metadata request case METADATA_DATA: var piece bytes.Buffer _, err := io.Copy(&piece, br) if err != nil { log.Println("Error when getting metadata piece: ", err) return } t.si.ME.Pieces[message.Piece] = piece.Bytes() finished := true for idx, data := range t.si.ME.Pieces { if len(data) == 0 { p.sendMetadataRequest(idx) finished = false } } if !finished { break } log.Println("Finished downloading metadata!") var full bytes.Buffer for _, piece := range t.si.ME.Pieces { full.Write(piece) } b := full.Bytes() // Verify sha sha := sha1.New() sha.Write(b) actual := string(sha.Sum(nil)) if actual != t.M.InfoHash { log.Println("Invalid metadata") log.Printf("Expected %x, got %x\n", t.M.InfoHash, actual) } metadata := string(b) err = saveMetaInfo(metadata) if err != nil { return } t.reload(metadata) case METADATA_REJECT: log.Printf("%s didn't want to send piece %d\n", p.address, message.Piece) default: log.Println("Didn't understand metadata extension type: ", mt) } }
func (t *TorrentSession) DoMetadata(msg []byte, p *peerState) { var message MetadataMessage err := bencode.Unmarshal(bytes.NewReader(msg), &message) if err != nil { log.Println("Error when parsing metadata: ", err) return } mt := message.MsgType switch mt { case METADATA_REQUEST: if !t.si.HaveTorrent { break } rawInfo := t.m.RawInfo() from := message.Piece * METADATA_PIECE_SIZE // Piece asked must be between the first one and the last one. // Note that the last one will most of the time be smaller than // METADATA_PIECE_SIZE if from >= len(rawInfo) { log.Printf("%d is out of range. Not sending this\n", message.Piece) break } to := from + METADATA_PIECE_SIZE if to > len(rawInfo) { to = len(rawInfo) } if _, ok := p.theirExtensions["ut_metadata"]; !ok { log.Println("%s doesn't understand ut_metadata\n", p.address) break } respHeader := MetadataMessage{ MsgType: METADATA_DATA, Piece: message.Piece, TotalSize: len(rawInfo), } var resp bytes.Buffer resp.WriteByte(EXTENSION) resp.WriteByte(byte(p.theirExtensions["ut_metadata"])) err = bencode.Marshal(&resp, respHeader) if err != nil { log.Println("Couldn't header metadata response: ", err) break } resp.Write(rawInfo[from:to]) p.sendMessage(resp.Bytes()) case METADATA_DATA: if t.si.HaveTorrent { break } if message.TotalSize == 0 { log.Println("No metadata size, bailing out") return } if message.Piece >= len(t.si.ME.Pieces) { log.Printf("Rejecting invalid metadata piece %d, max is %d\n", message.Piece, len(t.si.ME.Pieces)-1) break } pieceSize := METADATA_PIECE_SIZE if message.Piece == len(t.si.ME.Pieces)-1 { pieceSize = message.TotalSize - (message.TotalSize/METADATA_PIECE_SIZE)*METADATA_PIECE_SIZE } t.si.ME.Pieces[message.Piece] = msg[len(msg)-pieceSize:] finished := true for idx, data := range t.si.ME.Pieces { if len(data) == 0 { p.sendMetadataRequest(idx) finished = false break } } if !finished { break } log.Println("Finished downloading metadata!") var full bytes.Buffer for _, piece := range t.si.ME.Pieces { full.Write(piece) } info := full.Bytes() // Verify sha sha := sha1.New() sha.Write(info) actual := string(sha.Sum(nil)) if actual != t.m.InfoHash { log.Println("Invalid metadata") log.Printf("Expected %x, got %x\n", t.m.InfoHash, actual) break } err = t.reload(info) if err != nil { return } if p.have == nil { if p.temporaryBitfield != nil { p.have = bitset.NewFromBytes(t.totalPieces, p.temporaryBitfield) p.temporaryBitfield = nil } else { p.have = bitset.New(t.totalPieces) } } if p.have == nil { log.Panic("Invalid bitfield data") } p.SendBitfield(t.pieceSet) case METADATA_REJECT: log.Printf("%d didn't want to send piece %d\n", p.address, message.Piece) default: log.Println("Didn't understand metadata extension type: ", mt) } }