void ConnectAttempt::processResponse() { if (response_.result() == boost::beast::http::status::service_unavailable) { Json::Value json; Json::Reader r; std::string s; s.reserve(boost::asio::buffer_size(response_.body().data())); for(auto const& buffer : response_.body().data()) s.append( boost::asio::buffer_cast<char const*>(buffer), boost::asio::buffer_size(buffer)); auto const success = r.parse(s, json); if (success) { if (json.isObject() && json.isMember("peer-ips")) { Json::Value const& ips = json["peer-ips"]; if (ips.isArray()) { std::vector<boost::asio::ip::tcp::endpoint> eps; eps.reserve(ips.size()); for (auto const& v : ips) { if (v.isString()) { error_code ec; auto const ep = parse_endpoint(v.asString(), ec); if (!ec) eps.push_back(ep); } } overlay_.peerFinder().onRedirects( remote_endpoint_, eps); } } } } if (! OverlayImpl::isPeerUpgrade(response_)) { JLOG(journal_.info()) << "HTTP Response: " << response_.result() << " " << response_.reason(); return close(); } auto hello = parseHello (false, response_, journal_); if(! hello) return fail("processResponse: Bad TMHello"); auto sharedValue = makeSharedValue( ssl_bundle_->stream.native_handle(), journal_); if(! sharedValue) return close(); // makeSharedValue logs auto publicKey = verifyHello (*hello, *sharedValue, overlay_.setup().public_ip, beast::IPAddressConversion::from_asio(remote_endpoint_), journal_, app_); if(! publicKey) return close(); // verifyHello logs JLOG(journal_.info()) << "Public Key: " << toBase58 ( TokenType::NodePublic, *publicKey); auto const protocol = BuildInfo::make_protocol(hello->protoversion()); JLOG(journal_.info()) << "Protocol: " << to_string(protocol); auto member = app_.cluster().member(*publicKey); if (member) { JLOG(journal_.info()) << "Cluster name: " << *member; } auto const result = overlay_.peerFinder().activate (slot_, *publicKey, static_cast<bool>(member)); if (result != PeerFinder::Result::success) return fail("Outbound slots full"); auto const peer = std::make_shared<PeerImp>(app_, std::move(ssl_bundle_), read_buf_.data(), std::move(slot_), std::move(response_), usage_, *hello, *publicKey, id_, overlay_); overlay_.add_active (peer); }
Handoff OverlayImpl::onHandoff (std::unique_ptr <beast::asio::ssl_bundle>&& ssl_bundle, beast::http::message&& request, endpoint_type remote_endpoint) { auto const id = next_id_++; beast::WrappedSink sink (deprecatedLogs()["Peer"], makePrefix(id)); beast::Journal journal (sink); Handoff handoff; if (processRequest(request, handoff)) return handoff; if (! isPeerUpgrade(request)) return handoff; handoff.moved = true; if (journal.trace) journal.trace << "Peer connection upgrade from " << remote_endpoint; error_code ec; auto const local_endpoint (ssl_bundle->socket.local_endpoint(ec)); if (ec) { if (journal.trace) journal.trace << remote_endpoint << " failed: " << ec.message(); return handoff; } auto consumer = m_resourceManager.newInboundEndpoint( beast::IPAddressConversion::from_asio(remote_endpoint)); if (consumer.disconnect()) return handoff; auto const slot = m_peerFinder->new_inbound_slot ( beast::IPAddressConversion::from_asio(local_endpoint), beast::IPAddressConversion::from_asio(remote_endpoint)); if (slot == nullptr) { // self-connect, close handoff.moved = false; return handoff; } // TODO Validate HTTP request { auto const types = beast::rfc2616::split_commas( request.headers["Connect-As"]); if (std::find_if(types.begin(), types.end(), [](std::string const& s) { return beast::ci_equal(s, "peer"); }) == types.end()) { handoff.moved = false; handoff.response = makeRedirectResponse(slot, request, remote_endpoint.address()); handoff.keep_alive = request.keep_alive(); return handoff; } } handoff.moved = true; bool success = true; protocol::TMHello hello; std::tie(hello, success) = parseHello (request, journal); if(! success) return handoff; uint256 sharedValue; std::tie(sharedValue, success) = makeSharedValue( ssl_bundle->stream.native_handle(), journal); if(! success) return handoff; RippleAddress publicKey; std::tie(publicKey, success) = verifyHello (hello, sharedValue, journal, getApp()); if(! success) return handoff; std::string name; bool const cluster = getApp().getUNL().nodeInCluster( publicKey, name); auto const result = m_peerFinder->activate (slot, publicKey.toPublicKey(), cluster); if (result != PeerFinder::Result::success) { if (journal.trace) journal.trace << "Peer " << remote_endpoint << " redirected, slots full"; handoff.moved = false; handoff.response = makeRedirectResponse(slot, request, remote_endpoint.address()); handoff.keep_alive = request.keep_alive(); return handoff; } auto const peer = std::make_shared<PeerImp>(id, remote_endpoint, slot, std::move(request), hello, publicKey, consumer, std::move(ssl_bundle), *this); { // As we are not on the strand, run() must be called // while holding the lock, otherwise new I/O can be // queued after a call to stop(). std::lock_guard <decltype(mutex_)> lock (mutex_); add(peer); peer->run(); } handoff.moved = true; return handoff; }