Ejemplo n.º 1
0
void WSService::on_tcp_post_init(WSClass& c, websocketpp::connection_hdl hdl) {
	log_->trace() << log_tag() << BOOST_CURRENT_FUNCTION;

	auto connection_ptr = c.get_con_from_hdl(hdl);
	if(!c.is_server())
		connection_ptr->add_subprotocol(subprotocol_);

	try {
		// Validate SSL certificate
		X509* x509 = SSL_get_peer_certificate(connection_ptr->get_socket().native_handle());
		if(!x509) throw connection_error("Certificate error");

		// Detect loopback
		connection& conn = ws_assignment_[hdl];
		conn.remote_pubkey = pubkey_from_cert(x509);
		conn.remote_endpoint = connection_ptr->get_raw_socket().remote_endpoint();

		X509_free(x509);

		if(provider_.is_loopback(conn.remote_pubkey) || provider_.is_loopback(conn.remote_endpoint)) {
			provider_.mark_loopback(conn.remote_endpoint);
			throw connection_error("Loopback detected");
		}
	}catch(std::exception& e) {
		log_->warn() << log_tag() << BOOST_CURRENT_FUNCTION << " e:" << e.what();
		connection_ptr->terminate(websocketpp::lib::error_code());
	}
}
Ejemplo n.º 2
0
static void scrub_parity_reader(struct snapraid_worker* worker, struct snapraid_task* task)
{
	struct snapraid_io* io = worker->io;
	struct snapraid_state* state = io->state;
	struct snapraid_parity_handle* parity_handle = worker->parity_handle;
	unsigned level = parity_handle->level;
	block_off_t blockcur = task->position;
	unsigned char* buffer = task->buffer;
	int ret;

	/* read the parity */
	ret = parity_read(parity_handle, blockcur, buffer, state->block_size, log_error);
	if (ret == -1) {
		if (errno == EIO) {
			log_tag("parity_error:%u:%s: Read EIO error. %s\n", blockcur, lev_config_name(level), strerror(errno));
			log_error("Input/Output error in parity '%s' at position '%u'\n", lev_config_name(level), blockcur);
			task->state = TASK_STATE_IOERROR_CONTINUE;
			return;
		}

		log_tag("parity_error:%u:%s: Read error. %s\n", blockcur, lev_config_name(level), strerror(errno));
		task->state = TASK_STATE_ERROR_CONTINUE;
		return;
	}

	task->state = TASK_STATE_DONE;
}
Ejemplo n.º 3
0
void P2PFolder::handle_HaveChunk(const blob& message_raw) {
	log_->trace() << log_tag() << BOOST_CURRENT_FUNCTION;

	auto message_struct = parser_.parse_HaveChunk(message_raw);
	log_->debug() << log_tag() << "<== HAVE_BLOCK:"
		<< " ct_hash=" << ct_hash_readable(message_struct.ct_hash);
	folder_group()->notify_chunk(shared_from_this(), message_struct.ct_hash);
}
Ejemplo n.º 4
0
void P2PFolder::handle_MetaCancel(const blob& message_raw) {
#   warning "Not implemented yet"
	log_->trace() << log_tag() << BOOST_CURRENT_FUNCTION;

	auto message_struct = parser_.parse_MetaCancel(message_raw);
	log_->debug() << log_tag() << "<== META_CANCEL:"
		<< " path_id=" << path_id_readable(message_struct.revision.path_id_)
		<< " revision=" << message_struct.revision.revision_;
}
Ejemplo n.º 5
0
void P2PFolder::handle_NotInterested(const blob& message_raw) {
	log_->trace() << log_tag() << BOOST_CURRENT_FUNCTION;
	log_->debug() << log_tag() << "<== NOT_INTERESTED";

	if(peer_interested_) {
		peer_interested_ = false;
		folder_group()->handle_not_interested(shared_from_this());
	}
}
Ejemplo n.º 6
0
void P2PFolder::handle_Unchoke(const blob& message_raw) {
	log_->trace() << log_tag() << BOOST_CURRENT_FUNCTION;
	log_->debug() << log_tag() << "<== UNCHOKE";

	if(peer_choking_) {
		peer_choking_ = false;
		folder_group()->handle_unchoke(shared_from_this());
	}
}
Ejemplo n.º 7
0
void P2PFolder::handle_MetaRequest(const blob& message_raw) {
	log_->trace() << log_tag() << BOOST_CURRENT_FUNCTION;

	auto message_struct = parser_.parse_MetaRequest(message_raw);
	log_->debug() << log_tag() << "<== META_REQUEST:"
		<< " path_id=" << path_id_readable(message_struct.revision.path_id_)
		<< " revision=" << message_struct.revision.revision_;

	folder_group()->request_meta(shared_from_this(), message_struct.revision);
}
Ejemplo n.º 8
0
void P2PFolder::handle_BlockCancel(const blob& message_raw) {
#   warning "Not implemented yet"
	log_->trace() << log_tag() << BOOST_CURRENT_FUNCTION;

	auto message_struct = parser_.parse_BlockCancel(message_raw);
	log_->debug() << log_tag() << "<== BLOCK_CANCEL:"
		<< " ct_hash=" << ct_hash_readable(message_struct.ct_hash)
		<< " length=" << message_struct.length
		<< " offset=" << message_struct.offset;
}
Ejemplo n.º 9
0
void P2PFolder::handle_MetaReply(const blob& message_raw) {
	log_->trace() << log_tag() << BOOST_CURRENT_FUNCTION;

	auto message_struct = parser_.parse_MetaReply(message_raw, folder_group()->secret());
	log_->debug() << log_tag() << "<== META_REPLY:"
		<< " path_id=" << path_id_readable(message_struct.smeta.meta().path_id())
		<< " revision=" << message_struct.smeta.meta().revision()
		<< " bits=" << message_struct.bitfield;

	folder_group()->post_meta(shared_from_this(), message_struct.smeta, message_struct.bitfield);
}
Ejemplo n.º 10
0
void P2PFolder::handle_HaveMeta(const blob& message_raw) {
	log_->trace() << log_tag() << BOOST_CURRENT_FUNCTION;

	auto message_struct = parser_.parse_HaveMeta(message_raw);
	log_->debug() << log_tag() << "<== HAVE_META:"
		<< " path_id=" << path_id_readable(message_struct.revision.path_id_)
		<< " revision=" << message_struct.revision.revision_
		<< " bits=" << message_struct.bitfield;

	folder_group()->notify_meta(shared_from_this(), message_struct.revision, message_struct.bitfield);
}
Ejemplo n.º 11
0
void P2PFolder::handle_BlockRequest(const blob& message_raw) {
	log_->trace() << log_tag() << BOOST_CURRENT_FUNCTION;

	auto message_struct = parser_.parse_BlockRequest(message_raw);
	log_->debug() << log_tag() << "<== BLOCK_REQUEST:"
		<< " ct_hash=" << ct_hash_readable(message_struct.ct_hash)
		<< " length=" << message_struct.length
		<< " offset=" << message_struct.offset;

	folder_group()->request_block(shared_from_this(), message_struct.ct_hash, message_struct.offset, message_struct.length);
}
Ejemplo n.º 12
0
void WSService::on_message(websocketpp::connection_hdl hdl, const std::string& message_raw) {
	log_->trace() << log_tag() << BOOST_CURRENT_FUNCTION;

	try {
		blob message_blob = blob(message_raw.begin(), message_raw.end());
		std::shared_ptr<P2PFolder>(ws_assignment_[hdl].folder)->handle_message(message_blob);
	}catch(std::exception& e) {
		log_->trace() << log_tag() << BOOST_CURRENT_FUNCTION << " e:" << e.what();
		close(hdl, e.what());
	}
}
Ejemplo n.º 13
0
void P2PFolder::handle_BlockReply(const blob& message_raw) {
	log_->trace() << log_tag() << BOOST_CURRENT_FUNCTION;

	auto message_struct = parser_.parse_BlockReply(message_raw);
	log_->debug() << log_tag() << "<== BLOCK_REPLY:"
		<< " ct_hash=" << ct_hash_readable(message_struct.ct_hash)
		<< " offset=" << message_struct.offset;

	counter_.add_down_blocks(message_struct.content.size());

	folder_group()->post_block(shared_from_this(), message_struct.ct_hash, message_struct.content, message_struct.offset);
}
Ejemplo n.º 14
0
void ControlServer::on_message(websocketpp::connection_hdl hdl, server::message_ptr message_ptr) {
	log_->trace() << log_tag() << BOOST_CURRENT_FUNCTION;

	try {
		log_->trace() << message_ptr->get_payload();
		// Read as control_json;
		Json::Value control_json;
		Json::Reader r; r.parse(message_ptr->get_payload(), control_json);

		dispatch_control_json(control_json);
	}catch(std::exception& e) {
		log_->trace() << log_tag() << "on_message e:" << e.what();
		ws_server_.get_con_from_hdl(hdl)->close(websocketpp::close::status::protocol_error, e.what());
	}
}
Ejemplo n.º 15
0
void WSService::on_disconnect(websocketpp::connection_hdl hdl) {
	log_->trace() << log_tag() << BOOST_CURRENT_FUNCTION << " e:" << errmsg(hdl);

	auto dir_ptr = ws_assignment_[hdl].folder.lock();
	if(dir_ptr) {
		try {
			auto folder_group = dir_ptr->folder_group();
			if(folder_group)
				folder_group->detach(dir_ptr);
		}catch(const std::bad_weak_ptr& e){
			log_->debug() << log_tag() << BOOST_CURRENT_FUNCTION << " e:" << e.what();
		}
	}
	ws_assignment_.erase(hdl);
}
Ejemplo n.º 16
0
bool Downloader::request_one() {
	log_->trace() << log_tag() << BOOST_CURRENT_FUNCTION;
	// Try to choose block to request
	for(auto& needed_chunk : needed_chunks_) {
		auto& ct_hash = needed_chunk.first;

		// Try to choose a remote to request this block from
		auto remote = find_node_for_request(ct_hash);
		if(remote == nullptr) continue;

		// Rebuild request map to determine, which block to download now.
		AvailabilityMap<uint32_t> request_map = needed_chunk.second->file_map();
		for(auto& request : needed_chunk.second->requests)
			request_map.insert({request.second.offset, request.second.size});

		// Request, actually
		if(!request_map.full()) {
			NeededChunk::BlockRequest request;
			request.offset = request_map.begin()->first;
			request.size = std::min(request_map.begin()->second, uint32_t(Config::get()->globals()["p2p_block_size"].asUInt()));
			request.started = std::chrono::steady_clock::now();

			remote->request_block(ct_hash, request.offset, request.size);
			needed_chunk.second->requests.insert({remote, request});
			return true;
		}
	}
	return false;
}
Ejemplo n.º 17
0
void Uploader::request_block(std::shared_ptr<RemoteFolder> origin, const blob& ct_hash, uint32_t offset, uint32_t size) {
	try {
		origin->post_block(ct_hash, offset, get_block(ct_hash, offset, size));
	}catch(AbstractFolder::no_such_chunk& e){
		log_->warn() << log_tag() << "Requested nonexistent block";
	}
}
Ejemplo n.º 18
0
void Downloader::put_block(const blob& ct_hash, uint32_t offset, const blob& data, std::shared_ptr<RemoteFolder> from) {
	log_->trace() << log_tag() << BOOST_CURRENT_FUNCTION;
	auto needed_block_it = needed_chunks_.find(ct_hash);
	if(needed_block_it == needed_chunks_.end()) return;

	auto& requests = needed_block_it->second->requests;
	for(auto request_it = requests.begin(); request_it != requests.end();) {
		bool incremented_already = false;

		if(request_it->second.offset == offset          // Chunk position incorrect
			&& request_it->second.size == data.size()   // Chunk size incorrect
			&& request_it->first == from) {     // Requested node != replied. Well, it isn't critical, but will be useful to ban "fake" peers

			incremented_already = true;
			request_it = requests.erase(request_it);

			needed_block_it->second->put_block(offset, data);
			if(needed_block_it->second->full()) {
				exchange_group_.fs_dir()->put_chunk(ct_hash, needed_block_it->second->get_chunk());
			}   // TODO: catch "invalid hash" exception here

			periodic_maintain_.invoke_post();
		}

		if(!incremented_already) ++request_it;
	}
}
Ejemplo n.º 19
0
std::shared_ptr<ssl_context> WSService::on_tls_init(websocketpp::connection_hdl hdl) {
	log_->trace() << log_tag() << BOOST_CURRENT_FUNCTION;

	auto ssl_ctx_ptr = make_ssl_ctx();
	ssl_ctx_ptr->set_verify_callback(std::bind(&WSService::on_tls_verify, this, hdl, std::placeholders::_1, std::placeholders::_2));
	return ssl_ctx_ptr;
}
Ejemplo n.º 20
0
void Downloader::remove_requests_to(std::shared_ptr<RemoteFolder> remote) {
	log_->trace() << log_tag() << BOOST_CURRENT_FUNCTION;

	for(auto& needed_block : needed_chunks_) {
		needed_block.second->requests.erase(remote);
	}
}
Ejemplo n.º 21
0
/* RPC Actions */
void P2PFolder::choke() {
	if(! am_choking_) {
		send_message(parser_.gen_Choke());
		am_choking_ = true;

		log_->debug() << log_tag() << "==> CHOKE";
	}
}
Ejemplo n.º 22
0
void P2PFolder::interest() {
	if(! am_interested_) {
		send_message(parser_.gen_Interested());
		am_interested_ = true;

		log_->debug() << log_tag() << "==> INTERESTED";
	}
}
Ejemplo n.º 23
0
void P2PFolder::unchoke() {
	if(am_choking_) {
		send_message(parser_.gen_Unchoke());
		am_choking_ = false;

		log_->debug() << log_tag() << "==> UNCHOKE";
	}
}
Ejemplo n.º 24
0
void ControlServer::on_open(websocketpp::connection_hdl hdl) {
	log_->trace() << log_tag() << BOOST_CURRENT_FUNCTION;

	auto connection_ptr = ws_server_.get_con_from_hdl(hdl);
	ws_server_assignment_.insert(connection_ptr);

	send_control_json();
}
Ejemplo n.º 25
0
void P2PFolder::uninterest() {
	if(am_interested_) {
		send_message(parser_.gen_NotInterested());
		am_interested_ = false;

		log_->debug() << log_tag() << "==> NOT_INTERESTED";
	}
}
Ejemplo n.º 26
0
void P2PFolder::post_have_chunk(const blob& ct_hash) {
	V1Parser::HaveChunk message;
	message.ct_hash = ct_hash;
	send_message(parser_.gen_HaveChunk(message));

	log_->debug() << log_tag() << "==> HAVE_BLOCK:"
		<< " ct_hash=" << ct_hash_readable(ct_hash);
}
Ejemplo n.º 27
0
Downloader::Downloader(Client& client, FolderGroup& exchange_group) :
		Loggable(client, "Downloader"),
		client_(client),
		exchange_group_(exchange_group),
		periodic_maintain_(client.network_ios(), [this](PeriodicProcess& process){maintain_requests(process);}) {
	log_->trace() << log_tag() << BOOST_CURRENT_FUNCTION;
	periodic_maintain_.invoke();
}
Ejemplo n.º 28
0
void Downloader::add_needed_chunk(const blob& ct_hash) {
	log_->trace() << log_tag() << BOOST_CURRENT_FUNCTION;

	uint32_t unencrypted_blocksize = exchange_group_.fs_dir()->index->get_chunk_size(ct_hash);
	uint32_t padded_blocksize = unencrypted_blocksize % 16 == 0 ? unencrypted_blocksize : ((unencrypted_blocksize/16)+1)*16;
	auto needed_block = std::make_shared<NeededChunk>(padded_blocksize);
	needed_chunks_.insert({ct_hash, needed_block});
}
Ejemplo n.º 29
0
void P2PFolder::handle_Handshake(const blob& message_raw) {
	log_->trace() << log_tag() << BOOST_CURRENT_FUNCTION;
	auto message_struct = parser_.parse_Handshake(message_raw);
	log_->debug() << log_tag() << "<== HANDSHAKE";

	// Checking authentication using token
	if(message_struct.auth_token != remote_token()) throw auth_error();

	if(conn_.role == WSService::connection::SERVER) perform_handshake();

	client_name_ = message_struct.device_name;
	user_agent_ = message_struct.user_agent;

	log_->debug() << log_tag() << "LV Handshake successful";
	is_handshaken_ = true;

	folder_group()->handle_handshake(shared_from_this());
}
Ejemplo n.º 30
0
void WSService::on_tcp_pre_init(websocketpp::connection_hdl hdl, connection::role_type role) {
	log_->trace() << log_tag() << "on_tcp_pre_init()";

	connection& conn = ws_assignment_[hdl];
	conn.connection_handle = hdl;
	conn.role = role;

	ws_assignment_.insert({hdl, conn});
}