Ejemplo n.º 1
0
int TorrentFile::save_block(PIECE_INDEX piece, BLOCK_OFFSET block_offset, uint32_t block_length, char * block)
{
	if (block == NULL)
		return ERR_BAD_ARG;
	uint32_t block_index;
	m_torrent->get_block_index_by_offset(piece, block_offset, block_index) ;
	uint32_t real_block_length;
	m_torrent->get_block_length_by_index(piece, block_index, real_block_length);
	if (real_block_length != block_length)
		return ERR_INTERNAL;

	FILE_INDEX file_index;
	FILE_OFFSET offset;
	m_torrent->get_block_info(piece, block_index, file_index, offset);

	uint32_t pos = 0;
	BLOCK_ID block_id;
	generate_block_id(piece, block_index, block_id);

	while(pos < block_length)
	{
		//определяем сколько возможно записать в файл
		uint64_t remain = m_files[file_index].length - offset;
		//если данных для записи больше,чем это возможно, пишем в файл сколько можем(remain), иначе пишем все что есть
		uint64_t to_write = block_length - pos > remain ? remain : block_length - pos;
		try
		{
			m_fm->File_write(m_files[file_index++].file_, &block[pos], to_write, offset, block_id);
		}
		catch (Exception & e)
		{
			if (e.get_errcode() == Exception::ERR_CODE_NULL_REF || e.get_errcode() == Exception::ERR_CODE_FILE_NOT_EXISTS ||
					e.get_errcode() == Exception::ERR_CODE_UNDEF || e.get_errcode() ==  Exception::ERR_CODE_FILE_WRITE_OFFSET_OVERFLOW ||
					e.get_errcode() == Exception::ERR_CODE_BLOCK_TOO_BIG)
			{
				torrent_failure tf;
				tf.exception_errcode = e.get_errcode();
				tf.errno_ = 0;
				tf.description = m_files[file_index - 1].name;
				tf.where = TORRENT_FAILURE_WRITE_FILE;
				m_torrent->set_failure(tf);
			}
			return ERR_INTERNAL;
		}
		catch (SyscallException & e)
		{
			torrent_failure tf;
			tf.exception_errcode = Exception::NO_ERROR;
			tf.errno_ = e.get_errno();
			tf.description = m_files[file_index - 1].name;
			tf.where = TORRENT_FAILURE_WRITE_FILE;
			m_torrent->set_failure(tf);
			return ERR_INTERNAL;
		}
		pos += to_write;
		offset = 0;
	}
	return ERR_NO_ERROR;
}
Ejemplo n.º 2
0
int TorrentFile::block_done(uint32_t piece_index, uint32_t block_index)
{
	if (piece_index >= m_pieces_count)
		return -1;
	if (block_index >= m_piece_info[piece_index].block_count)
		return -1;
	std::map<uint32_t, Peer*>::iterator iter = m_piece_info[piece_index].blocks2download.find(block_index);
	if (iter == m_piece_info[piece_index].blocks2download.end() && m_piece_info[piece_index].blocks2download.count(block_index) == 0)
		return 0;
	if ((*iter).second != NULL)
	{
		printf("block is done %u %u\n", piece_index, block_index);
		m_piece_info[piece_index].marked_blocks--;
		(*iter).second->erase_requested_block(generate_block_id(piece_index, block_index));
		m_piece_info[piece_index].blocks2download.erase(iter);
	}
	return 0;
}
Ejemplo n.º 3
0
int TorrentFile::save_block(uint32_t piece, uint32_t block_offset, uint32_t block_length, char * block)
{
	if (piece >= m_pieces_count || block == NULL)
		return ERR_BAD_ARG;
	uint32_t block_index = block_offset / BLOCK_LENGTH;
	if (block_index >= m_piece_info[piece].block_count)
		return ERR_INTERNAL;
	printf("saving block %u %u\n", piece, block_index);
	uint32_t real_block_length;
	if (get_block_length_by_index(piece, block_index, &real_block_length) != ERR_NO_ERROR || real_block_length != block_length)
	{
		unmark_block(piece, block_index);
		return ERR_INTERNAL;
	}

	int file_index = m_piece_info[piece].file_index;
	uint64_t offset = block_offset + m_piece_info[piece].offset;
	while(offset >= m_files[file_index].length)
	{
		offset -= m_files[file_index++].length;
	}
	uint32_t pos = 0;
	uint64_t id = generate_block_id(piece, block_index);
	//uint64_t id = ((uint64_t)piece << 32) + block_index;
	while(pos < block_length)
	{
		//определяем сколько возможно записать в файл
		uint32_t remain = m_files[file_index].length - offset;
		//если данных для записи больше,чем это возможно, пишем в файл сколько можем(remain), иначе пишем все что есть
		uint32_t to_write = block_length - pos > remain ? remain : block_length - pos;
		//bad arg на этом этапе получить не реально, ошибку нехватки места в кэше не прокидываем,
		//т.к блок сможем скачать позже у кого угодно
		if (m_fm->File_write(m_files[file_index++].fm_id, &block[pos], to_write, offset, id) != ERR_NO_ERROR)
		{
			printf("can not save block %u %u\n", piece, block_index);
			unmark_block(piece, block_index);
		}
		pos += to_write;
		offset = 0;
	}
	return ERR_NO_ERROR;
}
Ejemplo n.º 4
0
int TorrentFile::read_block(uint32_t piece, uint32_t block_index, char * block, uint32_t * block_length)
{
	if (piece >= m_pieces_count)
		return ERR_BAD_ARG;
	if (block_index >= m_piece_info[piece].block_count)
		return ERR_INTERNAL;
	get_block_length_by_index(piece, block_index, block_length);

	uint64_t id = generate_block_id(piece, block_index);
	//printf("look to cache...\n");
	if (m_torrent->m_bc->get(m_torrent, id, block) == ERR_NO_ERROR)
		return ERR_NO_ERROR;
	//printf("not in cache, read from file\n");
	int file_index = m_piece_info[piece].file_index;
	uint32_t offset = block_index * BLOCK_LENGTH + m_piece_info[piece].offset;
	while(offset >= m_files[file_index].length)
	{
		offset -= m_files[file_index++].length;
	}
	uint32_t pos = 0;
	while(pos < *block_length)
	{
		//определяем сколько возможно прочитать из файла
		uint32_t remain = m_files[file_index].length - offset;
		//если прочитать надо больше, чем это возможно, читаем сколько можем(remain), иначе читаем все
		uint32_t to_read = *block_length - pos > remain ? remain : *block_length - pos;
		int ret = m_fm->File_read_immediately(m_files[file_index++].fm_id, &block[pos], offset, to_read);
		if (ret < 0)
			return ERR_INTERNAL;
		pos += to_read;
		offset = 0;
	}
	//printf("Put in cache\n");
	m_torrent->m_bc->put(m_torrent, id, block);
	return ERR_NO_ERROR;

}
Ejemplo n.º 5
0
int Peer::request(PIECE_INDEX piece_index, BLOCK_INDEX block_index)
{
    BLOCK_ID id;
    generate_block_id(piece_index, block_index, id);
    return request(id);
}
Ejemplo n.º 6
0
int Peer::process_messages()
{
    //is handshake
    if (m_buf.length - m_buf.pos >= HANDSHAKE_LENGHT &&
            m_buf.data[m_buf.pos] == '\x13' &&
            memcmp(&m_buf.data[m_buf.pos + 1], "BitTorrent protocol", 19) == 0 &&
            m_torrent->memcmp_infohash_bin((unsigned char*)&m_buf.data[m_buf.pos + 28]))
    {
        if (m_state != PEER_STATE_WAIT_HANDSHAKE)
            return ERR_INTERNAL;
        m_buf.pos += HANDSHAKE_LENGHT;
        m_state = PEER_STATE_GENERAL_READY;
#ifdef PEER_DEBUG
        logger::LOGGER() << "Peer " << m_ip.c_str() << ": is received handshake\n";
#endif
    }
    char ip[16];
    memset(ip, 0, 16);
    strcpy(ip,  inet_ntoa(m_sock->m_peer.sin_addr));
    uint32_t piece_count = m_torrent->get_piece_count();
    BLOCK_ID block_id;
    while((int)m_buf.length - (int)m_buf.pos > 4)
    {
        uint32_t len = 0;
        memcpy(&len, &m_buf.data[m_buf.pos], 4);
        len = ntohl(len);
        if (m_buf.length - m_buf.pos < len + 4)
            goto end;
        m_buf.pos += 4;
        if (len != 0)
        {
            char id = m_buf.data[m_buf.pos++];
            switch (id)
            {
            case '\x00'://choke: <len=0001><id=0>
#ifdef PEER_DEBUG
                logger::LOGGER() << "Peer " << m_ip.c_str() << ": is received choke";
#endif
                if ( m_state == PEER_STATE_WAIT_HANDSHAKE)
                    return ERR_INTERNAL;
                m_peer_choking = true;
                if (m_state == PEER_STATE_WAIT_UNCHOKE)
                    return ERR_INTERNAL;//m_state = PEER_STATE_GENERAL_READY; иначе зацикливаемся
                break;
            case '\x01'://unchoke: <len=0001><id=1>
#ifdef PEER_DEBUG
                logger::LOGGER() << "Peer " << m_ip.c_str() << ": is received unchoke";
#endif
                if ( m_state == PEER_STATE_WAIT_HANDSHAKE)
                    return ERR_INTERNAL;
                m_peer_choking = false;
                if (m_state == PEER_STATE_WAIT_UNCHOKE)
                    m_state = PEER_STATE_REQUEST_READY;
                break;
            case '\x02'://interested: <len=0001><id=2>
#ifdef PEER_DEBUG
                logger::LOGGER() << "Peer " << m_ip.c_str() << ": is received interested";
#endif
                if ( m_state == PEER_STATE_WAIT_HANDSHAKE)
                    return ERR_INTERNAL;
                m_peer_interested = true;
                send_unchoke();
                break;
            case '\x03'://not interested: <len=0001><id=3>
#ifdef PEER_DEBUG
                logger::LOGGER() << "Peer " << m_ip.c_str() << ": is received not interested";
#endif
                if ( m_state == PEER_STATE_WAIT_HANDSHAKE)
                    return ERR_INTERNAL;
                m_peer_interested = false;
                break;
            case '\x04'://have: <len=0005><id=4><piece index>
#ifdef PEER_DEBUG
                logger::LOGGER() << "Peer " << m_ip.c_str() << ": is received have";
#endif
                if ( m_state == PEER_STATE_WAIT_HANDSHAKE)
                    return ERR_INTERNAL;
                PIECE_INDEX piece_index;
                memcpy(&piece_index, &m_buf.data[m_buf.pos], 4);
                piece_index = ntohl(piece_index);
                if (piece_index >= piece_count)
                    return ERR_INTERNAL;
                m_available_pieces.insert(piece_index);
                set_bitfield(piece_index, piece_count, m_bitfield);
                break;
            case '\x05'://bitfield: <len=0001+X><id=5><bitfield>
#ifdef PEER_DEBUG
                logger::LOGGER() << "Peer " << m_ip.c_str() << ": is received bitfield";
#endif

                if (len - 1 != m_torrent->get_bitfield_length())
                    return ERR_INTERNAL;
                if (m_state == PEER_STATE_WAIT_HANDSHAKE)
                    return ERR_INTERNAL;
                memcpy(m_bitfield, &m_buf.data[m_buf.pos], len - 1);
                for(PIECE_INDEX i = 0; i < piece_count; i++)
                {
                    if (bit_in_bitfield(i, piece_count, m_bitfield))
                        m_available_pieces.insert(i);
                }
                break;
            case '\x06'://request: <len=0013><id=6><index><begin><length>
                if ( m_state == PEER_STATE_WAIT_HANDSHAKE)
                    return ERR_INTERNAL;
                PIECE_INDEX index;//индекс куска
                BLOCK_OFFSET offset;
                uint32_t length;
                memcpy(&index,&m_buf.data[m_buf.pos], 4);
                index = ntohl(index);
                memcpy(&offset,&m_buf.data[m_buf.pos + 4], 4);
                offset = ntohl(offset);
                memcpy(&length,&m_buf.data[m_buf.pos + 8], 4);
                length = ntohl(length);
                //проверяем валидность индексов, смещений
                if (length == 0 || length > BLOCK_LENGTH || offset % BLOCK_LENGTH != 0)
                    return ERR_INTERNAL;
                BLOCK_INDEX block_index;
                m_torrent->get_block_index_by_offset(index, offset, block_index) ;
                uint32_t real_block_length;
                m_torrent->get_block_length_by_index(index, block_index, real_block_length);
                if (real_block_length != length)
                    return ERR_INTERNAL;
                //кладем индекс блока в очередь запросов
                generate_block_id(index, block_index, block_id);
                m_requests_queue.insert(block_id);

#ifdef PEER_DEBUG
                logger::LOGGER() << "Peer " << m_ip.c_str() << ": is received request piece=" << index << " block=" << block_index;
#endif

                break;
            case '\x07'://piece: <len=0009+X><id=7><index><begin><block>
            {
                PIECE_INDEX index;//индекс куска
                BLOCK_OFFSET offset;
                uint32_t block_length = len - 9;
                if (m_state == PEER_STATE_WAIT_HANDSHAKE)
                    return ERR_INTERNAL;
                if (block_length == 0 || block_length > BLOCK_LENGTH)
                    return ERR_INTERNAL;
                memcpy(&index,&m_buf.data[m_buf.pos], 4);
                index = ntohl(index);
                memcpy(&offset,&m_buf.data[m_buf.pos + 4], 4);
                offset = ntohl(offset);
                if (offset % BLOCK_LENGTH != 0)
                    return ERR_INTERNAL;

                generate_block_id(index, offset / BLOCK_LENGTH, block_id);
                std::set<BLOCK_ID>::iterator iter = m_requested_blocks.find(block_id);

#ifdef PEER_DEBUG
                logger::LOGGER() << "Peer " << m_ip.c_str() << ": is received piece piece=" << index << " block=" << offset / BLOCK_LENGTH;
#endif

                if (iter == m_requested_blocks.end())
                    return ERR_INTERNAL;

                if (m_torrent->save_block(index, offset, block_length, &m_buf.data[m_buf.pos + 8]) != ERR_NO_ERROR)
                    return ERR_INTERNAL;

                m_requested_blocks.erase(iter);
                m_downloaded += block_length;

                break;
            }
            case '\x08'://cancel: <len=0013><id=8><index><begin><length>
            {
                if (m_state == PEER_STATE_WAIT_HANDSHAKE)
                    return ERR_INTERNAL;
                PIECE_INDEX index;//индекс куска
                BLOCK_OFFSET offset;
                uint32_t length;
                memcpy(&index,&m_buf.data[m_buf.pos], 4);
                index = ntohl(index);
                memcpy(&offset,&m_buf.data[m_buf.pos + 4], 4);
                offset = ntohl(offset);
                memcpy(&length,&m_buf.data[m_buf.pos + 8], 4);
                length = ntohl(length);
                //проверяем валидность индексов, смещений
                if (length == 0 || length > BLOCK_LENGTH || offset % BLOCK_LENGTH != 0)
                    return ERR_INTERNAL;
                uint32_t block_index;
                m_torrent->get_block_index_by_offset(index, offset, block_index);

#ifdef PEER_DEBUG
                logger::LOGGER() << "Peer " << m_ip.c_str() << ": is received cancel piece=" << index << " block=" << block_index;
#endif

                uint32_t real_block_length;
                m_torrent->get_block_length_by_index(index, block_index, real_block_length);
                if (real_block_length != length)
                    return ERR_INTERNAL;
                generate_block_id(index, block_index, block_id);
                m_requested_blocks.erase(block_id);
                break;
            }
            case '\x09'://port: <len=0003><id=9><listen-port>
                if (m_state == PEER_STATE_WAIT_HANDSHAKE)
                    return ERR_INTERNAL;
                break;
            default:
                return ERR_INTERNAL;
                break;
            }
            m_buf.pos += len - 1;
        }
    }
end:
    char temp[BUFFER_SIZE];
    size_t len = m_buf.length - m_buf.pos;
    memcpy(temp, &m_buf.data[m_buf.pos], len);
    m_buf.length = len;
    m_buf.pos = 0;
    memcpy(m_buf.data, temp, len);
    return ERR_NO_ERROR;
}
Ejemplo n.º 7
0
int TorrentFile::read_block(PIECE_INDEX piece, BLOCK_INDEX block_index, char * block, uint32_t & block_length)
{
	m_torrent->get_block_length_by_index(piece, block_index, block_length);

	BLOCK_ID block_id;
	generate_block_id(piece, block_index, block_id);
	block_cache::cache_key key(m_torrent.get(), block_id);
	try
	{
		m_torrent->get_bc()->get(key, block);
		return ERR_NO_ERROR;
	}
	catch (Exception & e) {
		if (e.get_errcode() != Exception::ERR_CODE_LRU_CACHE_NE)
		{
			torrent_failure tf;
			tf.exception_errcode = e.get_errcode();
			tf.errno_ = 0;
			tf.description = "";
			tf.where = TORRENT_FAILURE_GET_BLOCK_CACHE;
			m_torrent->set_failure(tf);
			return ERR_INTERNAL;
		}
	}

	FILE_INDEX file_index;
	FILE_OFFSET offset;
	m_torrent->get_block_info(piece, block_index, file_index, offset);

	uint32_t pos = 0;
	while(pos < block_length)
	{
		//определяем сколько возможно прочитать из файла
		uint64_t remain = m_files[file_index].length - offset;
		//если прочитать надо больше, чем это возможно, читаем сколько можем(remain), иначе читаем все
		uint64_t to_read = block_length - pos > remain ? remain : block_length - pos;
		try
		{
			m_fm->File_read_immediately(m_files[file_index++].file_, &block[pos], offset, to_read);
		}
		catch (Exception & e)
		{
			if (e.get_errcode() == Exception::ERR_CODE_NULL_REF || e.get_errcode() == Exception::ERR_CODE_FILE_NOT_EXISTS ||
					e.get_errcode() == Exception::ERR_CODE_UNDEF || e.get_errcode() ==  Exception::ERR_CODE_FILE_WRITE_OFFSET_OVERFLOW ||
					e.get_errcode() == Exception::ERR_CODE_FILE_NOT_OPENED)
			{
				torrent_failure tf;
				tf.exception_errcode = e.get_errcode();
				tf.errno_ = 0;
				tf.description = m_files[file_index - 1].name;
				tf.where = TORRENT_FAILURE_WRITE_FILE;
				m_torrent->set_failure(tf);
			}
			return ERR_INTERNAL;
		}
		catch (SyscallException & e)
		{
			torrent_failure tf;
			tf.exception_errcode = Exception::NO_ERROR;
			tf.errno_ = e.get_errno();
			tf.description = m_files[file_index - 1].name;
			tf.where = TORRENT_FAILURE_WRITE_FILE;
			m_torrent->set_failure(tf);
			return ERR_INTERNAL;
		}
		pos += to_read;
		offset = 0;
	}
	try
	{
		m_torrent->get_bc()->put(key, block);
	}
	catch(Exception & e)
	{
		torrent_failure tf;
		tf.exception_errcode = e.get_errcode();
		tf.errno_ = 0;
		tf.description = "";
		tf.where = TORRENT_FAILURE_PUT_BLOCK_CACHE;
		m_torrent->set_failure(tf);
		return ERR_INTERNAL;
	}
	return ERR_NO_ERROR;

}