Ejemplo n.º 1
0
func checkPieces(fs FileStore, totalLength int64, m *MetaInfo) (good, bad int, goodBits *bitset.Bitset, err error) {
	pieceLength := m.Info.PieceLength
	numPieces := int((totalLength + pieceLength - 1) / pieceLength)
	goodBits = bitset.New(int(numPieces))
	ref := m.Info.Pieces
	if len(ref) != numPieces*sha1.Size {
		err = errors.New(fmt.Sprintf("Incorrect Info.Pieces length: expected %d, got %d", len(ref), numPieces*sha1.Size))
		return
	}
	currentSums, err := computeSums(fs, totalLength, m.Info.PieceLength)
	if err != nil {
		return
	}
	for i := 0; i < numPieces; i++ {
		base := i * sha1.Size
		end := base + sha1.Size
		if checkEqual([]byte(ref[base:end]), currentSums[base:end]) {
			good++
			goodBits.Set(int(i))
		} else {
			fs.SetBad(int64(i) * pieceLength)
			bad++
		}
	}
	return
}
Ejemplo n.º 2
0
func (t *TorrentSession) AddPeer(btconn *btConn) {
	theirheader := btconn.header

	peer := btconn.conn.RemoteAddr().String()
	if t.peers.Len() >= MAX_NUM_PEERS {
		log.Println("We have enough peers. Rejecting additional peer", peer)
		btconn.conn.Close()
		return
	}
	ps := NewPeerState(btconn.conn)
	ps.address = peer
	ps.id = btconn.id

	if keep := t.peers.Add(ps); !keep {
		log.Printf("[TORRENT] Not keeping %s -- %s\n", ps.address, ps.id)
		return
	}

	if int(theirheader[5])&0x10 == 0x10 {
		ps.SendExtensions(t.si.OurExtensions, int64(len(t.m.RawInfo())))

		if t.si.HaveTorrent {
			ps.SendBitfield(t.pieceSet)
		}
	} else {
		ps.SendBitfield(t.pieceSet)
	}

	if t.si.HaveTorrent {
		// By default, a peer has no pieces. If it has pieces, it should send
		// a BITFIELD message as a first message
		ps.have = bitset.New(t.totalPieces)
	}

	// Note that we need to launch these at the end of initialisation, so
	// we are sure that the message we buffered previously will be the
	// first to be sent.
	go ps.peerWriter(t.peerMessageChan)
	go ps.peerReader(t.peerMessageChan)

	log.Printf("[TORRENT] AddPeer: added %s\n", btconn.conn.RemoteAddr().String())
}
Ejemplo n.º 3
0
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)
	}
}