Example #1
0
void
ConnectAttempt::onHandshake (error_code ec)
{
    cancelTimer();
    if(! stream_.next_layer().is_open())
        return;
    if(ec == boost::asio::error::operation_aborted)
        return;
    endpoint_type local_endpoint;
    if (! ec)
        local_endpoint = stream_.next_layer().local_endpoint(ec);
    if(ec)
        return fail("onHandshake", ec);
    JLOG(journal_.trace()) <<
        "onHandshake";

    if (! overlay_.peerFinder().onConnected (slot_,
            beast::IPAddressConversion::from_asio (local_endpoint)))
        return fail("Duplicate connection");

    auto sharedValue = makeSharedValue(
        stream_.native_handle(), journal_);
    if (! sharedValue)
        return close(); // makeSharedValue logs

    req_ = makeRequest(! overlay_.peerFinder().config().peerPrivate,
        remote_endpoint_.address());
    auto const hello = buildHello (
        *sharedValue,
        overlay_.setup().public_ip,
        beast::IPAddressConversion::from_asio(remote_endpoint_),
        app_);
    appendHello (req_, hello);

    setTimer();
    boost::beast::http::async_write(stream_, req_,
        strand_.wrap (std::bind (&ConnectAttempt::onWrite,
            shared_from_this(), std::placeholders::_1)));
}
Example #2
0
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);
}
Example #3
0
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;
}