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()); } }
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; }
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); }
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_; }
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()); } }
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()); } }
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); }
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; }
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); }
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); }
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); }
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()); } }
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); }
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()); } }
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); }
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; }
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"; } }
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; } }
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; }
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); } }
/* RPC Actions */ void P2PFolder::choke() { if(! am_choking_) { send_message(parser_.gen_Choke()); am_choking_ = true; log_->debug() << log_tag() << "==> CHOKE"; } }
void P2PFolder::interest() { if(! am_interested_) { send_message(parser_.gen_Interested()); am_interested_ = true; log_->debug() << log_tag() << "==> INTERESTED"; } }
void P2PFolder::unchoke() { if(am_choking_) { send_message(parser_.gen_Unchoke()); am_choking_ = false; log_->debug() << log_tag() << "==> UNCHOKE"; } }
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(); }
void P2PFolder::uninterest() { if(am_interested_) { send_message(parser_.gen_NotInterested()); am_interested_ = false; log_->debug() << log_tag() << "==> NOT_INTERESTED"; } }
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); }
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(); }
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}); }
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()); }
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}); }