void session_inbound::handle_accept(const code& ec, channel::ptr channel,
    acceptor::ptr accept)
{
    if (stopped())
    {
        log::debug(LOG_NETWORK)
            << "Suspended inbound connection.";
        return;
    }

    start_accept(error::success, accept);

    if (ec)
    {
        log::debug(LOG_NETWORK)
            << "Failure accepting connection: " << ec.message();
        return;
    }

    if (blacklisted(channel->authority()))
    {
        log::debug(LOG_NETWORK)
            << "Rejected inbound connection from ["
            << channel->authority() << "] due to blacklisted address.";
        return;
    }

    connection_count(BIND2(handle_connection_count, _1, channel));
}
Example #2
0
void session_inbound::handle_accept(const code& ec, channel::ptr channel,
    acceptor::ptr accept)
{
    if (stopped())
        return;

    start_accept(error::success, accept);

    if (ec)
    {
        log::debug(LOG_NETWORK)
            << "Failure accepting connection: " << ec.message();
        return;
    }

    if (blacklisted(channel->authority()))
    {
        log::debug(LOG_NETWORK)
            << "Rejected inbound connection from ["
            << channel->authority() << "] due to blacklisted address.";
        return;
    }

    connection_count(
        dispatch_.ordered_delegate(&session_inbound::handle_connection_count,
            shared_from_base<session_inbound>(), _1, channel));
}
Example #3
0
void responder::send_pool_tx(const code& ec, const transaction& tx,
    const hash_digest& tx_hash, channel::ptr node)
{
    if (ec == error::service_stopped)
        return;

    if (ec == error::not_found)
    {
        log::debug(LOG_RESPONDER)
            << "Transaction for [" << node->authority()
            << "] not in mempool [" << encode_hash(tx_hash) << "]";

        // It wasn't in the mempool, so relay the request to the blockchain.
        blockchain_.fetch_transaction(tx_hash,
            std::bind(&responder::send_chain_tx,
                this, _1, _2, tx_hash, node));
        return;
    }

    if (ec)
    {
        log::error(LOG_RESPONDER)
            << "Failure fetching mempool tx data for ["
            << node->authority() << "] " << ec.message();
        node->stop(ec);
        return;
    }

    send_tx(tx, tx_hash, node);
}
void session::handle_is_pending(bool pending, channel::ptr channel,
    result_handler handle_started)
{
    if (pending)
    {
        log::debug(LOG_NETWORK)
            << "Rejected connection from [" << channel->authority()
            << "] as loopback.";
        handle_started(error::accept_failed);
        return;
    }

    const auto version = channel->version();
    if (version.value < bc::peer_minimum_version)
    {
        log::debug(LOG_NETWORK)
            << "Peer version (" << version.value << ") below minimum ("
            << bc::peer_minimum_version << ") [" 
            << channel->authority() << "]";
        handle_started(error::accept_failed);
        return;
    }

    network_.store(channel, handle_started);
}
Example #5
0
// en.bitcoin.it/wiki/Protocol_documentation#getdata
// getdata can be used to retrieve transactions, but only if they are
// in the memory pool or relay set - arbitrary access to transactions
// in the  chain is not allowed to avoid having clients start to depend
// on nodes having full transaction indexes (which modern nodes do not).
void responder::send_chain_tx(const code& ec, const transaction& tx,
    const hash_digest& tx_hash, channel::ptr node)
{
    if (ec == error::service_stopped)
        return;

    if (ec == error::not_found)
    {
        log::debug(LOG_RESPONDER)
            << "Transaction for [" << node->authority()
            << "] not in blockchain [" << encode_hash(tx_hash) << "]";

        // It wasn't in the blockchain, so send notfound.
        send_tx_not_found(tx_hash, node);
        return;
    }

    if (ec)
    {
        log::error(LOG_RESPONDER)
            << "Failure fetching blockchain tx data for ["
            << node->authority() << "] " << ec.message();
        node->stop(ec);
        return;
    }

    send_tx(tx, tx_hash, node);
}
void session_manual::handle_connect(const code& ec, channel::ptr channel,
    const std::string& hostname, uint16_t port, uint32_t remaining,
    connector::ptr connector, channel_handler handler)
{
    unpend(connector);

    if (ec)
    {
        LOG_WARNING(LOG_NETWORK)
            << "Failure connecting [" << config::endpoint(hostname, port)
            << "] manually: " << ec.message();

        // Retry logic.
        // The handler invoke is the failure end of the connect sequence.
        if (settings_.manual_attempt_limit == 0)
            start_connect(hostname, port, 0, handler);
        else if (remaining > 0)
            start_connect(hostname, port, remaining - 1, handler);
        else
            handler(ec, nullptr);

        return;
    }

    LOG_INFO(LOG_NETWORK)
        << "Connected manual channel [" << config::endpoint(hostname, port)
        << "] as [" << channel->authority() << "]";

    register_channel(channel, 
        BIND5(handle_channel_start, _1, hostname, port, channel, handler),
        BIND3(handle_channel_stop, _1, hostname, port));
}
Example #7
0
// We don't seem to be getting getdata requests.
void responder::receive_get_data(const code& ec, const get_data& packet,
    channel::ptr node)
{
    if (ec == error::channel_stopped)
        return;

    const auto peer = node->authority();

    if (ec)
    {
        log::debug(LOG_RESPONDER)
            << "Failure in receive get data [" << peer << "] " << ec.message();
        node->stop(ec);
        return;
    }

    // Resubscribe to serve tx and blocks.
    node->subscribe<message::get_data>(
        std::bind(&responder::receive_get_data,
            this, _1, _2, node));

    log::debug(LOG_RESPONDER)
        << "Getdata BEGIN [" << peer << "] "
        << "txs (" << packet.count(inventory_type_id::transaction) << ") "
        << "blocks (" << packet.count(inventory_type_id::block) << ") "
        << "bloom (" << packet.count(inventory_type_id::filtered_block) << ")";

    for (const auto& inventory: packet.inventories)
    {
        switch (inventory.type)
        {
            case inventory_type_id::transaction:
                log::debug(LOG_RESPONDER)
                    << "Transaction getdata for [" << peer << "] "
                    << encode_hash(inventory.hash);
                tx_pool_.fetch(inventory.hash,
                    std::bind(&responder::send_pool_tx,
                        this, _1, _2, inventory.hash, node));
                break;

            case inventory_type_id::block:
                log::debug(LOG_RESPONDER)
                    << "Block getdata for [" << peer << "] "
                    << encode_hash(inventory.hash);
                block_fetcher::fetch(blockchain_, inventory.hash,
                    std::bind(&responder::send_block,
                        this, _1, _2, inventory.hash, node));
                break;

            case inventory_type_id::error:
            case inventory_type_id::none:
            default:
                log::debug(LOG_RESPONDER)
                    << "Ignoring invalid getdata type for [" << peer << "]";
        }
    }

    log::debug(LOG_RESPONDER)
        << "Getdata END [" << peer << "]";
}
Example #8
0
void session_manual::handle_connect(const code& ec, channel::ptr channel,
    const std::string& hostname, uint16_t port, channel_handler handler,
    uint16_t retries)
{
    if (ec)
    {
        log::warning(LOG_NETWORK)
            << "Failure connecting [" << config::endpoint(hostname, port)
            << "] manually: " << ec.message();

        // Retry logic.
        if (settings_.connect_attempts == 0)
            start_connect(hostname, port, handler, 0);
        else if (retries > 0)
            start_connect(hostname, port, handler, retries - 1);
        else
            handler(ec, nullptr);

        return;
    }

    log::info(LOG_NETWORK)
        << "Connected manual channel [" << config::endpoint(hostname, port)
        << "] as [" << channel->authority() << "]";

    register_channel(channel, 
        std::bind(&session_manual::handle_channel_start,
            shared_from_base<session_manual>(), _1, hostname, port, channel, handler),
        std::bind(&session_manual::handle_channel_stop,
            shared_from_base<session_manual>(), _1, hostname, port));
}
void session::handle_remove(const code& ec, channel::ptr channel)
{
    if (ec)
        LOG_DEBUG(LOG_NETWORK)
            << "Failed to remove channel [" << channel->authority() << "] "
            << ec.message();
}
Example #10
0
void responder::send_tx(const transaction& tx, const hash_digest& hash,
    channel::ptr node)
{
    const auto send_handler = [hash, node](const code& ec)
    {
        if (ec)
            log::debug(LOG_RESPONDER)
                << "Failure sending tx for ["
                << node->authority() << "]";
        else
            log::debug(LOG_RESPONDER)
                << "Sent tx for [" << node->authority()
                << "] " << encode_hash(hash);
    };

    node->send(tx, send_handler);
}
Example #11
0
void responder::send_tx_not_found(const hash_digest& hash, channel::ptr node)
{
    const auto send_handler = [hash, node](const code& ec)
    {
        if (ec)
            log::debug(LOG_RESPONDER)
                << "Failure sending tx notfound for ["
                << node->authority() << "]";
        else
            log::debug(LOG_RESPONDER)
                << "Sent tx notfound for [" << node->authority()
                << "] " << encode_hash(hash);
    };

    send_inventory_not_found(inventory_type_id::transaction, hash, node,
        send_handler);
}
Example #12
0
void responder::send_block_not_found(const hash_digest& block_hash,
    channel::ptr node)
{
    const auto send_handler = [block_hash, node](const code& ec)
    {
        if (ec)
            log::debug(LOG_RESPONDER)
                << "Failure sending block notfound for ["
                << node->authority() << "]";
        else
            log::debug(LOG_RESPONDER)
                << "Sent block notfound for [" << node->authority()
                << "] " << encode_hash(block_hash);
    };

    send_inventory_not_found(inventory_type_id::block, block_hash,
        node, send_handler);
}
void session_outbound::handle_channel_stop(const code& ec,
    connector::ptr connect, channel::ptr channel)
{
    log::debug(LOG_NETWORK)
        << "Outbound channel stopped [" << channel->authority() << "] "
        << ec.message();

    new_connection(connect);
}
Example #14
0
void session_inbound::handle_connection_count(size_t connections,
    channel::ptr channel)
{
    if (connections >= settings_.inbound_connection_limit)
    {
        log::debug(LOG_NETWORK)
            << "Rejected inbound connection from ["
            << channel->authority() << "] due to connection limit.";
        return;
    }
   
    log::info(LOG_NETWORK)
        << "Connected inbound channel [" << channel->authority() << "]";

    register_channel(channel, 
        std::bind(&session_inbound::handle_channel_start,
            shared_from_base<session_inbound>(), _1, channel),
        std::bind(&session_inbound::handle_channel_stop,
            shared_from_base<session_inbound>(), _1));
}
void session_inbound::handle_connection_count(size_t connections,
    channel::ptr channel)
{
    const auto connection_limit = settings_.inbound_connections + 
        settings_.outbound_connections;

    if (connections >= connection_limit)
    {
        log::debug(LOG_NETWORK)
            << "Rejected inbound connection from ["
            << channel->authority() << "] due to connection limit.";
        return;
    }
   
    log::info(LOG_NETWORK)
        << "Connected inbound channel [" << channel->authority() << "]";

    register_channel(channel, 
        BIND2(handle_channel_start, _1, channel),
        BIND1(handle_channel_stop, _1));
}
void session_inbound::handle_channel_start(const code& ec,
    channel::ptr channel)
{
    if (ec)
    {
        LOG_INFO(LOG_NETWORK)
            << "Inbound channel failed to start [" << channel->authority()
            << "] " << ec.message();
        return;
    }

    attach_protocols(channel);
};
Example #17
0
// Should we look in the orphan pool first?
void responder::send_block(const code& ec, const block& block,
    const hash_digest& block_hash, channel::ptr node)
{
    if (ec == error::service_stopped)
        return;

    if (ec == error::not_found)
    {
        log::debug(LOG_RESPONDER)
            << "Block for [" << node->authority()
            << "] not in blockchain [" << encode_hash(block_hash) << "]";

        // It wasn't in the blockchain, so send notfound.
        send_block_not_found(block_hash, node);
    }

    if (ec)
    {
        log::error(LOG_RESPONDER)
            << "Failure fetching block data for ["
            << node->authority() << "] " << ec.message();
        node->stop(ec);
        return;
    }

    const auto send_handler = [block_hash, node](const code& ec)
    {
        if (ec)
            log::debug(LOG_RESPONDER)
                << "Failure sending block for ["
                << node->authority() << "]";
        else
            log::debug(LOG_RESPONDER)
                << "Sent block for [" << node->authority()
                << "] " << encode_hash(block_hash);
    };

    node->send(block, send_handler);
}
void session_inbound::handle_is_pending(bool pending, channel::ptr channel,
    result_handler handle_started)
{
    if (pending)
    {
        LOG_DEBUG(LOG_NETWORK)
            << "Rejected connection from [" << channel->authority()
            << "] as loopback.";
        handle_started(error::accept_failed);
        return;
    }

    session::start_channel(channel, handle_started);
}
void session_inbound::handle_channel_start(const code& ec,
    channel::ptr channel)
{
    
    if (ec)
    {
        log::info(LOG_NETWORK)
            << "Inbound channel failed to start [" << channel->authority()
            << "] " << ec.message();
        return;
    }

    attach<protocol_ping>(channel)->start();
    attach<protocol_address>(channel)->start();
}
Example #20
0
void session::handle_starting(const code& ec, channel::ptr channel,
    result_handler handle_started)
{
    if (ec)
    {
        LOG_INFO(LOG_NETWORK)
            << "Channel failed to start [" << channel->authority() << "] "
            << ec.message();
        handle_started(ec);
        return;
    }

    attach_handshake_protocols(channel,
        BIND_3(handle_handshake, _1, channel, handle_started));
}
Example #21
0
void session::handle_handshake(const code& ec, channel::ptr channel,
    result_handler handle_started)
{
    if (ec)
    {
        LOG_DEBUG(LOG_NETWORK)
            << "Failure in handshake with [" << channel->authority()
            << "] " << ec.message();

        handle_started(ec);
        return;
    }

    // This will fail if the IP address or nonce is already connected.
    network_.store(channel, handle_started);
}
Example #22
0
code p2p::store(channel::ptr channel)
{
    const auto address = channel->authority();
    const auto match = [&address](const channel::ptr& element)
    {
        return element->authority() == address;
    };

    // May return error::address_in_use.
    const auto ec = pending_close_.store(channel, match);

    if (!ec && channel->notify())
        channel_subscriber_->relay(error::success, channel);

    return ec;
}
void session_outbound::handle_channel_start(const code& ec,
    connector::ptr connect, channel::ptr channel)
{
    // Treat a start failure just like a stop.
    if (ec)
    {
        log::debug(LOG_NETWORK)
            << "Outbound channel failed to start ["
            << channel->authority() << "] " << ec.message();

        new_connection(connect);
        return;
    }

    attach_protocols(channel);
};
// It is common for no connections, one connection or multiple connections to
// succeed, but only zero or one will reach this point. Other connections that
// succeed fall out of scope causing the socket to close on destruct.
void session_batch::handle_connect(const code& ec, channel::ptr channel,
    channel_handler handler)
{
    if (ec)
    {
        LOG_DEBUG(LOG_NETWORK)
            << "Failed to connect after (" << batch_size_
            << ") concurrent attempts: " << ec.message();
        handler(ec, nullptr);
        return;
    }

    LOG_DEBUG(LOG_NETWORK)
        << "Connected to [" << channel->authority() << "]";

    // This is the end of the connect sequence.
    handler(error::success, channel);
}
void session_outbound::handle_connect(const code& ec, channel::ptr channel,
    connector::ptr connect)
{
    if (ec)
    {
        log::debug(LOG_NETWORK)
            << "Failure connecting outbound: " << ec.message();
        new_connection(connect);
        return;
    }

    log::info(LOG_NETWORK)
        << "Connected to outbound channel [" << channel->authority() << "]";

    register_channel(channel, 
        BIND3(handle_channel_start, _1, connect, channel),
        BIND3(handle_channel_stop, _1, connect, channel));
}
void session_manual::handle_channel_start(const code& ec,
    const std::string& hostname, uint16_t port, channel::ptr channel,
    channel_handler handler)
{
    // The start failure is also caught by handle_channel_stop.
    // Treat a start failure like a stop, but preserve the start handler.
    if (ec)
    {
        LOG_INFO(LOG_NETWORK)
            << "Manual channel failed to start [" << channel->authority()
            << "] " << ec.message();
        return;
    }

    // This is the success end of the connect sequence.
    handler(error::success, channel);
    attach_protocols(channel);
};
void session::handle_handshake(const code& ec, channel::ptr channel,
    result_handler handle_started)
{
    if (ec)
    {
        log::debug(LOG_NETWORK)
            << "Failure in handshake with [" << channel->authority()
            << "] " << ec.message();
        handle_started(ec);
        return;
    }

    truth_handler handler = 
        BIND_3(handle_is_pending, _1, channel, handle_started);

    // The loopback test is for incoming channels only.
    if (incoming_)
        pending_.exists(channel->version().nonce, handler);
    else
        handler(false);
}
Example #28
0
void session_outbound::handle_connect(const code& ec, channel::ptr channel,
    const authority& host, connector::ptr connect)
{
    if (ec)
    {
        log::debug(LOG_NETWORK)
            << "Failure connecting [" << host << "] outbound: "
            << ec.message();
        new_connection(connect);
        return;
    }

    log::info(LOG_NETWORK)
        << "Connected to outbound channel [" << channel->authority() << "]";

    register_channel(channel, 
        std::bind(&session_outbound::handle_channel_start,
            shared_from_base<session_outbound>(), _1, connect, channel),
        std::bind(&session_outbound::handle_channel_stop,
            shared_from_base<session_outbound>(), _1, connect));
}
void session_batch::handle_connect(const code& ec, channel::ptr channel,
    const authority& host, connector::ptr connect, atomic_counter_ptr counter,
    channel_handler handler)
{
    if (counter->load() == batch_size_)
        return;

    if (ec)
    {
        log::debug(LOG_NETWORK)
            << "Failure connecting to [" << host << "] "
            << ec.message();
        handler(ec, nullptr);
        return;
    }

    log::debug(LOG_NETWORK)
        << "Connected to [" << channel->authority() << "]";

    // This is the end of the connect sequence.
    handler(error::success, channel);
}