<commit_before>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

//! Remotely authenticated vs. unauthenticated network end-points:
//! ---------------------------------------------------
//! A network end-point operates with remote authentication if it only accepts connections
//! from a known set of peers (`trusted_peers`) identified by their network identity keys.
//! This does not mean that the other end-point of a connection also needs to operate with
//! authentication -- a network end-point running with remote authentication enabled will
//! connect to or accept connections from an end-point running in authenticated mode as
//! long as the latter is in its trusted peers set.
use channel::{self, message_queues::QueueStyle};
use diem_config::{
    config::{
        DiscoveryMethod, NetworkConfig, Peer, PeerRole, PeerSet, RateLimitConfig, RoleType,
        CONNECTION_BACKOFF_BASE, CONNECTIVITY_CHECK_INTERVAL_MS, MAX_CONCURRENT_NETWORK_REQS,
        MAX_CONNECTION_DELAY_MS, MAX_FRAME_SIZE, MAX_FULLNODE_OUTBOUND_CONNECTIONS,
        MAX_INBOUND_CONNECTIONS, NETWORK_CHANNEL_SIZE,
    },
    network_id::NetworkContext,
};
use diem_crypto::x25519::PublicKey;
use diem_infallible::RwLock;
use diem_logger::prelude::*;
use diem_metrics::IntCounterVec;
use diem_network_address_encryption::Encryptor;
use diem_time_service::TimeService;
use diem_types::{chain_id::ChainId, network_address::NetworkAddress};
use network::{
    connectivity_manager::{builder::ConnectivityManagerBuilder, ConnectivityRequest},
    logging::NetworkSchema,
    peer_manager::{
        builder::{AuthenticationMode, PeerManagerBuilder},
        conn_notifs_channel, ConnectionRequestSender,
    },
    protocols::{
        health_checker::{self, builder::HealthCheckerBuilder},
        network::{NewNetworkEvents, NewNetworkSender},
    },
    ProtocolId,
};
use network_simple_onchain_discovery::{
    builder::ValidatorSetChangeListenerBuilder, gen_simple_discovery_reconfig_subscription,
};
use std::{clone::Clone, collections::HashMap, sync::Arc};
use subscription_service::ReconfigSubscription;
use tokio::runtime::Handle;

#[derive(Debug, PartialEq, PartialOrd)]
enum State {
    CREATED,
    BUILT,
    STARTED,
}

/// Build Network module with custom configuration values.
/// Methods can be chained in order to set the configuration values.
/// MempoolNetworkHandler and ConsensusNetworkHandler are constructed by calling
/// [`NetworkBuilder::build`].  New instances of `NetworkBuilder` are obtained
/// via [`NetworkBuilder::create`].
pub struct NetworkBuilder {
    state: State,
    executor: Option<Handle>,
    time_service: TimeService,
    network_context: Arc<NetworkContext>,

    configuration_change_listener_builder: Option<ValidatorSetChangeListenerBuilder>,
    connectivity_manager_builder: Option<ConnectivityManagerBuilder>,
    health_checker_builder: Option<HealthCheckerBuilder>,
    peer_manager_builder: PeerManagerBuilder,

    // (StateSync) ReconfigSubscriptions required by internal Network components.
    reconfig_subscriptions: Vec<ReconfigSubscription>,
}

impl NetworkBuilder {
    /// Return a new NetworkBuilder initialized with default configuration values.
    // TODO:  Remove `pub`.  NetworkBuilder should only be created thorugh `::create()`
    pub fn new(
        chain_id: ChainId,
        trusted_peers: Arc<RwLock<PeerSet>>,
        network_context: Arc<NetworkContext>,
        time_service: TimeService,
        listen_address: NetworkAddress,
        authentication_mode: AuthenticationMode,
        max_frame_size: usize,
        enable_proxy_protocol: bool,
        network_channel_size: usize,
        max_concurrent_network_reqs: usize,
        inbound_connection_limit: usize,
        inbound_rate_limit_config: Option<RateLimitConfig>,
        outbound_rate_limit_config: Option<RateLimitConfig>,
    ) -> Self {
        // A network cannot exist without a PeerManager
        // TODO:  construct this in create and pass it to new() as a parameter. The complication is manual construction of NetworkBuilder in various tests.
        let peer_manager_builder = PeerManagerBuilder::create(
            chain_id,
            network_context.clone(),
            time_service.clone(),
            listen_address,
            trusted_peers,
            authentication_mode,
            network_channel_size,
            max_concurrent_network_reqs,
            max_frame_size,
            enable_proxy_protocol,
            inbound_connection_limit,
            inbound_rate_limit_config,
            outbound_rate_limit_config,
        );

        NetworkBuilder {
            state: State::CREATED,
            executor: None,
            time_service,
            network_context,
            configuration_change_listener_builder: None,
            connectivity_manager_builder: None,
            health_checker_builder: None,
            peer_manager_builder,
            reconfig_subscriptions: vec![],
        }
    }

    pub fn new_for_test(
        chain_id: ChainId,
        seeds: PeerSet,
        trusted_peers: Arc<RwLock<PeerSet>>,
        network_context: Arc<NetworkContext>,
        time_service: TimeService,
        listen_address: NetworkAddress,
        authentication_mode: AuthenticationMode,
    ) -> NetworkBuilder {
        let mutual_authentication = matches!(authentication_mode, AuthenticationMode::Mutual(_));

        let mut builder = NetworkBuilder::new(
            chain_id,
            trusted_peers.clone(),
            network_context,
            time_service,
            listen_address,
            authentication_mode,
            MAX_FRAME_SIZE,
            false, /* Disable proxy protocol */
            NETWORK_CHANNEL_SIZE,
            MAX_CONCURRENT_NETWORK_REQS,
            MAX_INBOUND_CONNECTIONS,
            None,
            None,
        );

        builder.add_connectivity_manager(
            seeds,
            trusted_peers,
            MAX_FULLNODE_OUTBOUND_CONNECTIONS,
            CONNECTION_BACKOFF_BASE,
            MAX_CONNECTION_DELAY_MS,
            CONNECTIVITY_CHECK_INTERVAL_MS,
            NETWORK_CHANNEL_SIZE,
            mutual_authentication,
        );

        builder
    }

    /// Create a new NetworkBuilder based on the provided configuration.
    pub fn create(
        chain_id: ChainId,
        role: RoleType,
        config: &NetworkConfig,
        time_service: TimeService,
    ) -> NetworkBuilder {
        let peer_id = config.peer_id();
        let identity_key = config.identity_key();
        let pubkey = identity_key.public_key();

        let authentication_mode = if config.mutual_authentication {
            AuthenticationMode::Mutual(identity_key)
        } else {
            AuthenticationMode::MaybeMutual(identity_key)
        };

        let network_context = Arc::new(NetworkContext::new(
            role,
            config.network_id.clone(),
            peer_id,
        ));

        let trusted_peers = Arc::new(RwLock::new(HashMap::new()));

        let mut network_builder = NetworkBuilder::new(
            chain_id,
            trusted_peers.clone(),
            network_context,
            time_service,
            config.listen_address.clone(),
            authentication_mode,
            config.max_frame_size,
            config.enable_proxy_protocol,
            config.network_channel_size,
            config.max_concurrent_network_reqs,
            config.max_inbound_connections,
            config.inbound_rate_limit_config,
            config.outbound_rate_limit_config,
        );

        network_builder.add_connection_monitoring(
            config.ping_interval_ms,
            config.ping_timeout_ms,
            config.ping_failures_tolerated,
        );

        // Don't turn on connectivity manager if we're a public-facing server,
        // for example.
        //
        // Cases that require connectivity manager:
        //
        // 1) mutual authentication networks currently require connmgr to set the
        //    trusted peers set.
        // 2) networks with a discovery protocol need connmgr to connect to newly
        //    discovered peers.
        // 3) if we have seed peers, then we need connmgr to connect to them.
        // TODO(philiphayes): could probably use a better way to specify these cases
        // TODO:  Why not add ConnectivityManager always?
        if config.mutual_authentication
            || config.discovery_method != DiscoveryMethod::None
            || !config.seed_addrs.is_empty()
            || !config.seeds.is_empty()
        {
            let seeds = merge_seeds(config);

            network_builder.add_connectivity_manager(
                seeds,
                trusted_peers,
                config.max_outbound_connections,
                config.connection_backoff_base,
                config.max_connection_delay_ms,
                config.connectivity_check_interval_ms,
                config.network_channel_size,
                config.mutual_authentication,
            );
        }

        match &config.discovery_method {
            DiscoveryMethod::Onchain => {
                network_builder.add_validator_set_listener(pubkey, config.encryptor());
            }
            DiscoveryMethod::None => {}
        }

        network_builder
    }

    /// Create the configured Networking components.
    pub fn build(&mut self, executor: Handle) -> &mut Self {
        assert_eq!(self.state, State::CREATED);
        self.state = State::BUILT;
        self.executor = Some(executor);
        self.build_peer_manager()
    }

    /// Start the built Networking components.
    pub fn start(&mut self) -> &mut Self {
        assert_eq!(self.state, State::BUILT);
        self.state = State::STARTED;
        self.start_peer_manager()
            .start_connectivity_manager()
            .start_connection_monitoring()
            .start_validator_set_listener()
    }

    pub fn reconfig_subscriptions(&mut self) -> &mut Vec<ReconfigSubscription> {
        &mut self.reconfig_subscriptions
    }

    pub fn network_context(&self) -> Arc<NetworkContext> {
        self.network_context.clone()
    }

    pub fn conn_mgr_reqs_tx(&self) -> Option<channel::Sender<ConnectivityRequest>> {
        self.connectivity_manager_builder
            .as_ref()
            .map(|conn_mgr_builder| conn_mgr_builder.conn_mgr_reqs_tx())
    }

    fn add_connection_event_listener(&mut self) -> conn_notifs_channel::Receiver {
        self.peer_manager_builder.add_connection_event_listener()
    }

    pub fn listen_address(&self) -> NetworkAddress {
        self.peer_manager_builder.listen_address()
    }

    fn build_peer_manager(&mut self) -> &mut Self {
        self.peer_manager_builder
            .build(self.executor.as_mut().expect("Executor must exist"));
        self
    }

    fn start_peer_manager(&mut self) -> &mut Self {
        self.peer_manager_builder
            .start(self.executor.as_mut().expect("Executor must exist"));
        self
    }

    /// Add a [`ConnectivityManager`] to the network.
    ///
    /// [`ConnectivityManager`] is responsible for ensuring that we are connected
    /// to a node iff. it is an eligible node and maintaining persistent
    /// connections with all eligible nodes. A list of eligible nodes is received
    /// at initialization, and updates are received on changes to system membership.
    ///
    /// Note: a connectivity manager should only be added if the network is
    /// permissioned.
    pub fn add_connectivity_manager(
        &mut self,
        seeds: PeerSet,
        trusted_peers: Arc<RwLock<PeerSet>>,
        max_outbound_connections: usize,
        connection_backoff_base: u64,
        max_connection_delay_ms: u64,
        connectivity_check_interval_ms: u64,
        channel_size: usize,
        mutual_authentication: bool,
    ) -> &mut Self {
        let pm_conn_mgr_notifs_rx = self.add_connection_event_listener();
        let outbound_connection_limit = if !self.network_context.network_id().is_validator_network()
        {
            Some(max_outbound_connections)
        } else {
            None
        };

        self.connectivity_manager_builder = Some(ConnectivityManagerBuilder::create(
            self.network_context(),
            self.time_service.clone(),
            trusted_peers,
            seeds,
            connectivity_check_interval_ms,
            connection_backoff_base,
            max_connection_delay_ms,
            channel_size,
            ConnectionRequestSender::new(self.peer_manager_builder.connection_reqs_tx()),
            pm_conn_mgr_notifs_rx,
            outbound_connection_limit,
            mutual_authentication,
        ));
        self
    }

    fn start_connectivity_manager(&mut self) -> &mut Self {
        if let Some(builder) = self.connectivity_manager_builder.as_mut() {
            builder.start(self.executor.as_mut().expect("Executor must exist"));
        }
        self
    }

    fn add_validator_set_listener(&mut self, pubkey: PublicKey, encryptor: Encryptor) -> &mut Self {
        let conn_mgr_reqs_tx = self
            .conn_mgr_reqs_tx()
            .expect("ConnectivityManager must be installed for validator");
        let (simple_discovery_reconfig_subscription, simple_discovery_reconfig_rx) =
            gen_simple_discovery_reconfig_subscription();
        self.reconfig_subscriptions
            .push(simple_discovery_reconfig_subscription);

        self.configuration_change_listener_builder =
            Some(ValidatorSetChangeListenerBuilder::create(
                self.network_context.clone(),
                pubkey,
                encryptor,
                conn_mgr_reqs_tx,
                simple_discovery_reconfig_rx,
            ));
        self
    }

    fn start_validator_set_listener(&mut self) -> &mut Self {
        if let Some(configuration_change_listener) =
            self.configuration_change_listener_builder.as_mut()
        {
            configuration_change_listener
                .start(self.executor.as_mut().expect("Executor must exist"));
        }
        self
    }

    /// Add a HealthChecker to the network.
    fn add_connection_monitoring(
        &mut self,
        ping_interval_ms: u64,
        ping_timeout_ms: u64,
        ping_failures_tolerated: u64,
    ) -> &mut Self {
        // Initialize and start HealthChecker.
        let (hc_network_tx, hc_network_rx) =
            self.add_protocol_handler(health_checker::network_endpoint_config());

        self.health_checker_builder = Some(HealthCheckerBuilder::new(
            self.network_context(),
            self.time_service.clone(),
            ping_interval_ms,
            ping_timeout_ms,
            ping_failures_tolerated,
            hc_network_tx,
            hc_network_rx,
        ));
        debug!(
            NetworkSchema::new(&self.network_context),
            "{} Created health checker", self.network_context
        );
        self
    }

    /// Star the built HealthChecker.
    fn start_connection_monitoring(&mut self) -> &mut Self {
        if let Some(health_checker) = self.health_checker_builder.as_mut() {
            health_checker.start(self.executor.as_mut().expect("Executor must exist"));
            debug!(
                NetworkSchema::new(&self.network_context),
                "{} Started health checker", self.network_context
            );
        };
        self
    }

    /// Adds a endpoints for the provided configuration.  Returns NetworkSender and NetworkEvent which
    /// can be attached to other components.
    pub fn add_protocol_handler<SenderT, EventT>(
        &mut self,
        (rpc_protocols, direct_send_protocols, queue_preference, max_queue_size_per_peer, counter): (
            Vec<ProtocolId>,
            Vec<ProtocolId>,
            QueueStyle,
            usize,
            Option<&'static IntCounterVec>,
        ),
    ) -> (SenderT, EventT)
    where
        EventT: NewNetworkEvents,
        SenderT: NewNetworkSender,
    {
        let (peer_mgr_reqs_tx, peer_mgr_reqs_rx, connection_reqs_tx, connection_notifs_rx) =
            self.peer_manager_builder.add_protocol_handler(
                rpc_protocols,
                direct_send_protocols,
                queue_preference,
                max_queue_size_per_peer,
                counter,
            );
        (
            SenderT::new(peer_mgr_reqs_tx, connection_reqs_tx),
            EventT::new(peer_mgr_reqs_rx, connection_notifs_rx),
        )
    }
}

/// Retrieve and merge seeds so that they have all keys associated
fn merge_seeds(config: &NetworkConfig) -> PeerSet {
    config.verify_seeds().expect("Seeds must be well formed");
    let mut seeds = config.seeds.clone();

    // Merge old seed configuration with new seed configuration
    // TODO(gnazario): Once fully migrated, remove `seed_addrs`
    config
        .seed_addrs
        .iter()
        .map(|(peer_id, addrs)| {
            (
                peer_id,
                Peer::from_addrs(PeerRole::ValidatorFullNode, addrs.clone()),
            )
        })
        .for_each(|(peer_id, peer)| {
            seeds
                .entry(*peer_id)
                // Sad clone due to Rust not realizing these are two distinct paths
                .and_modify(|seed| seed.extend(peer.clone()).unwrap())
                .or_insert(peer);
        });

    // Pull public keys out of addresses
    seeds.values_mut().for_each(
        |Peer {
             addresses, keys, ..
         }| {
            addresses
                .iter()
                .filter_map(NetworkAddress::find_noise_proto)
                .for_each(|pubkey| {
                    keys.insert(pubkey);
                });
        },
    );
    seeds
}
<commit_msg>[network] Remove superfluous functions from NetworkBuilder<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

//! Remotely authenticated vs. unauthenticated network end-points:
//! ---------------------------------------------------
//! A network end-point operates with remote authentication if it only accepts connections
//! from a known set of peers (`trusted_peers`) identified by their network identity keys.
//! This does not mean that the other end-point of a connection also needs to operate with
//! authentication -- a network end-point running with remote authentication enabled will
//! connect to or accept connections from an end-point running in authenticated mode as
//! long as the latter is in its trusted peers set.
use channel::{self, message_queues::QueueStyle};
use diem_config::{
    config::{
        DiscoveryMethod, NetworkConfig, Peer, PeerRole, PeerSet, RateLimitConfig, RoleType,
        CONNECTION_BACKOFF_BASE, CONNECTIVITY_CHECK_INTERVAL_MS, MAX_CONCURRENT_NETWORK_REQS,
        MAX_CONNECTION_DELAY_MS, MAX_FRAME_SIZE, MAX_FULLNODE_OUTBOUND_CONNECTIONS,
        MAX_INBOUND_CONNECTIONS, NETWORK_CHANNEL_SIZE,
    },
    network_id::NetworkContext,
};
use diem_crypto::x25519::PublicKey;
use diem_infallible::RwLock;
use diem_logger::prelude::*;
use diem_metrics::IntCounterVec;
use diem_network_address_encryption::Encryptor;
use diem_time_service::TimeService;
use diem_types::{chain_id::ChainId, network_address::NetworkAddress};
use network::{
    connectivity_manager::{builder::ConnectivityManagerBuilder, ConnectivityRequest},
    logging::NetworkSchema,
    peer_manager::{
        builder::{AuthenticationMode, PeerManagerBuilder},
        ConnectionRequestSender,
    },
    protocols::{
        health_checker::{self, builder::HealthCheckerBuilder},
        network::{NewNetworkEvents, NewNetworkSender},
    },
    ProtocolId,
};
use network_simple_onchain_discovery::{
    builder::ValidatorSetChangeListenerBuilder, gen_simple_discovery_reconfig_subscription,
};
use std::{clone::Clone, collections::HashMap, sync::Arc};
use subscription_service::ReconfigSubscription;
use tokio::runtime::Handle;

#[derive(Debug, PartialEq, PartialOrd)]
enum State {
    CREATED,
    BUILT,
    STARTED,
}

/// Build Network module with custom configuration values.
/// Methods can be chained in order to set the configuration values.
/// MempoolNetworkHandler and ConsensusNetworkHandler are constructed by calling
/// [`NetworkBuilder::build`].  New instances of `NetworkBuilder` are obtained
/// via [`NetworkBuilder::create`].
pub struct NetworkBuilder {
    state: State,
    executor: Option<Handle>,
    time_service: TimeService,
    network_context: Arc<NetworkContext>,

    validator_set_listener_builder: Option<ValidatorSetChangeListenerBuilder>,
    connectivity_manager_builder: Option<ConnectivityManagerBuilder>,
    health_checker_builder: Option<HealthCheckerBuilder>,
    peer_manager_builder: PeerManagerBuilder,

    // (StateSync) ReconfigSubscriptions required by internal Network components.
    reconfig_subscriptions: Vec<ReconfigSubscription>,
}

impl NetworkBuilder {
    /// Return a new NetworkBuilder initialized with default configuration values.
    // TODO:  Remove `pub`.  NetworkBuilder should only be created thorugh `::create()`
    pub fn new(
        chain_id: ChainId,
        trusted_peers: Arc<RwLock<PeerSet>>,
        network_context: Arc<NetworkContext>,
        time_service: TimeService,
        listen_address: NetworkAddress,
        authentication_mode: AuthenticationMode,
        max_frame_size: usize,
        enable_proxy_protocol: bool,
        network_channel_size: usize,
        max_concurrent_network_reqs: usize,
        inbound_connection_limit: usize,
        inbound_rate_limit_config: Option<RateLimitConfig>,
        outbound_rate_limit_config: Option<RateLimitConfig>,
    ) -> Self {
        // A network cannot exist without a PeerManager
        // TODO:  construct this in create and pass it to new() as a parameter. The complication is manual construction of NetworkBuilder in various tests.
        let peer_manager_builder = PeerManagerBuilder::create(
            chain_id,
            network_context.clone(),
            time_service.clone(),
            listen_address,
            trusted_peers,
            authentication_mode,
            network_channel_size,
            max_concurrent_network_reqs,
            max_frame_size,
            enable_proxy_protocol,
            inbound_connection_limit,
            inbound_rate_limit_config,
            outbound_rate_limit_config,
        );

        NetworkBuilder {
            state: State::CREATED,
            executor: None,
            time_service,
            network_context,
            validator_set_listener_builder: None,
            connectivity_manager_builder: None,
            health_checker_builder: None,
            peer_manager_builder,
            reconfig_subscriptions: vec![],
        }
    }

    pub fn new_for_test(
        chain_id: ChainId,
        seeds: PeerSet,
        trusted_peers: Arc<RwLock<PeerSet>>,
        network_context: Arc<NetworkContext>,
        time_service: TimeService,
        listen_address: NetworkAddress,
        authentication_mode: AuthenticationMode,
    ) -> NetworkBuilder {
        let mutual_authentication = matches!(authentication_mode, AuthenticationMode::Mutual(_));

        let mut builder = NetworkBuilder::new(
            chain_id,
            trusted_peers.clone(),
            network_context,
            time_service,
            listen_address,
            authentication_mode,
            MAX_FRAME_SIZE,
            false, /* Disable proxy protocol */
            NETWORK_CHANNEL_SIZE,
            MAX_CONCURRENT_NETWORK_REQS,
            MAX_INBOUND_CONNECTIONS,
            None,
            None,
        );

        builder.add_connectivity_manager(
            seeds,
            trusted_peers,
            MAX_FULLNODE_OUTBOUND_CONNECTIONS,
            CONNECTION_BACKOFF_BASE,
            MAX_CONNECTION_DELAY_MS,
            CONNECTIVITY_CHECK_INTERVAL_MS,
            NETWORK_CHANNEL_SIZE,
            mutual_authentication,
        );

        builder
    }

    /// Create a new NetworkBuilder based on the provided configuration.
    pub fn create(
        chain_id: ChainId,
        role: RoleType,
        config: &NetworkConfig,
        time_service: TimeService,
    ) -> NetworkBuilder {
        let peer_id = config.peer_id();
        let identity_key = config.identity_key();
        let pubkey = identity_key.public_key();

        let authentication_mode = if config.mutual_authentication {
            AuthenticationMode::Mutual(identity_key)
        } else {
            AuthenticationMode::MaybeMutual(identity_key)
        };

        let network_context = Arc::new(NetworkContext::new(
            role,
            config.network_id.clone(),
            peer_id,
        ));

        let trusted_peers = Arc::new(RwLock::new(HashMap::new()));

        let mut network_builder = NetworkBuilder::new(
            chain_id,
            trusted_peers.clone(),
            network_context,
            time_service,
            config.listen_address.clone(),
            authentication_mode,
            config.max_frame_size,
            config.enable_proxy_protocol,
            config.network_channel_size,
            config.max_concurrent_network_reqs,
            config.max_inbound_connections,
            config.inbound_rate_limit_config,
            config.outbound_rate_limit_config,
        );

        network_builder.add_connection_monitoring(
            config.ping_interval_ms,
            config.ping_timeout_ms,
            config.ping_failures_tolerated,
        );

        // Don't turn on connectivity manager if we're a public-facing server,
        // for example.
        //
        // Cases that require connectivity manager:
        //
        // 1) mutual authentication networks currently require connmgr to set the
        //    trusted peers set.
        // 2) networks with a discovery protocol need connmgr to connect to newly
        //    discovered peers.
        // 3) if we have seed peers, then we need connmgr to connect to them.
        // TODO(philiphayes): could probably use a better way to specify these cases
        // TODO:  Why not add ConnectivityManager always?
        if config.mutual_authentication
            || config.discovery_method != DiscoveryMethod::None
            || !config.seed_addrs.is_empty()
            || !config.seeds.is_empty()
        {
            let seeds = merge_seeds(config);

            network_builder.add_connectivity_manager(
                seeds,
                trusted_peers,
                config.max_outbound_connections,
                config.connection_backoff_base,
                config.max_connection_delay_ms,
                config.connectivity_check_interval_ms,
                config.network_channel_size,
                config.mutual_authentication,
            );
        }

        match &config.discovery_method {
            DiscoveryMethod::Onchain => {
                network_builder.add_validator_set_listener(pubkey, config.encryptor());
            }
            DiscoveryMethod::None => {}
        }

        network_builder
    }

    /// Create the configured Networking components.
    pub fn build(&mut self, executor: Handle) -> &mut Self {
        assert_eq!(self.state, State::CREATED);
        self.state = State::BUILT;
        self.executor = Some(executor);
        self.peer_manager_builder
            .build(self.executor.as_mut().expect("Executor must exist"));
        self
    }

    /// Start the built Networking components.
    pub fn start(&mut self) -> &mut Self {
        assert_eq!(self.state, State::BUILT);
        self.state = State::STARTED;

        let executor = self.executor.as_mut().expect("Executor must exist");
        self.peer_manager_builder.start(executor);
        debug!(
            NetworkSchema::new(&self.network_context),
            "{} Started peer manager", self.network_context
        );

        if let Some(conn_mgr_builder) = self.connectivity_manager_builder.as_mut() {
            conn_mgr_builder.start(executor);
            debug!(
                NetworkSchema::new(&self.network_context),
                "{} Started conn manager", self.network_context
            );
        }

        if let Some(health_checker_builder) = self.health_checker_builder.as_mut() {
            health_checker_builder.start(executor);
            debug!(
                NetworkSchema::new(&self.network_context),
                "{} Started health checker", self.network_context
            );
        }

        if let Some(validator_set_listener_builder) = self.validator_set_listener_builder.as_mut() {
            validator_set_listener_builder.start(executor);
            debug!(
                NetworkSchema::new(&self.network_context),
                "{} Started validator set listener", self.network_context
            );
        }
        self
    }

    pub fn reconfig_subscriptions(&mut self) -> &mut Vec<ReconfigSubscription> {
        &mut self.reconfig_subscriptions
    }

    pub fn network_context(&self) -> Arc<NetworkContext> {
        self.network_context.clone()
    }

    pub fn conn_mgr_reqs_tx(&self) -> Option<channel::Sender<ConnectivityRequest>> {
        self.connectivity_manager_builder
            .as_ref()
            .map(|conn_mgr_builder| conn_mgr_builder.conn_mgr_reqs_tx())
    }

    pub fn listen_address(&self) -> NetworkAddress {
        self.peer_manager_builder.listen_address()
    }

    /// Add a [`ConnectivityManager`] to the network.
    ///
    /// [`ConnectivityManager`] is responsible for ensuring that we are connected
    /// to a node iff. it is an eligible node and maintaining persistent
    /// connections with all eligible nodes. A list of eligible nodes is received
    /// at initialization, and updates are received on changes to system membership.
    ///
    /// Note: a connectivity manager should only be added if the network is
    /// permissioned.
    pub fn add_connectivity_manager(
        &mut self,
        seeds: PeerSet,
        trusted_peers: Arc<RwLock<PeerSet>>,
        max_outbound_connections: usize,
        connection_backoff_base: u64,
        max_connection_delay_ms: u64,
        connectivity_check_interval_ms: u64,
        channel_size: usize,
        mutual_authentication: bool,
    ) -> &mut Self {
        let pm_conn_mgr_notifs_rx = self.peer_manager_builder.add_connection_event_listener();
        let outbound_connection_limit = if !self.network_context.network_id().is_validator_network()
        {
            Some(max_outbound_connections)
        } else {
            None
        };

        self.connectivity_manager_builder = Some(ConnectivityManagerBuilder::create(
            self.network_context(),
            self.time_service.clone(),
            trusted_peers,
            seeds,
            connectivity_check_interval_ms,
            connection_backoff_base,
            max_connection_delay_ms,
            channel_size,
            ConnectionRequestSender::new(self.peer_manager_builder.connection_reqs_tx()),
            pm_conn_mgr_notifs_rx,
            outbound_connection_limit,
            mutual_authentication,
        ));
        self
    }

    fn add_validator_set_listener(&mut self, pubkey: PublicKey, encryptor: Encryptor) -> &mut Self {
        let conn_mgr_reqs_tx = self
            .conn_mgr_reqs_tx()
            .expect("ConnectivityManager must be installed for validator");
        let (simple_discovery_reconfig_subscription, simple_discovery_reconfig_rx) =
            gen_simple_discovery_reconfig_subscription();
        self.reconfig_subscriptions
            .push(simple_discovery_reconfig_subscription);

        self.validator_set_listener_builder = Some(ValidatorSetChangeListenerBuilder::create(
            self.network_context.clone(),
            pubkey,
            encryptor,
            conn_mgr_reqs_tx,
            simple_discovery_reconfig_rx,
        ));
        self
    }

    /// Add a HealthChecker to the network.
    fn add_connection_monitoring(
        &mut self,
        ping_interval_ms: u64,
        ping_timeout_ms: u64,
        ping_failures_tolerated: u64,
    ) -> &mut Self {
        // Initialize and start HealthChecker.
        let (hc_network_tx, hc_network_rx) =
            self.add_protocol_handler(health_checker::network_endpoint_config());

        self.health_checker_builder = Some(HealthCheckerBuilder::new(
            self.network_context(),
            self.time_service.clone(),
            ping_interval_ms,
            ping_timeout_ms,
            ping_failures_tolerated,
            hc_network_tx,
            hc_network_rx,
        ));
        debug!(
            NetworkSchema::new(&self.network_context),
            "{} Created health checker", self.network_context
        );
        self
    }

    /// Adds a endpoints for the provided configuration.  Returns NetworkSender and NetworkEvent which
    /// can be attached to other components.
    pub fn add_protocol_handler<SenderT, EventT>(
        &mut self,
        (rpc_protocols, direct_send_protocols, queue_preference, max_queue_size_per_peer, counter): (
            Vec<ProtocolId>,
            Vec<ProtocolId>,
            QueueStyle,
            usize,
            Option<&'static IntCounterVec>,
        ),
    ) -> (SenderT, EventT)
    where
        EventT: NewNetworkEvents,
        SenderT: NewNetworkSender,
    {
        let (peer_mgr_reqs_tx, peer_mgr_reqs_rx, connection_reqs_tx, connection_notifs_rx) =
            self.peer_manager_builder.add_protocol_handler(
                rpc_protocols,
                direct_send_protocols,
                queue_preference,
                max_queue_size_per_peer,
                counter,
            );
        (
            SenderT::new(peer_mgr_reqs_tx, connection_reqs_tx),
            EventT::new(peer_mgr_reqs_rx, connection_notifs_rx),
        )
    }
}

/// Retrieve and merge seeds so that they have all keys associated
fn merge_seeds(config: &NetworkConfig) -> PeerSet {
    config.verify_seeds().expect("Seeds must be well formed");
    let mut seeds = config.seeds.clone();

    // Merge old seed configuration with new seed configuration
    // TODO(gnazario): Once fully migrated, remove `seed_addrs`
    config
        .seed_addrs
        .iter()
        .map(|(peer_id, addrs)| {
            (
                peer_id,
                Peer::from_addrs(PeerRole::ValidatorFullNode, addrs.clone()),
            )
        })
        .for_each(|(peer_id, peer)| {
            seeds
                .entry(*peer_id)
                // Sad clone due to Rust not realizing these are two distinct paths
                .and_modify(|seed| seed.extend(peer.clone()).unwrap())
                .or_insert(peer);
        });

    // Pull public keys out of addresses
    seeds.values_mut().for_each(
        |Peer {
             addresses, keys, ..
         }| {
            addresses
                .iter()
                .filter_map(NetworkAddress::find_noise_proto)
                .for_each(|pubkey| {
                    keys.insert(pubkey);
                });
        },
    );
    seeds
}
<|endoftext|>


<commit_before>/*!
 * Poorly categorised functions for reading things used in multiple places.
 *
 * (That is, typically, more than one of request-or-response reading-or-writing.)
 *
 * TODO: refactor all this to store things in more usefully categorised places.
 */
use std::num::{Zero, cast};
use std::io::{IoError, IoResult, OtherIoError};
#[cfg(test)]
use std::io::MemReader;

// XXX: IoError ain't a good representation of this.
fn bad_input() -> IoError {
    IoError {
        kind: OtherIoError,
        desc: "invalid number",
        detail: None,
    }
}

static ASCII_ZERO: u8 = b'0';
static ASCII_NINE: u8 = b'9';
static ASCII_LOWER_A: u8 = b'a';
static ASCII_LOWER_F: u8 = b'f';
static ASCII_UPPER_A: u8 = b'A';
static ASCII_UPPER_F: u8 = b'F';

/**
 * Read a positive decimal integer from the given reader.
 *
 * # Arguments
 *
 * - `reader` - the reader to read the decimal digits from (and whatever byte comes next)
 * - `expected_end` - this function is called with the byte that follows the last decimal digit
 *   and should return `true` if that byte is what is expected to follow the number.
 *
 * # Return value
 *
 * - `None`, if the number overflows;
 * - `None`, if there is a leading zero;
 * - `None`, if all the digits are read and the `expected_end` function is false
 *
 * Should everything work as designed (i.e. none of these conditions occur) a `Some` is returned.
 */
pub fn read_decimal<R: Reader, N: Unsigned + NumCast + PartialOrd + CheckedMul + CheckedAdd>
                   (reader: &mut R, expected_end: |u8| -> bool)
                   -> IoResult<N> {
    // Here and in `read_hexadecimal` there is the possibility of infinite sequence of zeroes. The
    // spec allows this, but it may not be a good thing to allow. It's not a particularly good
    // attack surface, though, because of the low return.
    let mut n: N = Zero::zero();
    let mut got_content = false;
    let ten: N = cast(10u32).unwrap();
    loop {
        n = match reader.read_byte() {
            Ok(b@ASCII_ZERO..ASCII_NINE) => {
                // Written sanely, this is: n * 10 + (b - '0'), but we avoid
                // (semantically unsound) overflow by using checked operations.
                // There is no need in the b - '0' part as it is safe.
                match n.checked_mul(&ten).and_then(
                        |n| n.checked_add(&cast(b - ASCII_ZERO).unwrap())) {
                    Some(new_n) => new_n,
                    None => return Err(bad_input()),  // overflow
                }
            },
            Ok(b) if got_content && expected_end(b) => return Ok(n),
            Ok(_) => return Err(bad_input()),  // not a valid number
            Err(err) => return Err(err),  // I/O error
        };
        got_content = true;
    }
}

/**
 * Read a positive hexadecimal integer from the given reader.
 *
 * # Arguments
 *
 * - `reader` - the reader to read the hexadecimal digits from (and whatever byte comes next)
 * - `expected_end` - this function is called with the byte that follows the last hexadecimal digit
 *   and should return `true` if that byte is what is expected to follow the number.
 *
 * # Return value
 *
 * - `None`, if the number overflows;
 * - `None`, if there is a leading zero;
 * - `None`, if all the digits are read and the `expected_end` function is false
 *
 * Should everything work as designed (i.e. none of these conditions occur) a `Some` is returned.
 */
pub fn read_hexadecimal<R: Reader, N: Unsigned + NumCast + PartialOrd + CheckedMul + CheckedAdd>
                       (reader: &mut R, expected_end: |u8| -> bool)
                       -> IoResult<N> {
    let mut n: N = Zero::zero();
    let mut got_content = false;
    let sixteen: N = cast(16u32).unwrap();
    loop {
        n = match reader.read_byte() {
            Ok(b@ASCII_ZERO..ASCII_NINE) => {
                match n.checked_mul(&sixteen).and_then(
                        |n| n.checked_add(&cast(b - ASCII_ZERO).unwrap())) {
                    Some(new_n) => new_n,
                    None => return Err(bad_input()),  // overflow
                }
            },
            Ok(b@ASCII_LOWER_A..ASCII_LOWER_F) => {
                match n.checked_mul(&sixteen).and_then(
                        |n| n.checked_add(&cast(b - ASCII_LOWER_A + 10).unwrap())) {
                    Some(new_n) => new_n,
                    None => return Err(bad_input()),  // overflow
                }
            },
            Ok(b@ASCII_UPPER_A..ASCII_UPPER_F) => {
                match n.checked_mul(&sixteen).and_then(
                        |n| n.checked_add(&cast(b - ASCII_UPPER_A + 10).unwrap())) {
                    Some(new_n) => new_n,
                    None => return Err(bad_input()),  // overflow
                }
            },
            Ok(b) if got_content && expected_end(b) => return Ok(n),
            Ok(_) => return Err(bad_input()),  // not a valid number
            Err(err) => return Err(err),  // I/O error
        };
        got_content = true;
    }
}

/**
 * Read an HTTP-Version (e.g. "HTTP/1.1") from a stream.
 *
 * # Arguments
 *
 * - `reader` - the reader to read the HTTP-Version from (and whatever byte comes next)
 * - `expected_end` - this function is called with the byte that follows the HTTP-Version
 *   and should return `true` if that byte is what is expected to follow the HTTP-Version.
 *
 * # Return value
 *
 * - `None`, if the HTTP-Version is malformed in any way;
 * - `None`, if the `expected_end` function returns false;
 * - A `Some`, if all goes well.
 */
#[inline]
pub fn read_http_version<R: Reader>
                        (reader: &mut R, expected_end: |u8| -> bool)
                        -> IoResult<(uint, uint)> {
    // I'd read into a [0u8, ..5], but that buffer is not guaranteed to be
    // filled, so I must read it byte by byte to guarantee correctness.
    // (Sure, no sane person/library would send the first packet with "HTT"
    // and leave the "P/1.1" to the next packet, but it's *possible*.)
    let b0 = try!(reader.read_byte());
    let b1 = try!(reader.read_byte());
    let b2 = try!(reader.read_byte());
    let b3 = try!(reader.read_byte());
    let b4 = try!(reader.read_byte());
    if (b0 != b'h' && b0 != b'H') ||
       (b1 != b't' && b1 != b'T') ||
       (b2 != b't' && b2 != b'T') ||
       (b3 != b'p' && b3 != b'P') ||
       b4 != b'/' {
        return Err(bad_input());
    }

    let major = try!(read_decimal(reader, |b| b == b'.'));
    let minor = try!(read_decimal(reader, expected_end));
    Ok((major, minor))
}

// I couldn't think what to call it. Ah well. It's just trivial syntax sugar, anyway.
macro_rules! test_reads {
    ($func:ident $($value:expr => $expected:expr),*) => {{
        $(
            assert_eq!(
                concat_idents!(read_, $func)(&mut MemReader::new($value.bytes().collect::<Vec<_>>()),
                                             |b| b == 0).ok(),
                $expected);
        )*
    }}
}

#[test]
fn test_read_http_version() {
    test_reads!(http_version
                "HTTP/25.17\0" => Some((25, 17)),
                "http/1.0\0" => Some((1, 0)),
                "http 1.0\0" => None,
                "HTTP/1.0.\0" => None,
                "HTTP/1.0.\0" => None
    );
}

#[test]
fn test_read_decimal() {
    test_reads!(decimal
                "0\0" => Some(0u),
                "0\0" => Some(0u8),
                "0\0" => Some(0u64),
                "9\0" => Some(9u8),
                "42\0" => Some(42u64),
                "0123456789\0" => Some(123456789u64),
                "00000000000000000000000031\0" => Some(31u64),

                // End of stream in middle of number
                "0" => None::<u64>,

                // No number
                "\0" => None::<u64>,

                // Invalid character
                "0a\0" => None::<u64>,

                // At overflow bounds
                "255\0" => Some(255u8),
                "256\0" => None::<u8>,
                "256\0" => Some(256u16)
    );
}

#[test]
fn test_read_hexadecimal() {
    test_reads!(hexadecimal
                "0\0" => Some(0u),
                "0\0" => Some(0u8),
                "0\0" => Some(0u64),
                "f\0" => Some(0xfu8),
                "42\0" => Some(0x42u64),
                "012345\0" => Some(0x12345u64),
                "00000000000000000000000031\0" => Some(0x31u64),
                "0123456789AbCdEf\0" => Some(0x123456789abcdefu64),

                // End of stream in middle of number
                "0" => None::<u64>,

                // No number
                "\0" => None::<u64>,

                // Invalid character
                "fg\0" => None::<u64>,

                // At overflow bounds
                "ff\0" => Some(0xffu8),
                "100\0" => None::<u8>,
                "100\0" => Some(0x100u16)
    );
}
<commit_msg>Change ranges from A..B to A...B<commit_after>/*!
 * Poorly categorised functions for reading things used in multiple places.
 *
 * (That is, typically, more than one of request-or-response reading-or-writing.)
 *
 * TODO: refactor all this to store things in more usefully categorised places.
 */
use std::num::{Zero, cast};
use std::io::{IoError, IoResult, OtherIoError};
#[cfg(test)]
use std::io::MemReader;

// XXX: IoError ain't a good representation of this.
fn bad_input() -> IoError {
    IoError {
        kind: OtherIoError,
        desc: "invalid number",
        detail: None,
    }
}

static ASCII_ZERO: u8 = b'0';
static ASCII_NINE: u8 = b'9';
static ASCII_LOWER_A: u8 = b'a';
static ASCII_LOWER_F: u8 = b'f';
static ASCII_UPPER_A: u8 = b'A';
static ASCII_UPPER_F: u8 = b'F';

/**
 * Read a positive decimal integer from the given reader.
 *
 * # Arguments
 *
 * - `reader` - the reader to read the decimal digits from (and whatever byte comes next)
 * - `expected_end` - this function is called with the byte that follows the last decimal digit
 *   and should return `true` if that byte is what is expected to follow the number.
 *
 * # Return value
 *
 * - `None`, if the number overflows;
 * - `None`, if there is a leading zero;
 * - `None`, if all the digits are read and the `expected_end` function is false
 *
 * Should everything work as designed (i.e. none of these conditions occur) a `Some` is returned.
 */
pub fn read_decimal<R: Reader, N: Unsigned + NumCast + PartialOrd + CheckedMul + CheckedAdd>
                   (reader: &mut R, expected_end: |u8| -> bool)
                   -> IoResult<N> {
    // Here and in `read_hexadecimal` there is the possibility of infinite sequence of zeroes. The
    // spec allows this, but it may not be a good thing to allow. It's not a particularly good
    // attack surface, though, because of the low return.
    let mut n: N = Zero::zero();
    let mut got_content = false;
    let ten: N = cast(10u32).unwrap();
    loop {
        n = match reader.read_byte() {
            Ok(b@ASCII_ZERO...ASCII_NINE) => {
                // Written sanely, this is: n * 10 + (b - '0'), but we avoid
                // (semantically unsound) overflow by using checked operations.
                // There is no need in the b - '0' part as it is safe.
                match n.checked_mul(&ten).and_then(
                        |n| n.checked_add(&cast(b - ASCII_ZERO).unwrap())) {
                    Some(new_n) => new_n,
                    None => return Err(bad_input()),  // overflow
                }
            },
            Ok(b) if got_content && expected_end(b) => return Ok(n),
            Ok(_) => return Err(bad_input()),  // not a valid number
            Err(err) => return Err(err),  // I/O error
        };
        got_content = true;
    }
}

/**
 * Read a positive hexadecimal integer from the given reader.
 *
 * # Arguments
 *
 * - `reader` - the reader to read the hexadecimal digits from (and whatever byte comes next)
 * - `expected_end` - this function is called with the byte that follows the last hexadecimal digit
 *   and should return `true` if that byte is what is expected to follow the number.
 *
 * # Return value
 *
 * - `None`, if the number overflows;
 * - `None`, if there is a leading zero;
 * - `None`, if all the digits are read and the `expected_end` function is false
 *
 * Should everything work as designed (i.e. none of these conditions occur) a `Some` is returned.
 */
pub fn read_hexadecimal<R: Reader, N: Unsigned + NumCast + PartialOrd + CheckedMul + CheckedAdd>
                       (reader: &mut R, expected_end: |u8| -> bool)
                       -> IoResult<N> {
    let mut n: N = Zero::zero();
    let mut got_content = false;
    let sixteen: N = cast(16u32).unwrap();
    loop {
        n = match reader.read_byte() {
            Ok(b@ASCII_ZERO...ASCII_NINE) => {
                match n.checked_mul(&sixteen).and_then(
                        |n| n.checked_add(&cast(b - ASCII_ZERO).unwrap())) {
                    Some(new_n) => new_n,
                    None => return Err(bad_input()),  // overflow
                }
            },
            Ok(b@ASCII_LOWER_A...ASCII_LOWER_F) => {
                match n.checked_mul(&sixteen).and_then(
                        |n| n.checked_add(&cast(b - ASCII_LOWER_A + 10).unwrap())) {
                    Some(new_n) => new_n,
                    None => return Err(bad_input()),  // overflow
                }
            },
            Ok(b@ASCII_UPPER_A...ASCII_UPPER_F) => {
                match n.checked_mul(&sixteen).and_then(
                        |n| n.checked_add(&cast(b - ASCII_UPPER_A + 10).unwrap())) {
                    Some(new_n) => new_n,
                    None => return Err(bad_input()),  // overflow
                }
            },
            Ok(b) if got_content && expected_end(b) => return Ok(n),
            Ok(_) => return Err(bad_input()),  // not a valid number
            Err(err) => return Err(err),  // I/O error
        };
        got_content = true;
    }
}

/**
 * Read an HTTP-Version (e.g. "HTTP/1.1") from a stream.
 *
 * # Arguments
 *
 * - `reader` - the reader to read the HTTP-Version from (and whatever byte comes next)
 * - `expected_end` - this function is called with the byte that follows the HTTP-Version
 *   and should return `true` if that byte is what is expected to follow the HTTP-Version.
 *
 * # Return value
 *
 * - `None`, if the HTTP-Version is malformed in any way;
 * - `None`, if the `expected_end` function returns false;
 * - A `Some`, if all goes well.
 */
#[inline]
pub fn read_http_version<R: Reader>
                        (reader: &mut R, expected_end: |u8| -> bool)
                        -> IoResult<(uint, uint)> {
    // I'd read into a [0u8, ..5], but that buffer is not guaranteed to be
    // filled, so I must read it byte by byte to guarantee correctness.
    // (Sure, no sane person/library would send the first packet with "HTT"
    // and leave the "P/1.1" to the next packet, but it's *possible*.)
    let b0 = try!(reader.read_byte());
    let b1 = try!(reader.read_byte());
    let b2 = try!(reader.read_byte());
    let b3 = try!(reader.read_byte());
    let b4 = try!(reader.read_byte());
    if (b0 != b'h' && b0 != b'H') ||
       (b1 != b't' && b1 != b'T') ||
       (b2 != b't' && b2 != b'T') ||
       (b3 != b'p' && b3 != b'P') ||
       b4 != b'/' {
        return Err(bad_input());
    }

    let major = try!(read_decimal(reader, |b| b == b'.'));
    let minor = try!(read_decimal(reader, expected_end));
    Ok((major, minor))
}

// I couldn't think what to call it. Ah well. It's just trivial syntax sugar, anyway.
macro_rules! test_reads {
    ($func:ident $($value:expr => $expected:expr),*) => {{
        $(
            assert_eq!(
                concat_idents!(read_, $func)(&mut MemReader::new($value.bytes().collect::<Vec<_>>()),
                                             |b| b == 0).ok(),
                $expected);
        )*
    }}
}

#[test]
fn test_read_http_version() {
    test_reads!(http_version
                "HTTP/25.17\0" => Some((25, 17)),
                "http/1.0\0" => Some((1, 0)),
                "http 1.0\0" => None,
                "HTTP/1.0.\0" => None,
                "HTTP/1.0.\0" => None
    );
}

#[test]
fn test_read_decimal() {
    test_reads!(decimal
                "0\0" => Some(0u),
                "0\0" => Some(0u8),
                "0\0" => Some(0u64),
                "9\0" => Some(9u8),
                "42\0" => Some(42u64),
                "0123456789\0" => Some(123456789u64),
                "00000000000000000000000031\0" => Some(31u64),

                // End of stream in middle of number
                "0" => None::<u64>,

                // No number
                "\0" => None::<u64>,

                // Invalid character
                "0a\0" => None::<u64>,

                // At overflow bounds
                "255\0" => Some(255u8),
                "256\0" => None::<u8>,
                "256\0" => Some(256u16)
    );
}

#[test]
fn test_read_hexadecimal() {
    test_reads!(hexadecimal
                "0\0" => Some(0u),
                "0\0" => Some(0u8),
                "0\0" => Some(0u64),
                "f\0" => Some(0xfu8),
                "42\0" => Some(0x42u64),
                "012345\0" => Some(0x12345u64),
                "00000000000000000000000031\0" => Some(0x31u64),
                "0123456789AbCdEf\0" => Some(0x123456789abcdefu64),

                // End of stream in middle of number
                "0" => None::<u64>,

                // No number
                "\0" => None::<u64>,

                // Invalid character
                "fg\0" => None::<u64>,

                // At overflow bounds
                "ff\0" => Some(0xffu8),
                "100\0" => None::<u8>,
                "100\0" => Some(0x100u16)
    );
}
<|endoftext|>


<commit_before>use std::fmt::Display;
use thiserror::Error;

// Some of the elaborate cases from the rcc codebase, which is a C compiler in
// Rust. https://github.com/jyn514/rcc/blob/0.8.0/src/data/error.rs
#[derive(Error, Debug)]
pub enum CompilerError {
    #[error("cannot shift {} by {maximum} or more bits (got {current})", if *.is_left { "left" } else { "right" })]
    TooManyShiftBits {
        is_left: bool,
        maximum: u64,
        current: u64,
    },

    #[error("#error {}", (.0).iter().copied().collect::<Vec<_>>().join(" "))]
    User(Vec<&'static str>),

    #[error("overflow while parsing {}integer literal",
        if let Some(signed) = .is_signed {
            if *signed { "signed "} else { "unsigned "}
        } else {
            ""
        }
    )]
    IntegerOverflow { is_signed: Option<bool> },

    #[error("overflow while parsing {}integer literal", match .is_signed {
        Some(true) => "signed ",
        Some(false) => "unsigned ",
        None => "",
    })]
    IntegerOverflow2 { is_signed: Option<bool> },
}

// Examples drawn from Rustup.
#[derive(Error, Debug)]
pub enum RustupError {
    #[error(
        "toolchain '{name}' does not contain component {component}{}",
        .suggestion
            .as_ref()
            .map(|s| format!("; did you mean '{}'?", s))
            .unwrap_or_else(String::new),
    )]
    UnknownComponent {
        name: String,
        component: String,
        suggestion: Option<String>,
    },
}

fn assert<T: Display>(expected: &str, value: T) {
    assert_eq!(expected, value.to_string());
}

#[test]
fn test_rcc() {
    assert(
        "cannot shift left by 32 or more bits (got 50)",
        CompilerError::TooManyShiftBits {
            is_left: true,
            maximum: 32,
            current: 50,
        },
    );

    assert("#error A B C", CompilerError::User(vec!["A", "B", "C"]));

    assert(
        "overflow while parsing signed integer literal",
        CompilerError::IntegerOverflow {
            is_signed: Some(true),
        },
    );
}

#[test]
fn test_rustup() {
    assert(
        "toolchain 'nightly' does not contain component clipy; did you mean 'clippy'?",
        RustupError::UnknownComponent {
            name: "nightly".to_owned(),
            component: "clipy".to_owned(),
            suggestion: Some("clippy".to_owned()),
        },
    );
}
<commit_msg>Resolve clippy map_unwrap_or pedantic lint in test suite<commit_after>use std::fmt::Display;
use thiserror::Error;

// Some of the elaborate cases from the rcc codebase, which is a C compiler in
// Rust. https://github.com/jyn514/rcc/blob/0.8.0/src/data/error.rs
#[derive(Error, Debug)]
pub enum CompilerError {
    #[error("cannot shift {} by {maximum} or more bits (got {current})", if *.is_left { "left" } else { "right" })]
    TooManyShiftBits {
        is_left: bool,
        maximum: u64,
        current: u64,
    },

    #[error("#error {}", (.0).iter().copied().collect::<Vec<_>>().join(" "))]
    User(Vec<&'static str>),

    #[error("overflow while parsing {}integer literal",
        if let Some(signed) = .is_signed {
            if *signed { "signed "} else { "unsigned "}
        } else {
            ""
        }
    )]
    IntegerOverflow { is_signed: Option<bool> },

    #[error("overflow while parsing {}integer literal", match .is_signed {
        Some(true) => "signed ",
        Some(false) => "unsigned ",
        None => "",
    })]
    IntegerOverflow2 { is_signed: Option<bool> },
}

// Examples drawn from Rustup.
#[derive(Error, Debug)]
pub enum RustupError {
    #[error(
        "toolchain '{name}' does not contain component {component}{}",
        .suggestion
            .as_ref()
            .map_or_else(String::new, |s| format!("; did you mean '{}'?", s)),
    )]
    UnknownComponent {
        name: String,
        component: String,
        suggestion: Option<String>,
    },
}

fn assert<T: Display>(expected: &str, value: T) {
    assert_eq!(expected, value.to_string());
}

#[test]
fn test_rcc() {
    assert(
        "cannot shift left by 32 or more bits (got 50)",
        CompilerError::TooManyShiftBits {
            is_left: true,
            maximum: 32,
            current: 50,
        },
    );

    assert("#error A B C", CompilerError::User(vec!["A", "B", "C"]));

    assert(
        "overflow while parsing signed integer literal",
        CompilerError::IntegerOverflow {
            is_signed: Some(true),
        },
    );
}

#[test]
fn test_rustup() {
    assert(
        "toolchain 'nightly' does not contain component clipy; did you mean 'clippy'?",
        RustupError::UnknownComponent {
            name: "nightly".to_owned(),
            component: "clipy".to_owned(),
            suggestion: Some("clippy".to_owned()),
        },
    );
}
<|endoftext|>


<commit_before>use std::io::prelude::*;
use std::io;

struct InfixNotation<'a> {
    text: &'a str,
    index: usize
}

impl<'a> InfixNotation<'a> {
    fn new(string: &'a str) -> InfixNotation<'a> {
        InfixNotation {
            text: string.trim().clone(),
            index: 0
        }
    }
}

impl<'a> Iterator for InfixNotation<'a> {
    type Item = &'a str;
    fn next(&mut self) -> Option<&'a str> {
        let start_pos = self.index;
        if start_pos >= self.text.len() {
            return None;
        }
        let mut end_pos = self.index;
        for block in self.text.chars().skip(start_pos) {
            end_pos += 1;
            match block {
                '+' | '-' | '*' | '/' | '(' | ')' => {
                    end_pos -= 1;
                    break;
                },
                _ => continue
            }
        }
        if end_pos - start_pos == 0 {
            self.index = end_pos + 1;
        } else {
            self.index = end_pos;
        }
        Some(unsafe {
            self.text.slice_unchecked(start_pos, self.index)
        })
    }
}

fn is_digit(block: &str) -> bool {
    block.chars().nth(0).unwrap().is_digit(10)
}

fn get_priority(operator: &str) -> Option<i8> {
    match operator {
        "(" => Some(-1),
        "*" | "/" => Some(1),
        "+" | "-" => Some(2),
        _ => None
    }
}

fn can_pop(op1: &str, stack: &Vec<&str>) -> bool {
    if stack.len() == 0 {
        return false
    }
    let p1 = get_priority(op1).unwrap();
    let last = *stack.last().unwrap();
    let p2 = get_priority(last).unwrap();
    p1 >= 0 && p2 >= 0 && p1 >= p2
}

fn in2rpn(input: &str) -> String {
    let mut result = String::new();
    let it = InfixNotation::new(input);
    let mut func: Vec<&str> = Vec::new();
    for item in it {
        if is_digit(item) {
            result.push_str(item);
            result.push(' ');
        } else {
            if item == ")" {
                while func.len() > 0 && *func.last().unwrap() != "(" {
                    result.push_str(func.pop().unwrap());
                    result.push(' ');
                }
                func.pop();
            } else {
                while can_pop(item, &func) {
                    result.push_str(func.pop().unwrap());
                    result.push(' ');
                }
                func.push(item);
            }
        }
    }
    while let Some(item) = func.pop() {
        result.push_str(item);
        result.push(' ');
    }
    result
}

fn main() {
    print!("enter expression: ");
    io::stdout().flush()
        .ok()
        .expect( "[error] Can't flush to stdout!" );
    let mut buffer = String::new();
    io::stdin().read_line(&mut buffer)
        .ok()
        .expect( "[error] Can't read line from stdin!" );
    println!("result: {}", in2rpn(&buffer));
}
<commit_msg>[upd] use format! for push_str<commit_after>use std::io::prelude::*;
use std::io;

struct InfixNotation<'a> {
    text: &'a str,
    index: usize
}

impl<'a> InfixNotation<'a> {
    fn new(string: &'a str) -> InfixNotation<'a> {
        InfixNotation {
            text: string.trim().clone(),
            index: 0
        }
    }
}

impl<'a> Iterator for InfixNotation<'a> {
    type Item = &'a str;
    fn next(&mut self) -> Option<&'a str> {
        let start_pos = self.index;
        if start_pos >= self.text.len() {
            return None;
        }
        let mut end_pos = self.index;
        for block in self.text.chars().skip(start_pos) {
            end_pos += 1;
            match block {
                '+' | '-' | '*' | '/' | '(' | ')' => {
                    end_pos -= 1;
                    break;
                },
                _ => continue
            }
        }
        if end_pos - start_pos == 0 {
            self.index = end_pos + 1;
        } else {
            self.index = end_pos;
        }
        Some(unsafe {
            self.text.slice_unchecked(start_pos, self.index)
        })
    }
}

fn is_digit(block: &str) -> bool {
    block.chars().nth(0).unwrap().is_digit(10)
}

fn get_priority(operator: &str) -> Option<i8> {
    match operator {
        "(" => Some(-1),
        "*" | "/" => Some(1),
        "+" | "-" => Some(2),
        _ => None
    }
}

fn can_pop(op1: &str, stack: &Vec<&str>) -> bool {
    if stack.len() == 0 {
        return false
    }
    let p1 = get_priority(op1).unwrap();
    let last = *stack.last().unwrap();
    let p2 = get_priority(last).unwrap();
    p1 >= 0 && p2 >= 0 && p1 >= p2
}

fn in2rpn(input: &str) -> String {
    let mut result = String::new();
    let it = InfixNotation::new(input);
    let mut func: Vec<&str> = Vec::new();
    for item in it {
        if is_digit(item) {
            result.push_str(&format!("{} ", item));
        } else {
            if item == ")" {
                while func.len() > 0 && *func.last().unwrap() != "(" {
                    result.push_str(&format!("{} ", func.pop().unwrap()));
                }
                func.pop();
            } else {
                while can_pop(item, &func) {
                    result.push_str(&format!("{} ", func.pop().unwrap()));
                }
                func.push(item);
            }
        }
    }
    while let Some(item) = func.pop() {
        result.push_str(&format!("{} ", item));
    }
    result
}

fn main() {
    print!("enter expression: ");
    io::stdout().flush()
        .ok()
        .expect( "[error] Can't flush to stdout!" );
    let mut buffer = String::new();
    io::stdin().read_line(&mut buffer)
        .ok()
        .expect( "[error] Can't read line from stdin!" );
    println!("result: {}", in2rpn(&buffer));
}
<|endoftext|>


<commit_before>#[doc = "Definitions useful for C interop"];

/*
FIXME: Add a test that uses some native code to verify these sizes,
which are not obviously correct for all potential platforms. (see Issue #1990)
*/

export c_char, c_int, c_uint, long, longlong, unsigned, ulong, ulonglong;
export intptr_t, uintptr_t;
export uint32_t;
export void::{};
export c_float, c_double;
export size_t, ssize_t;
export off_t, fd_t, pid_t;
export enum;

// PORT adapt to architecture

#[doc = "A signed integer with the same size as a C `char`."]
type c_char = i8;

#[doc = "A signed integer with the same size as a C `int`."]
type c_int = i32;

#[doc = "An unsigned integer with the same size as a C `unsigned int`."]
type c_uint = u32;

#[doc = "A signed integer with the same size as a C `long`."]
type long = int;

#[doc = "A signed integer with the same size as a C `long long`."]
type longlong = i64;

#[doc = "A signed integer with the same size as a C `unsigned int`."]
type unsigned = u32;

#[doc = "A signed integer with the same size as a C `unsigned long`."]
type ulong = uint;

#[doc = "A signed integer with the same size as a C `unsigned long long`."]
type ulonglong = u64;

#[doc = "
A signed integer with the same size as a pointer.  This is guaranteed
to always be the same type as a Rust `int`.
"]
type intptr_t = int;

#[doc = "
An unsigned integer with the same size as a pointer.  This is
guaranteed to always be the same type as a Rust `uint`.
"]
type uintptr_t = uint;
type uint32_t = u32;

#[doc = "
A type, a pointer to which can be used as C `void *`.

The void type cannot be constructed or destructured, but using
pointers to this type when interoperating with C void pointers can
help in documentation.
"]
enum void {}

#[doc = "A float value with the same size as a C `float`."]
type c_float = f32;

#[doc = "A float value with the same size as a C `double`."]
type c_double = f64;

#[doc = "An unsigned integer corresponding to the C `size_t`."]
type size_t = uint;

#[doc = "A signed integer corresponding to the C `ssize_t`."]
type ssize_t = int;

#[doc = "An unsigned integer corresponding to the C `off_t`."]
type off_t = uint;

#[doc = "A type that can be used for C file descriptors."]
type fd_t = i32;      // not actually a C type, but should be.

#[doc = "A type for representing process ID's, corresponding to C `pid_t`."]
type pid_t = i32;

#[doc = "
An unsigned integer with the same size as a C enum.  enum is
implementation-defined, but is 32-bits in practice
"]
type enum = u32;

<commit_msg>Remove ctypes -- it's no longer used.<commit_after><|endoftext|>


<commit_before>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Interfaces to the operating system provided random number
//! generators.

pub use self::imp::OsRng;

#[cfg(all(unix, not(target_os = "ios")))]
mod imp {
    extern crate libc;

    use self::OsRngInner::*;

    use io::{IoResult, File};
    use path::Path;
    use rand::Rng;
    use rand::reader::ReaderRng;
    use result::Result::{Ok, Err};
    use slice::SliceExt;
    use mem;
    use os::errno;

    #[cfg(all(target_os = "linux",
              any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm")))]
    fn getrandom(buf: &mut [u8]) -> libc::c_long {
        extern "C" {
            fn syscall(number: libc::c_long, ...) -> libc::c_long;
        }

        #[cfg(target_arch = "x86_64")]
        const NR_GETRANDOM: libc::c_long = 318;
        #[cfg(target_arch = "x86")]
        const NR_GETRANDOM: libc::c_long = 355;
        #[cfg(target_arch = "arm")]
        const NR_GETRANDOM: libc::c_long = 384;

        unsafe {
            syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), 0u)
        }
    }

    #[cfg(not(all(target_os = "linux",
                  any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm"))))]
    fn getrandom(_buf: &mut [u8]) -> libc::c_long { -1 }

    fn getrandom_fill_bytes(v: &mut [u8]) {
        let mut read = 0;
        let len = v.len();
        while read < len {
            let result = getrandom(v.slice_from_mut(read));
            if result == -1 {
                let err = errno() as libc::c_int;
                if err == libc::EINTR {
                    continue;
                } else {
                    panic!("unexpected getrandom error: {}", err);
                }
            } else {
                read += result as uint;
            }
        }
    }

    fn getrandom_next_u32() -> u32 {
        let mut buf: [u8; 4] = [0u8; 4];
        getrandom_fill_bytes(&mut buf);
        unsafe { mem::transmute::<[u8; 4], u32>(buf) }
    }

    fn getrandom_next_u64() -> u64 {
        let mut buf: [u8; 8] = [0u8; 8];
        getrandom_fill_bytes(&mut buf);
        unsafe { mem::transmute::<[u8; 8], u64>(buf) }
    }

    #[cfg(all(target_os = "linux",
              any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm")))]
    fn is_getrandom_available() -> bool {
        use sync::atomic::{AtomicBool, INIT_ATOMIC_BOOL, Relaxed};

        static GETRANDOM_CHECKED: AtomicBool = INIT_ATOMIC_BOOL;
        static GETRANDOM_AVAILABLE: AtomicBool = INIT_ATOMIC_BOOL;

        if !GETRANDOM_CHECKED.load(Relaxed) {
            let mut buf: [u8; 0] = [];
            let result = getrandom(&mut buf);
            let available = if result == -1 {
                let err = errno() as libc::c_int;
                err != libc::ENOSYS
            } else {
                true
            };
            GETRANDOM_AVAILABLE.store(available, Relaxed);
            GETRANDOM_CHECKED.store(true, Relaxed);
            available
        } else {
            GETRANDOM_AVAILABLE.load(Relaxed)
        }
    }

    #[cfg(not(all(target_os = "linux",
                  any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm"))))]
    fn is_getrandom_available() -> bool { false }

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
    ///
    /// This does not block.
    pub struct OsRng {
        inner: OsRngInner,
    }

    enum OsRngInner {
        OsGetrandomRng,
        OsReaderRng(ReaderRng<File>),
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            if is_getrandom_available() {
                return Ok(OsRng { inner: OsGetrandomRng });
            }

            let reader = try!(File::open(&Path::new("/dev/urandom")));
            let reader_rng = ReaderRng::new(reader);

            Ok(OsRng { inner: OsReaderRng(reader_rng) })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            match self.inner {
                OsGetrandomRng => getrandom_next_u32(),
                OsReaderRng(ref mut rng) => rng.next_u32(),
            }
        }
        fn next_u64(&mut self) -> u64 {
            match self.inner {
                OsGetrandomRng => getrandom_next_u64(),
                OsReaderRng(ref mut rng) => rng.next_u64(),
            }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            match self.inner {
                OsGetrandomRng => getrandom_fill_bytes(v),
                OsReaderRng(ref mut rng) => rng.fill_bytes(v)
            }
        }
    }
}

#[cfg(target_os = "ios")]
mod imp {
    extern crate libc;

    use io::{IoResult};
    use kinds::Sync;
    use mem;
    use os;
    use rand::Rng;
    use result::Result::{Ok};
    use self::libc::{c_int, size_t};
    use slice::SliceExt;

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
    ///
    /// This does not block.
    #[allow(missing_copy_implementations)]
    pub struct OsRng {
        // dummy field to ensure that this struct cannot be constructed outside of this module
        _dummy: (),
    }

    #[repr(C)]
    struct SecRandom;

    unsafe impl Sync for *const SecRandom {}

    #[allow(non_upper_case_globals)]
    static kSecRandomDefault: *const SecRandom = 0 as *const SecRandom;

    #[link(name = "Security", kind = "framework")]
    extern "C" {
        fn SecRandomCopyBytes(rnd: *const SecRandom,
                              count: size_t, bytes: *mut u8) -> c_int;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            Ok(OsRng { _dummy: () })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0u8; 4];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0u8; 8];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                SecRandomCopyBytes(kSecRandomDefault, v.len() as size_t, v.as_mut_ptr())
            };
            if ret == -1 {
                panic!("couldn't generate random bytes: {}", os::last_os_error());
            }
        }
    }
}

#[cfg(windows)]
mod imp {
    extern crate libc;

    use io::{IoResult, IoError};
    use mem;
    use ops::Drop;
    use os;
    use rand::Rng;
    use result::Result::{Ok, Err};
    use self::libc::{DWORD, BYTE, LPCSTR, BOOL};
    use self::libc::types::os::arch::extra::{LONG_PTR};
    use slice::SliceExt;

    type HCRYPTPROV = LONG_PTR;

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
    ///
    /// This does not block.
    pub struct OsRng {
        hcryptprov: HCRYPTPROV
    }

    static PROV_RSA_FULL: DWORD = 1;
    static CRYPT_SILENT: DWORD = 64;
    static CRYPT_VERIFYCONTEXT: DWORD = 0xF0000000;

    #[allow(non_snake_case)]
    extern "system" {
        fn CryptAcquireContextA(phProv: *mut HCRYPTPROV,
                                pszContainer: LPCSTR,
                                pszProvider: LPCSTR,
                                dwProvType: DWORD,
                                dwFlags: DWORD) -> BOOL;
        fn CryptGenRandom(hProv: HCRYPTPROV,
                          dwLen: DWORD,
                          pbBuffer: *mut BYTE) -> BOOL;
        fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) -> BOOL;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            let mut hcp = 0;
            let ret = unsafe {
                CryptAcquireContextA(&mut hcp, 0 as LPCSTR, 0 as LPCSTR,
                                     PROV_RSA_FULL,
                                     CRYPT_VERIFYCONTEXT | CRYPT_SILENT)
            };

            if ret == 0 {
                Err(IoError::last_error())
            } else {
                Ok(OsRng { hcryptprov: hcp })
            }
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0u8; 4];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0u8; 8];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                CryptGenRandom(self.hcryptprov, v.len() as DWORD,
                               v.as_mut_ptr())
            };
            if ret == 0 {
                panic!("couldn't generate random bytes: {}", os::last_os_error());
            }
        }
    }

    impl Drop for OsRng {
        fn drop(&mut self) {
            let ret = unsafe {
                CryptReleaseContext(self.hcryptprov, 0)
            };
            if ret == 0 {
                panic!("couldn't release context: {}", os::last_os_error());
            }
        }
    }
}

#[cfg(test)]
mod test {
    use prelude::v1::*;

    use sync::mpsc::channel;
    use rand::Rng;
    use super::OsRng;
    use thread::Thread;

    #[test]
    fn test_os_rng() {
        let mut r = OsRng::new().unwrap();

        r.next_u32();
        r.next_u64();

        let mut v = [0u8; 1000];
        r.fill_bytes(&mut v);
    }

    #[test]
    fn test_os_rng_tasks() {

        let mut txs = vec!();
        for _ in range(0u, 20) {
            let (tx, rx) = channel();
            txs.push(tx);

            Thread::spawn(move|| {
                // wait until all the tasks are ready to go.
                rx.recv().unwrap();

                // deschedule to attempt to interleave things as much
                // as possible (XXX: is this a good test?)
                let mut r = OsRng::new().unwrap();
                Thread::yield_now();
                let mut v = [0u8; 1000];

                for _ in range(0u, 100) {
                    r.next_u32();
                    Thread::yield_now();
                    r.next_u64();
                    Thread::yield_now();
                    r.fill_bytes(&mut v);
                    Thread::yield_now();
                }
            }).detach();
        }

        // start all the tasks
        for tx in txs.iter() {
            tx.send(()).unwrap();
        }
    }
}
<commit_msg>rollup merge of #20315: alexcrichton/std-sync<commit_after>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Interfaces to the operating system provided random number
//! generators.

pub use self::imp::OsRng;

#[cfg(all(unix, not(target_os = "ios")))]
mod imp {
    extern crate libc;

    use self::OsRngInner::*;

    use io::{IoResult, File};
    use path::Path;
    use rand::Rng;
    use rand::reader::ReaderRng;
    use result::Result::{Ok, Err};
    use slice::SliceExt;
    use mem;
    use os::errno;

    #[cfg(all(target_os = "linux",
              any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm")))]
    fn getrandom(buf: &mut [u8]) -> libc::c_long {
        extern "C" {
            fn syscall(number: libc::c_long, ...) -> libc::c_long;
        }

        #[cfg(target_arch = "x86_64")]
        const NR_GETRANDOM: libc::c_long = 318;
        #[cfg(target_arch = "x86")]
        const NR_GETRANDOM: libc::c_long = 355;
        #[cfg(target_arch = "arm")]
        const NR_GETRANDOM: libc::c_long = 384;

        unsafe {
            syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), 0u)
        }
    }

    #[cfg(not(all(target_os = "linux",
                  any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm"))))]
    fn getrandom(_buf: &mut [u8]) -> libc::c_long { -1 }

    fn getrandom_fill_bytes(v: &mut [u8]) {
        let mut read = 0;
        let len = v.len();
        while read < len {
            let result = getrandom(v.slice_from_mut(read));
            if result == -1 {
                let err = errno() as libc::c_int;
                if err == libc::EINTR {
                    continue;
                } else {
                    panic!("unexpected getrandom error: {}", err);
                }
            } else {
                read += result as uint;
            }
        }
    }

    fn getrandom_next_u32() -> u32 {
        let mut buf: [u8; 4] = [0u8; 4];
        getrandom_fill_bytes(&mut buf);
        unsafe { mem::transmute::<[u8; 4], u32>(buf) }
    }

    fn getrandom_next_u64() -> u64 {
        let mut buf: [u8; 8] = [0u8; 8];
        getrandom_fill_bytes(&mut buf);
        unsafe { mem::transmute::<[u8; 8], u64>(buf) }
    }

    #[cfg(all(target_os = "linux",
              any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm")))]
    fn is_getrandom_available() -> bool {
        use sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Relaxed};

        static GETRANDOM_CHECKED: AtomicBool = ATOMIC_BOOL_INIT;
        static GETRANDOM_AVAILABLE: AtomicBool = ATOMIC_BOOL_INIT;

        if !GETRANDOM_CHECKED.load(Relaxed) {
            let mut buf: [u8; 0] = [];
            let result = getrandom(&mut buf);
            let available = if result == -1 {
                let err = errno() as libc::c_int;
                err != libc::ENOSYS
            } else {
                true
            };
            GETRANDOM_AVAILABLE.store(available, Relaxed);
            GETRANDOM_CHECKED.store(true, Relaxed);
            available
        } else {
            GETRANDOM_AVAILABLE.load(Relaxed)
        }
    }

    #[cfg(not(all(target_os = "linux",
                  any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm"))))]
    fn is_getrandom_available() -> bool { false }

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
    ///
    /// This does not block.
    pub struct OsRng {
        inner: OsRngInner,
    }

    enum OsRngInner {
        OsGetrandomRng,
        OsReaderRng(ReaderRng<File>),
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            if is_getrandom_available() {
                return Ok(OsRng { inner: OsGetrandomRng });
            }

            let reader = try!(File::open(&Path::new("/dev/urandom")));
            let reader_rng = ReaderRng::new(reader);

            Ok(OsRng { inner: OsReaderRng(reader_rng) })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            match self.inner {
                OsGetrandomRng => getrandom_next_u32(),
                OsReaderRng(ref mut rng) => rng.next_u32(),
            }
        }
        fn next_u64(&mut self) -> u64 {
            match self.inner {
                OsGetrandomRng => getrandom_next_u64(),
                OsReaderRng(ref mut rng) => rng.next_u64(),
            }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            match self.inner {
                OsGetrandomRng => getrandom_fill_bytes(v),
                OsReaderRng(ref mut rng) => rng.fill_bytes(v)
            }
        }
    }
}

#[cfg(target_os = "ios")]
mod imp {
    extern crate libc;

    use io::{IoResult};
    use kinds::Sync;
    use mem;
    use os;
    use rand::Rng;
    use result::Result::{Ok};
    use self::libc::{c_int, size_t};
    use slice::SliceExt;

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
    ///
    /// This does not block.
    #[allow(missing_copy_implementations)]
    pub struct OsRng {
        // dummy field to ensure that this struct cannot be constructed outside of this module
        _dummy: (),
    }

    #[repr(C)]
    struct SecRandom;

    unsafe impl Sync for *const SecRandom {}

    #[allow(non_upper_case_globals)]
    static kSecRandomDefault: *const SecRandom = 0 as *const SecRandom;

    #[link(name = "Security", kind = "framework")]
    extern "C" {
        fn SecRandomCopyBytes(rnd: *const SecRandom,
                              count: size_t, bytes: *mut u8) -> c_int;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            Ok(OsRng { _dummy: () })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0u8; 4];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0u8; 8];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                SecRandomCopyBytes(kSecRandomDefault, v.len() as size_t, v.as_mut_ptr())
            };
            if ret == -1 {
                panic!("couldn't generate random bytes: {}", os::last_os_error());
            }
        }
    }
}

#[cfg(windows)]
mod imp {
    extern crate libc;

    use io::{IoResult, IoError};
    use mem;
    use ops::Drop;
    use os;
    use rand::Rng;
    use result::Result::{Ok, Err};
    use self::libc::{DWORD, BYTE, LPCSTR, BOOL};
    use self::libc::types::os::arch::extra::{LONG_PTR};
    use slice::SliceExt;

    type HCRYPTPROV = LONG_PTR;

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
    ///
    /// This does not block.
    pub struct OsRng {
        hcryptprov: HCRYPTPROV
    }

    static PROV_RSA_FULL: DWORD = 1;
    static CRYPT_SILENT: DWORD = 64;
    static CRYPT_VERIFYCONTEXT: DWORD = 0xF0000000;

    #[allow(non_snake_case)]
    extern "system" {
        fn CryptAcquireContextA(phProv: *mut HCRYPTPROV,
                                pszContainer: LPCSTR,
                                pszProvider: LPCSTR,
                                dwProvType: DWORD,
                                dwFlags: DWORD) -> BOOL;
        fn CryptGenRandom(hProv: HCRYPTPROV,
                          dwLen: DWORD,
                          pbBuffer: *mut BYTE) -> BOOL;
        fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) -> BOOL;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            let mut hcp = 0;
            let ret = unsafe {
                CryptAcquireContextA(&mut hcp, 0 as LPCSTR, 0 as LPCSTR,
                                     PROV_RSA_FULL,
                                     CRYPT_VERIFYCONTEXT | CRYPT_SILENT)
            };

            if ret == 0 {
                Err(IoError::last_error())
            } else {
                Ok(OsRng { hcryptprov: hcp })
            }
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0u8; 4];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0u8; 8];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                CryptGenRandom(self.hcryptprov, v.len() as DWORD,
                               v.as_mut_ptr())
            };
            if ret == 0 {
                panic!("couldn't generate random bytes: {}", os::last_os_error());
            }
        }
    }

    impl Drop for OsRng {
        fn drop(&mut self) {
            let ret = unsafe {
                CryptReleaseContext(self.hcryptprov, 0)
            };
            if ret == 0 {
                panic!("couldn't release context: {}", os::last_os_error());
            }
        }
    }
}

#[cfg(test)]
mod test {
    use prelude::v1::*;

    use sync::mpsc::channel;
    use rand::Rng;
    use super::OsRng;
    use thread::Thread;

    #[test]
    fn test_os_rng() {
        let mut r = OsRng::new().unwrap();

        r.next_u32();
        r.next_u64();

        let mut v = [0u8; 1000];
        r.fill_bytes(&mut v);
    }

    #[test]
    fn test_os_rng_tasks() {

        let mut txs = vec!();
        for _ in range(0u, 20) {
            let (tx, rx) = channel();
            txs.push(tx);

            Thread::spawn(move|| {
                // wait until all the tasks are ready to go.
                rx.recv().unwrap();

                // deschedule to attempt to interleave things as much
                // as possible (XXX: is this a good test?)
                let mut r = OsRng::new().unwrap();
                Thread::yield_now();
                let mut v = [0u8; 1000];

                for _ in range(0u, 100) {
                    r.next_u32();
                    Thread::yield_now();
                    r.next_u64();
                    Thread::yield_now();
                    r.fill_bytes(&mut v);
                    Thread::yield_now();
                }
            }).detach();
        }

        // start all the tasks
        for tx in txs.iter() {
            tx.send(()).unwrap();
        }
    }
}
<|endoftext|>


<commit_before>use super::internal::*;
use super::*;
use iter::*;
use iter::internal::*;
use std;
use std::iter;
use std::usize;

pub struct Repeat<T> {
    element: T,
}

pub fn repeat<T: Clone>(elt: T) -> Repeat<T> {
    Repeat{element: elt}
}

impl<T: Clone> Clone for Repeat<T>{
    fn clone(&self) -> Repeat<T> {
        Repeat{ element: self.element.clone()}
    }
}

impl<T> ParallelIterator for Repeat<T>
    where T: Clone + Send
{
    type Item = T;

    fn drive_unindexed<C>(self, consumer: C) -> C::Result
       where C: UnindexedConsumer<Self::Item>
   {
       bridge(self, consumer)
   }
}

impl<T> IndexedParallelIterator for Repeat<T>
    where T: Clone + Send
{
    fn drive<C>(self, consumer: C) -> C::Result
        where C: Consumer<Self::Item>
    {
            bridge(self, consumer)
    }

    fn with_producer<CB>(self, callback: CB) -> CB :: Output
        where CB: ProducerCallback<Self::Item>
        {
            callback.callback(RepeatProducer{ repeat: self})
        }

    fn len(&mut self) -> usize { usize::MAX }
}

/// Producer

struct RepeatProducer<P> {
    repeat: Repeat<P>,
}

impl<T: Clone + Send> Producer for RepeatProducer<T> {
    type Item = T;
    type IntoIter = RepeatIter<T>;

    fn into_iter(self) -> Self::IntoIter{
        RepeatIter{repeat: self.repeat}
    }

    fn split_at(self, index: usize) -> (Self, Self) {
        (
            RepeatProducer{repeat: self.repeat.clone()},
            RepeatProducer{repeat: self.repeat.clone()}
        )
    }
}

impl<T: Clone + Send> UnindexedProducer for Repeat<T> {
    type Item = T;

    fn split(self) -> (Self, Option<Self>) {
        (Repeat{element: self.element.clone()}, Some(Repeat{element: self.element.clone()}))
    }

    fn fold_with<F>(self, folder: F) -> F where F: Folder<T> {
        folder.consume_iter(RepeatIter{repeat: Repeat{element: self.element}})
    }
}

/// Repeat Iter Create As Repeat Does Not Have ExactSizeIterator

struct RepeatIter<T> {
    repeat: Repeat<T>,
}

impl<T: Clone> Iterator for RepeatIter<T> {
    type Item = T;

    #[inline]
    fn next(&mut self) -> Option<T> { Some(self.repeat.element.clone()) }
    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) { (usize::MAX, None) }
}

impl<A: Clone> DoubleEndedIterator for RepeatIter<A> {
    #[inline]
    fn next_back(&mut self) -> Option<A> { Some(self.repeat.element.clone()) }
}

impl<T: Clone> ExactSizeIterator for RepeatIter<T> {
    fn len(&self) -> usize {
        usize::MAX
    }
}
<commit_msg>Fix Unnecessary Imports In Repeat<commit_after>use super::*;
use super::internal::*;
use std::usize;

pub struct Repeat<T> {
    element: T,
}

pub fn repeat<T: Clone>(elt: T) -> Repeat<T> {
    Repeat{element: elt}
}

impl<T: Clone> Clone for Repeat<T>{
    fn clone(&self) -> Repeat<T> {
        Repeat{ element: self.element.clone()}
    }
}

impl<T> ParallelIterator for Repeat<T>
    where T: Clone + Send
{
    type Item = T;

    fn drive_unindexed<C>(self, consumer: C) -> C::Result
       where C: UnindexedConsumer<Self::Item>
   {
       bridge(self, consumer)
   }
}

impl<T> IndexedParallelIterator for Repeat<T>
    where T: Clone + Send
{
    fn drive<C>(self, consumer: C) -> C::Result
        where C: Consumer<Self::Item>
    {
            bridge(self, consumer)
    }

    fn with_producer<CB>(self, callback: CB) -> CB :: Output
        where CB: ProducerCallback<Self::Item>
        {
            callback.callback(RepeatProducer{ repeat: self})
        }

    fn len(&mut self) -> usize { usize::MAX }
}

/// Producer

struct RepeatProducer<P> {
    repeat: Repeat<P>,
}

impl<T: Clone + Send> Producer for RepeatProducer<T> {
    type Item = T;
    type IntoIter = RepeatIter<T>;

    fn into_iter(self) -> Self::IntoIter{
        RepeatIter{repeat: self.repeat}
    }

    fn split_at(self, index: usize) -> (Self, Self) {
        (
            RepeatProducer{repeat: self.repeat.clone()},
            RepeatProducer{repeat: self.repeat.clone()}
        )
    }
}

impl<T: Clone + Send> UnindexedProducer for Repeat<T> {
    type Item = T;

    fn split(self) -> (Self, Option<Self>) {
        (Repeat{element: self.element.clone()}, Some(Repeat{element: self.element.clone()}))
    }

    fn fold_with<F>(self, folder: F) -> F where F: Folder<T> {
        folder.consume_iter(RepeatIter{repeat: Repeat{element: self.element}})
    }
}

/// Repeat Iter Create As Repeat Does Not Have ExactSizeIterator

struct RepeatIter<T> {
    repeat: Repeat<T>,
}

impl<T: Clone> Iterator for RepeatIter<T> {
    type Item = T;

    #[inline]
    fn next(&mut self) -> Option<T> { Some(self.repeat.element.clone()) }
    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) { (usize::MAX, None) }
}

impl<A: Clone> DoubleEndedIterator for RepeatIter<A> {
    #[inline]
    fn next_back(&mut self) -> Option<A> { Some(self.repeat.element.clone()) }
}

impl<T: Clone> ExactSizeIterator for RepeatIter<T> {
    fn len(&self) -> usize {
        usize::MAX
    }
}
<|endoftext|>