<commit_before>extern crate bindgen;
extern crate pkg_config;
extern crate gcc;

use std::env;
use std::ffi::OsString;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::Command;

// stolen from: https://github.com/alexcrichton/backtrace-rs/blob/master/backtrace-sys/build.rs
macro_rules! t {
    ($e:expr) => (match $e{
        Ok(e) => e,
        Err(e) => panic!("{} failed with {}", stringify!($e), e),
    })
}

const LIBMODBUS_DIR: &'static str = "libmodbus";

fn main() {
    let dst = env::var("OUT_DIR").unwrap();
    let target = env::var("TARGET").unwrap();
    let host = env::var("HOST").unwrap();

    let build_dir = Path::new(LIBMODBUS_DIR);
    let prefix    = Path::new(&dst).join("libmodbus-root");
    let include   = Path::new(&prefix).join("include")
                                      .join("modbus");

    // if `pkg-config` is present and the libmodbus headers are found
    // we use `pkg-config` to find the include_path and call bindgen with it.
    //
    if let Ok(library) = pkg_config::find_library("libmodbus") {
        if let Some(include) = library.include_paths.get(0) {
            run_bindgen(&include);
        }

        return
    }

    // pkg-config is not found. We build libmodbus from source (source are in a git submodule)
    // and run bindgen with that folder as include path set.
    //

    // If autogen.sh is not present, initalize git submodules
    if !Path::new("libmodbus/autogen.sh").exists() {
        run_command("", Command::new("git").args(&["submodule", "update", "--init"]));
    }

    let _ = fs::remove_dir_all(env::var("OUT_DIR").unwrap());
    t!(fs::create_dir_all(env::var("OUT_DIR").unwrap()));

    let cfg = gcc::Config::new();
    let compiler = cfg.get_compiler();
    let mut flags = OsString::new();
    for (i, flag) in compiler.args().iter().enumerate() {
        if i > 0 {
            flags.push(" ");
        }
        flags.push(flag);
    }

    // Generate configure, run configure, make, make install
    run_command("Generating configure",
        Command::new("autoreconf")
            .arg("--install")
            .arg("--symlink")
            .arg("--force")
            .current_dir(&build_dir));

    run_command("Configuring libmodbus",
        Command::new("./configure")
            .arg("--prefix")
            .arg(&prefix)
            .env("CC", compiler.path())
            .env("CFLAGS", flags)
            .arg("--with-pic")
            .arg("--disable-shared")
            .arg(format!("--target={}", target))
            .arg(format!("--host={}", host))
            .current_dir(&build_dir));

    run_command("Building libmodbus",
        Command::new("make")
            .arg("install")
            .current_dir(&build_dir));

    println!("cargo:rustc-link-lib=static=modbus");
    println!("cargo:rustc-link-search=native={}/libmodbus-root/lib", dst);

    run_bindgen(&include);
}

fn run_bindgen(include: &PathBuf) {
    let include_path = format!("-I{}", include.display());

    // The bindgen::Builder is the main entry point
    // to bindgen, and lets you build up options for
    // the resulting bindings.
    let bindings = bindgen::Builder::default()
        // Do not generate unstable Rust code that
        // requires a nightly rustc and enabling
        // unstable features.
        .no_unstable_rust()
        // The input header we would like to generate
        // bindings for.
        .header("wrapper.h")
        .clang_arg(include_path)
        // Finish the builder and generate the bindings.
        .generate()
        // Unwrap the Result and panic on failure.
        .expect("Unable to generate bindings");

    // Write the bindings to the $OUT_DIR/bindings.rs file.
    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
    bindings
        .write_to_file(out_path.join("bindings.rs"))
        .expect("Couldn't write bindings!");
}

// Helper which run a given command, and check it's success
fn run_command(which: &'static str, cmd: &mut Command) {
    assert!(cmd.status().expect(which).success(), which);
}
<commit_msg>Update deprecated methods<commit_after>extern crate bindgen;
extern crate pkg_config;
extern crate gcc;

use std::env;
use std::ffi::OsString;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::Command;

// stolen from: https://github.com/alexcrichton/backtrace-rs/blob/master/backtrace-sys/build.rs
macro_rules! t {
    ($e:expr) => (match $e{
        Ok(e) => e,
        Err(e) => panic!("{} failed with {}", stringify!($e), e),
    })
}

const LIBMODBUS_DIR: &'static str = "libmodbus";

fn main() {
    let dst = env::var("OUT_DIR").unwrap();
    let target = env::var("TARGET").unwrap();
    let host = env::var("HOST").unwrap();

    let build_dir = Path::new(LIBMODBUS_DIR);
    let prefix    = Path::new(&dst).join("libmodbus-root");
    let include   = Path::new(&prefix).join("include")
                                      .join("modbus");

    // if `pkg-config` is present and the libmodbus headers are found
    // we use `pkg-config` to find the include_path and call bindgen with it.
    //
    if let Ok(library) = pkg_config::probe_library("libmodbus") {
        if let Some(include) = library.include_paths.get(0) {
            run_bindgen(&include);
        }

        return
    }

    // pkg-config is not found. We build libmodbus from source (source are in a git submodule)
    // and run bindgen with that folder as include path set.
    //

    // If autogen.sh is not present, initalize git submodules
    if !Path::new("libmodbus/autogen.sh").exists() {
        run_command("", Command::new("git").args(&["submodule", "update", "--init"]));
    }

    let _ = fs::remove_dir_all(env::var("OUT_DIR").unwrap());
    t!(fs::create_dir_all(env::var("OUT_DIR").unwrap()));

    let cfg = gcc::Build::new();
    let compiler = cfg.get_compiler();
    let mut flags = OsString::new();
    for (i, flag) in compiler.args().iter().enumerate() {
        if i > 0 {
            flags.push(" ");
        }
        flags.push(flag);
    }

    // Generate configure, run configure, make, make install
    run_command("Generating configure",
        Command::new("autoreconf")
            .arg("--install")
            .arg("--symlink")
            .arg("--force")
            .current_dir(&build_dir));

    run_command("Configuring libmodbus",
        Command::new("./configure")
            .arg("--prefix")
            .arg(&prefix)
            .env("CC", compiler.path())
            .env("CFLAGS", flags)
            .arg("--with-pic")
            .arg("--disable-shared")
            .arg(format!("--target={}", target))
            .arg(format!("--host={}", host))
            .current_dir(&build_dir));

    run_command("Building libmodbus",
        Command::new("make")
            .arg("install")
            .current_dir(&build_dir));

    println!("cargo:rustc-link-lib=static=modbus");
    println!("cargo:rustc-link-search=native={}/libmodbus-root/lib", dst);

    run_bindgen(&include);
}

fn run_bindgen(include: &PathBuf) {
    let include_path = format!("-I{}", include.display());

    // The bindgen::Builder is the main entry point
    // to bindgen, and lets you build up options for
    // the resulting bindings.
    let bindings = bindgen::Builder::default()
        // Do not generate unstable Rust code that
        // requires a nightly rustc and enabling
        // unstable features.
        .no_unstable_rust()
        // The input header we would like to generate
        // bindings for.
        .header("wrapper.h")
        .clang_arg(include_path)
        // Finish the builder and generate the bindings.
        .generate()
        // Unwrap the Result and panic on failure.
        .expect("Unable to generate bindings");

    // Write the bindings to the $OUT_DIR/bindings.rs file.
    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
    bindings
        .write_to_file(out_path.join("bindings.rs"))
        .expect("Couldn't write bindings!");
}

// Helper which run a given command, and check it's success
fn run_command(which: &'static str, cmd: &mut Command) {
    assert!(cmd.status().expect(which).success(), which);
}
<|endoftext|>


<commit_before>use header::EntryHeader;
use content::EntryContent;
use store::StoreId;

/**
 * An Entry of the store
 *
 * Contains location, header and content part.
 */
#[derive(Debug, Clone)]
pub struct Entry {
    location: StoreId,
    header: EntryHeader,
    content: EntryContent,
}

<commit_msg>Add Entry getters<commit_after>use header::EntryHeader;
use content::EntryContent;
use store::StoreId;

/**
 * An Entry of the store
 *
 * Contains location, header and content part.
 */
#[derive(Debug, Clone)]
pub struct Entry {
    location: StoreId,
    header: EntryHeader,
    content: EntryContent,
}

impl Entry {

    pub fn get_location(&self) -> &StoreId {
        &self.location
    }

    pub fn get_header(&self) -> &EntryHeader {
        &self.header
    }

    pub fn get_content(&self) -> &EntryContent {
        &self.content
    }

}

<|endoftext|>


<commit_before>// Copyright 2018 The Grin Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Seeds a server with initial peers on first start and keep monitoring
//! peer counts to connect to more if neeed. Seedin strategy is
//! configurable with either no peers, a user-defined list or a preset
//! list of DNS records (the default).

use chrono::prelude::Utc;
use chrono::{Duration, MIN_DATE};
use rand::{thread_rng, Rng};
use std::net::{SocketAddr, ToSocketAddrs};
use std::sync::{mpsc, Arc};
use std::{cmp, io, str, thread, time};

use crate::core::global;
use crate::p2p;
use crate::p2p::ChainAdapter;
use crate::pool::DandelionConfig;
use crate::util::{Mutex, StopState};

// DNS Seeds with contact email associated
const MAINNET_DNS_SEEDS: &'static [&'static str] = &[
	"mainnet.seed.grin-tech.org", // igno.peverell@protonmail.com
];
const FLOONET_DNS_SEEDS: &'static [&'static str] = &[
	"floonet.seed.grin-tech.org", // igno.peverell@protonmail.com
];

pub fn connect_and_monitor(
	p2p_server: Arc<p2p::Server>,
	capabilities: p2p::Capabilities,
	dandelion_config: DandelionConfig,
	seed_list: Box<dyn Fn() -> Vec<SocketAddr> + Send>,
	preferred_peers: Option<Vec<SocketAddr>>,
	stop_state: Arc<Mutex<StopState>>,
) {
	let _ = thread::Builder::new()
		.name("seed".to_string())
		.spawn(move || {
			let peers = p2p_server.peers.clone();

			// open a channel with a listener that connects every peer address sent below
			// max peer count
			let (tx, rx) = mpsc::channel();

			// check seeds first
			connect_to_seeds_and_preferred_peers(
				peers.clone(),
				tx.clone(),
				seed_list,
				preferred_peers.clone(),
			);

			let mut prev = MIN_DATE.and_hms(0, 0, 0);
			let mut prev_expire_check = MIN_DATE.and_hms(0, 0, 0);
			let mut prev_ping = Utc::now();
			let mut start_attempt = 0;

			loop {
				if stop_state.lock().is_stopped() {
					break;
				}

				// Pause egress peer connection request. Only for tests.
				if stop_state.lock().is_paused() {
					thread::sleep(time::Duration::from_secs(1));
					continue;
				}

				// Check for and remove expired peers from the storage
				if Utc::now() - prev_expire_check > Duration::hours(1) {
					peers.remove_expired();

					prev_expire_check = Utc::now();
				}

				// make several attempts to get peers as quick as possible
				// with exponential backoff
				if Utc::now() - prev > Duration::seconds(cmp::min(20, 1 << start_attempt)) {
					// try to connect to any address sent to the channel
					listen_for_addrs(peers.clone(), p2p_server.clone(), capabilities, &rx);

					// monitor additional peers if we need to add more
					monitor_peers(
						peers.clone(),
						p2p_server.config.clone(),
						tx.clone(),
						preferred_peers.clone(),
					);

					update_dandelion_relay(peers.clone(), dandelion_config.clone());

					prev = Utc::now();
					start_attempt = cmp::min(6, start_attempt + 1);
				}

				// Ping connected peers on every 10s to monitor peers.
				if Utc::now() - prev_ping > Duration::seconds(10) {
					let total_diff = peers.total_difficulty();
					let total_height = peers.total_height();
					peers.check_all(total_diff, total_height);
					prev_ping = Utc::now();
				}

				thread::sleep(time::Duration::from_secs(1));
			}
		});
}

fn monitor_peers(
	peers: Arc<p2p::Peers>,
	config: p2p::P2PConfig,
	tx: mpsc::Sender<SocketAddr>,
	preferred_peers_list: Option<Vec<SocketAddr>>,
) {
	// regularly check if we need to acquire more peers  and if so, gets
	// them from db
	let total_count = peers.all_peers().len();
	let mut healthy_count = 0;
	let mut banned_count = 0;
	let mut defuncts = vec![];

	for x in peers.all_peers() {
		match x.flags {
			p2p::State::Banned => {
				let interval = Utc::now().timestamp() - x.last_banned;
				// Unban peer
				if interval >= config.ban_window() {
					peers.unban_peer(&x.addr);
					debug!(
						"monitor_peers: unbanned {} after {} seconds",
						x.addr, interval
					);
				} else {
					banned_count += 1;
				}
			}
			p2p::State::Healthy => healthy_count += 1,
			p2p::State::Defunct => defuncts.push(x),
		}
	}

	debug!(
		"monitor_peers: on {}:{}, {} connected ({} most_work). \
		 all {} = {} healthy + {} banned + {} defunct",
		config.host,
		config.port,
		peers.peer_count(),
		peers.most_work_peers().len(),
		total_count,
		healthy_count,
		banned_count,
		defuncts.len(),
	);

	// maintenance step first, clean up p2p server peers
	peers.clean_peers(config.peer_max_count() as usize);

	// not enough peers, getting more from db
	if peers.peer_count() >= config.peer_min_preferred_count() {
		return;
	}

	// loop over connected peers
	// ask them for their list of peers
	let mut connected_peers: Vec<SocketAddr> = vec![];
	for p in peers.connected_peers() {
		trace!(
			"monitor_peers: {}:{} ask {} for more peers",
			config.host,
			config.port,
			p.info.addr,
		);
		let _ = p.send_peer_request(p2p::Capabilities::PEER_LIST);
		connected_peers.push(p.info.addr)
	}

	// Attempt to connect to preferred peers if there is some
	match preferred_peers_list {
		Some(preferred_peers) => {
			for p in preferred_peers {
				if !connected_peers.is_empty() {
					if !connected_peers.contains(&p) {
						tx.send(p).unwrap();
					}
				} else {
					tx.send(p).unwrap();
				}
			}
		}
		None => debug!("monitor_peers: no preferred peers"),
	}

	// take a random defunct peer and mark it healthy: over a long period any
	// peer will see another as defunct eventually, gives us a chance to retry
	if defuncts.len() > 0 {
		thread_rng().shuffle(&mut defuncts);
		let _ = peers.update_state(defuncts[0].addr, p2p::State::Healthy);
	}

	// find some peers from our db
	// and queue them up for a connection attempt
	let new_peers = peers.find_peers(
		p2p::State::Healthy,
		p2p::Capabilities::UNKNOWN,
		config.peer_max_count() as usize,
	);

	for p in new_peers.iter().filter(|p| !peers.is_known(&p.addr)) {
		trace!(
			"monitor_peers: on {}:{}, queue to soon try {}",
			config.host,
			config.port,
			p.addr,
		);
		tx.send(p.addr).unwrap();
	}
}

fn update_dandelion_relay(peers: Arc<p2p::Peers>, dandelion_config: DandelionConfig) {
	// Dandelion Relay Updater
	let dandelion_relay = peers.get_dandelion_relay();
	if dandelion_relay.is_empty() {
		debug!("monitor_peers: no dandelion relay updating");
		peers.update_dandelion_relay();
	} else {
		for last_added in dandelion_relay.keys() {
			let dandelion_interval = Utc::now().timestamp() - last_added;
			if dandelion_interval >= dandelion_config.relay_secs.unwrap() as i64 {
				debug!("monitor_peers: updating expired dandelion relay");
				peers.update_dandelion_relay();
			}
		}
	}
}

// Check if we have any pre-existing peer in db. If so, start with those,
// otherwise use the seeds provided.
fn connect_to_seeds_and_preferred_peers(
	peers: Arc<p2p::Peers>,
	tx: mpsc::Sender<SocketAddr>,
	seed_list: Box<dyn Fn() -> Vec<SocketAddr>>,
	peers_preferred_list: Option<Vec<SocketAddr>>,
) {
	// check if we have some peers in db
	// look for peers that are able to give us other peers (via PEER_LIST capability)
	let peers = peers.find_peers(p2p::State::Healthy, p2p::Capabilities::PEER_LIST, 100);

	// if so, get their addresses, otherwise use our seeds
	let mut peer_addrs = if peers.len() > 3 {
		peers.iter().map(|p| p.addr).collect::<Vec<_>>()
	} else {
		seed_list()
	};

	// If we have preferred peers add them to the connection
	match peers_preferred_list {
		Some(mut peers_preferred) => peer_addrs.append(&mut peers_preferred),
		None => trace!("No preferred peers"),
	};

	if peer_addrs.len() == 0 {
		warn!("No seeds were retrieved.");
	}

	// connect to this first set of addresses
	for addr in peer_addrs {
		tx.send(addr).unwrap();
	}
}

/// Regularly poll a channel receiver for new addresses and initiate a
/// connection if the max peer count isn't exceeded. A request for more
/// peers is also automatically sent after connection.
fn listen_for_addrs(
	peers: Arc<p2p::Peers>,
	p2p: Arc<p2p::Server>,
	capab: p2p::Capabilities,
	rx: &mpsc::Receiver<SocketAddr>,
) {
	if peers.peer_count() >= p2p.config.peer_max_count() {
		// clean the rx messages to avoid accumulating
		for _ in rx.try_iter() {}
		return;
	}

	for addr in rx.try_iter() {
		let peers_c = peers.clone();
		let p2p_c = p2p.clone();
		let _ = thread::Builder::new()
			.name("peer_connect".to_string())
			.spawn(move || {
				// connect and retry on fail, but for 3 times at most
				for _ in 0..3 {
					match p2p_c.connect(&addr) {
						Ok(p) => {
							let _ = p.send_peer_request(capab);
							let _ = peers_c.update_state(addr, p2p::State::Healthy);
							break;
						}
						Err(e) => {
							let _ = peers_c.update_state(addr, p2p::State::Defunct);

							// don't retry if connection refused or PeerWithSelf
							match e {
								p2p::Error::Connection(io_err) => {
									if io::ErrorKind::ConnectionRefused == io_err.kind() {
										break;
									}
								}
								p2p::Error::PeerWithSelf => break,
								_ => (), // allow to retry on any other error
							}
						}
					}

					thread::sleep(time::Duration::from_secs(1));
				}
			});
	}
}

pub fn dns_seeds() -> Box<dyn Fn() -> Vec<SocketAddr> + Send> {
	Box::new(|| {
		let mut addresses: Vec<SocketAddr> = vec![];
		let net_seeds = if global::is_floonet() {
			FLOONET_DNS_SEEDS
		} else {
			MAINNET_DNS_SEEDS
		};
		for dns_seed in net_seeds {
			let temp_addresses = addresses.clone();
			debug!("Retrieving seed nodes from dns {}", dns_seed);
			match (dns_seed.to_owned(), 0).to_socket_addrs() {
				Ok(addrs) => addresses.append(
					&mut (addrs
						.map(|mut addr| {
							addr.set_port(13414);
							addr
						})
						.filter(|addr| !temp_addresses.contains(addr))
						.collect()),
				),
				Err(e) => debug!("Failed to resolve seed {:?} got error {:?}", dns_seed, e),
			}
		}
		debug!("Retrieved seed addresses: {:?}", addresses);
		addresses
	})
}

/// Convenience function when the seed list is immediately known. Mostly used
/// for tests.
pub fn predefined_seeds(addrs_str: Vec<String>) -> Box<dyn Fn() -> Vec<SocketAddr> + Send> {
	Box::new(move || {
		addrs_str
			.iter()
			.map(|s| s.parse().unwrap())
			.collect::<Vec<_>>()
	})
}

/// Convenience function when the seed list is immediately known. Mostly used
/// for tests.
pub fn preferred_peers(addrs_str: Vec<String>) -> Option<Vec<SocketAddr>> {
	if addrs_str.is_empty() {
		None
	} else {
		Some(
			addrs_str
				.iter()
				.map(|s| s.parse().unwrap())
				.collect::<Vec<_>>(),
		)
	}
}
<commit_msg>Add one more dns seed (#2250)<commit_after>// Copyright 2018 The Grin Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Seeds a server with initial peers on first start and keep monitoring
//! peer counts to connect to more if neeed. Seedin strategy is
//! configurable with either no peers, a user-defined list or a preset
//! list of DNS records (the default).

use chrono::prelude::Utc;
use chrono::{Duration, MIN_DATE};
use rand::{thread_rng, Rng};
use std::net::{SocketAddr, ToSocketAddrs};
use std::sync::{mpsc, Arc};
use std::{cmp, io, str, thread, time};

use crate::core::global;
use crate::p2p;
use crate::p2p::ChainAdapter;
use crate::pool::DandelionConfig;
use crate::util::{Mutex, StopState};

// DNS Seeds with contact email associated
const MAINNET_DNS_SEEDS: &'static [&'static str] = &[
	"mainnet.seed.grin-tech.org", // igno.peverell@protonmail.com
	"mainnet.seed.grin.icu",      // gary.peverell@protonmail.com
];
const FLOONET_DNS_SEEDS: &'static [&'static str] = &[
	"floonet.seed.grin-tech.org", // igno.peverell@protonmail.com
	"floonet.seed.grin.icu",      // gary.peverell@protonmail.com
];

pub fn connect_and_monitor(
	p2p_server: Arc<p2p::Server>,
	capabilities: p2p::Capabilities,
	dandelion_config: DandelionConfig,
	seed_list: Box<dyn Fn() -> Vec<SocketAddr> + Send>,
	preferred_peers: Option<Vec<SocketAddr>>,
	stop_state: Arc<Mutex<StopState>>,
) {
	let _ = thread::Builder::new()
		.name("seed".to_string())
		.spawn(move || {
			let peers = p2p_server.peers.clone();

			// open a channel with a listener that connects every peer address sent below
			// max peer count
			let (tx, rx) = mpsc::channel();

			// check seeds first
			connect_to_seeds_and_preferred_peers(
				peers.clone(),
				tx.clone(),
				seed_list,
				preferred_peers.clone(),
			);

			let mut prev = MIN_DATE.and_hms(0, 0, 0);
			let mut prev_expire_check = MIN_DATE.and_hms(0, 0, 0);
			let mut prev_ping = Utc::now();
			let mut start_attempt = 0;

			loop {
				if stop_state.lock().is_stopped() {
					break;
				}

				// Pause egress peer connection request. Only for tests.
				if stop_state.lock().is_paused() {
					thread::sleep(time::Duration::from_secs(1));
					continue;
				}

				// Check for and remove expired peers from the storage
				if Utc::now() - prev_expire_check > Duration::hours(1) {
					peers.remove_expired();

					prev_expire_check = Utc::now();
				}

				// make several attempts to get peers as quick as possible
				// with exponential backoff
				if Utc::now() - prev > Duration::seconds(cmp::min(20, 1 << start_attempt)) {
					// try to connect to any address sent to the channel
					listen_for_addrs(peers.clone(), p2p_server.clone(), capabilities, &rx);

					// monitor additional peers if we need to add more
					monitor_peers(
						peers.clone(),
						p2p_server.config.clone(),
						tx.clone(),
						preferred_peers.clone(),
					);

					update_dandelion_relay(peers.clone(), dandelion_config.clone());

					prev = Utc::now();
					start_attempt = cmp::min(6, start_attempt + 1);
				}

				// Ping connected peers on every 10s to monitor peers.
				if Utc::now() - prev_ping > Duration::seconds(10) {
					let total_diff = peers.total_difficulty();
					let total_height = peers.total_height();
					peers.check_all(total_diff, total_height);
					prev_ping = Utc::now();
				}

				thread::sleep(time::Duration::from_secs(1));
			}
		});
}

fn monitor_peers(
	peers: Arc<p2p::Peers>,
	config: p2p::P2PConfig,
	tx: mpsc::Sender<SocketAddr>,
	preferred_peers_list: Option<Vec<SocketAddr>>,
) {
	// regularly check if we need to acquire more peers  and if so, gets
	// them from db
	let total_count = peers.all_peers().len();
	let mut healthy_count = 0;
	let mut banned_count = 0;
	let mut defuncts = vec![];

	for x in peers.all_peers() {
		match x.flags {
			p2p::State::Banned => {
				let interval = Utc::now().timestamp() - x.last_banned;
				// Unban peer
				if interval >= config.ban_window() {
					peers.unban_peer(&x.addr);
					debug!(
						"monitor_peers: unbanned {} after {} seconds",
						x.addr, interval
					);
				} else {
					banned_count += 1;
				}
			}
			p2p::State::Healthy => healthy_count += 1,
			p2p::State::Defunct => defuncts.push(x),
		}
	}

	debug!(
		"monitor_peers: on {}:{}, {} connected ({} most_work). \
		 all {} = {} healthy + {} banned + {} defunct",
		config.host,
		config.port,
		peers.peer_count(),
		peers.most_work_peers().len(),
		total_count,
		healthy_count,
		banned_count,
		defuncts.len(),
	);

	// maintenance step first, clean up p2p server peers
	peers.clean_peers(config.peer_max_count() as usize);

	// not enough peers, getting more from db
	if peers.peer_count() >= config.peer_min_preferred_count() {
		return;
	}

	// loop over connected peers
	// ask them for their list of peers
	let mut connected_peers: Vec<SocketAddr> = vec![];
	for p in peers.connected_peers() {
		trace!(
			"monitor_peers: {}:{} ask {} for more peers",
			config.host,
			config.port,
			p.info.addr,
		);
		let _ = p.send_peer_request(p2p::Capabilities::PEER_LIST);
		connected_peers.push(p.info.addr)
	}

	// Attempt to connect to preferred peers if there is some
	match preferred_peers_list {
		Some(preferred_peers) => {
			for p in preferred_peers {
				if !connected_peers.is_empty() {
					if !connected_peers.contains(&p) {
						tx.send(p).unwrap();
					}
				} else {
					tx.send(p).unwrap();
				}
			}
		}
		None => debug!("monitor_peers: no preferred peers"),
	}

	// take a random defunct peer and mark it healthy: over a long period any
	// peer will see another as defunct eventually, gives us a chance to retry
	if defuncts.len() > 0 {
		thread_rng().shuffle(&mut defuncts);
		let _ = peers.update_state(defuncts[0].addr, p2p::State::Healthy);
	}

	// find some peers from our db
	// and queue them up for a connection attempt
	let new_peers = peers.find_peers(
		p2p::State::Healthy,
		p2p::Capabilities::UNKNOWN,
		config.peer_max_count() as usize,
	);

	for p in new_peers.iter().filter(|p| !peers.is_known(&p.addr)) {
		trace!(
			"monitor_peers: on {}:{}, queue to soon try {}",
			config.host,
			config.port,
			p.addr,
		);
		tx.send(p.addr).unwrap();
	}
}

fn update_dandelion_relay(peers: Arc<p2p::Peers>, dandelion_config: DandelionConfig) {
	// Dandelion Relay Updater
	let dandelion_relay = peers.get_dandelion_relay();
	if dandelion_relay.is_empty() {
		debug!("monitor_peers: no dandelion relay updating");
		peers.update_dandelion_relay();
	} else {
		for last_added in dandelion_relay.keys() {
			let dandelion_interval = Utc::now().timestamp() - last_added;
			if dandelion_interval >= dandelion_config.relay_secs.unwrap() as i64 {
				debug!("monitor_peers: updating expired dandelion relay");
				peers.update_dandelion_relay();
			}
		}
	}
}

// Check if we have any pre-existing peer in db. If so, start with those,
// otherwise use the seeds provided.
fn connect_to_seeds_and_preferred_peers(
	peers: Arc<p2p::Peers>,
	tx: mpsc::Sender<SocketAddr>,
	seed_list: Box<dyn Fn() -> Vec<SocketAddr>>,
	peers_preferred_list: Option<Vec<SocketAddr>>,
) {
	// check if we have some peers in db
	// look for peers that are able to give us other peers (via PEER_LIST capability)
	let peers = peers.find_peers(p2p::State::Healthy, p2p::Capabilities::PEER_LIST, 100);

	// if so, get their addresses, otherwise use our seeds
	let mut peer_addrs = if peers.len() > 3 {
		peers.iter().map(|p| p.addr).collect::<Vec<_>>()
	} else {
		seed_list()
	};

	// If we have preferred peers add them to the connection
	match peers_preferred_list {
		Some(mut peers_preferred) => peer_addrs.append(&mut peers_preferred),
		None => trace!("No preferred peers"),
	};

	if peer_addrs.len() == 0 {
		warn!("No seeds were retrieved.");
	}

	// connect to this first set of addresses
	for addr in peer_addrs {
		tx.send(addr).unwrap();
	}
}

/// Regularly poll a channel receiver for new addresses and initiate a
/// connection if the max peer count isn't exceeded. A request for more
/// peers is also automatically sent after connection.
fn listen_for_addrs(
	peers: Arc<p2p::Peers>,
	p2p: Arc<p2p::Server>,
	capab: p2p::Capabilities,
	rx: &mpsc::Receiver<SocketAddr>,
) {
	if peers.peer_count() >= p2p.config.peer_max_count() {
		// clean the rx messages to avoid accumulating
		for _ in rx.try_iter() {}
		return;
	}

	for addr in rx.try_iter() {
		let peers_c = peers.clone();
		let p2p_c = p2p.clone();
		let _ = thread::Builder::new()
			.name("peer_connect".to_string())
			.spawn(move || {
				// connect and retry on fail, but for 3 times at most
				for _ in 0..3 {
					match p2p_c.connect(&addr) {
						Ok(p) => {
							let _ = p.send_peer_request(capab);
							let _ = peers_c.update_state(addr, p2p::State::Healthy);
							break;
						}
						Err(e) => {
							let _ = peers_c.update_state(addr, p2p::State::Defunct);

							// don't retry if connection refused or PeerWithSelf
							match e {
								p2p::Error::Connection(io_err) => {
									if io::ErrorKind::ConnectionRefused == io_err.kind() {
										break;
									}
								}
								p2p::Error::PeerWithSelf => break,
								_ => (), // allow to retry on any other error
							}
						}
					}

					thread::sleep(time::Duration::from_secs(1));
				}
			});
	}
}

pub fn dns_seeds() -> Box<dyn Fn() -> Vec<SocketAddr> + Send> {
	Box::new(|| {
		let mut addresses: Vec<SocketAddr> = vec![];
		let net_seeds = if global::is_floonet() {
			FLOONET_DNS_SEEDS
		} else {
			MAINNET_DNS_SEEDS
		};
		for dns_seed in net_seeds {
			let temp_addresses = addresses.clone();
			debug!("Retrieving seed nodes from dns {}", dns_seed);
			match (dns_seed.to_owned(), 0).to_socket_addrs() {
				Ok(addrs) => addresses.append(
					&mut (addrs
						.map(|mut addr| {
							addr.set_port(13414);
							addr
						})
						.filter(|addr| !temp_addresses.contains(addr))
						.collect()),
				),
				Err(e) => debug!("Failed to resolve seed {:?} got error {:?}", dns_seed, e),
			}
		}
		debug!("Retrieved seed addresses: {:?}", addresses);
		addresses
	})
}

/// Convenience function when the seed list is immediately known. Mostly used
/// for tests.
pub fn predefined_seeds(addrs_str: Vec<String>) -> Box<dyn Fn() -> Vec<SocketAddr> + Send> {
	Box::new(move || {
		addrs_str
			.iter()
			.map(|s| s.parse().unwrap())
			.collect::<Vec<_>>()
	})
}

/// Convenience function when the seed list is immediately known. Mostly used
/// for tests.
pub fn preferred_peers(addrs_str: Vec<String>) -> Option<Vec<SocketAddr>> {
	if addrs_str.is_empty() {
		None
	} else {
		Some(
			addrs_str
				.iter()
				.map(|s| s.parse().unwrap())
				.collect::<Vec<_>>(),
		)
	}
}
<|endoftext|>


<commit_before>use std::sync::Arc;

use conduit::{Handler, HandlerResult, RequestExt};
use conduit_router::{RequestParams, RouteBuilder};

use crate::controllers::*;
use crate::util::errors::{std_error, AppError, NotFound};
use crate::util::EndpointResult;
use crate::{App, Env};

pub fn build_router(app: &App) -> R404 {
    let mut api_router = RouteBuilder::new();

    // Route used by both `cargo search` and the frontend
    api_router.get("/crates", C(krate::search::search));

    // Routes used by `cargo`
    api_router.put("/crates/new", C(krate::publish::publish));
    api_router.get("/crates/:crate_id/owners", C(krate::owners::owners));
    api_router.put("/crates/:crate_id/owners", C(krate::owners::add_owners));
    api_router.delete("/crates/:crate_id/owners", C(krate::owners::remove_owners));
    api_router.delete("/crates/:crate_id/:version/yank", C(version::yank::yank));
    api_router.put(
        "/crates/:crate_id/:version/unyank",
        C(version::yank::unyank),
    );
    api_router.get(
        "/crates/:crate_id/:version/download",
        C(version::downloads::download),
    );

    // Routes that appear to be unused
    api_router.get("/versions", C(version::deprecated::index));
    api_router.get("/versions/:version_id", C(version::deprecated::show_by_id));

    // Routes used by the frontend
    api_router.get("/crates/:crate_id", C(krate::metadata::show));
    api_router.get("/crates/:crate_id/:version", C(version::metadata::show));
    api_router.get(
        "/crates/:crate_id/:version/readme",
        C(krate::metadata::readme),
    );
    api_router.get(
        "/crates/:crate_id/:version/dependencies",
        C(version::metadata::dependencies),
    );
    api_router.get(
        "/crates/:crate_id/:version/downloads",
        C(version::downloads::downloads),
    );
    api_router.get(
        "/crates/:crate_id/:version/authors",
        C(version::metadata::authors),
    );
    api_router.get(
        "/crates/:crate_id/downloads",
        C(krate::downloads::downloads),
    );
    api_router.get("/crates/:crate_id/versions", C(krate::metadata::versions));
    api_router.put("/crates/:crate_id/follow", C(krate::follow::follow));
    api_router.delete("/crates/:crate_id/follow", C(krate::follow::unfollow));
    api_router.get("/crates/:crate_id/following", C(krate::follow::following));
    api_router.get("/crates/:crate_id/owner_team", C(krate::owners::owner_team));
    api_router.get("/crates/:crate_id/owner_user", C(krate::owners::owner_user));
    api_router.get(
        "/crates/:crate_id/reverse_dependencies",
        C(krate::metadata::reverse_dependencies),
    );
    api_router.get("/keywords", C(keyword::index));
    api_router.get("/keywords/:keyword_id", C(keyword::show));
    api_router.get("/categories", C(category::index));
    api_router.get("/categories/:category_id", C(category::show));
    api_router.get("/category_slugs", C(category::slugs));
    api_router.get("/users/:user_id", C(user::other::show));
    api_router.put("/users/:user_id", C(user::me::update_user));
    api_router.get("/users/:user_id/stats", C(user::other::stats));
    api_router.get("/teams/:team_id", C(team::show_team));
    api_router.get("/me", C(user::me::me));
    api_router.get("/me/updates", C(user::me::updates));
    api_router.get("/me/tokens", C(token::list));
    api_router.put("/me/tokens", C(token::new));
    api_router.delete("/me/tokens/:id", C(token::revoke));
    api_router.get(
        "/me/crate_owner_invitations",
        C(crate_owner_invitation::list),
    );
    api_router.put(
        "/me/crate_owner_invitations/:crate_id",
        C(crate_owner_invitation::handle_invite),
    );
    api_router.put(
        "/me/crate_owner_invitations/accept/:token",
        C(crate_owner_invitation::handle_invite_with_token),
    );
    api_router.put(
        "/me/email_notifications",
        C(user::me::update_email_notifications),
    );
    api_router.get("/summary", C(krate::metadata::summary));
    api_router.put("/confirm/:email_token", C(user::me::confirm_user_email));
    api_router.put(
        "/users/:user_id/resend",
        C(user::me::regenerate_token_and_send),
    );
    api_router.get("/site_metadata", C(site_metadata::show_deployed_sha));
    let api_router = Arc::new(R404(api_router));

    let mut router = RouteBuilder::new();

    // Mount the router under the /api/v1 path so we're at least somewhat at the
    // liberty to change things in the future!
    router.get("/api/v1/*path", R(Arc::clone(&api_router)));
    router.put("/api/v1/*path", R(Arc::clone(&api_router)));
    router.post("/api/v1/*path", R(Arc::clone(&api_router)));
    router.head("/api/v1/*path", R(Arc::clone(&api_router)));
    router.delete("/api/v1/*path", R(api_router));

    // Session management
    router.get("/api/private/session/begin", C(user::session::begin));
    router.get(
        "/api/private/session/authorize",
        C(user::session::authorize),
    );
    router.delete("/api/private/session", C(user::session::logout));

    // Only serve the local checkout of the git index in development mode.
    // In production, for crates.io, cargo gets the index from
    // https://github.com/rust-lang/crates.io-index directly.
    if app.config.env == Env::Development {
        let s = conduit_git_http_backend::Serve("./tmp/index-bare".into());
        let s = Arc::new(s);
        router.get("/git/index/*path", R(Arc::clone(&s)));
        router.post("/git/index/*path", R(s));
    }

    R404(router)
}

struct C(pub fn(&mut dyn RequestExt) -> EndpointResult);

impl Handler for C {
    fn call(&self, req: &mut dyn RequestExt) -> HandlerResult {
        let C(f) = *self;
        match f(req) {
            Ok(resp) => Ok(resp),
            Err(e) => {
                if let Some(cause) = e.cause() {
                    req.log_metadata("cause", cause.to_string())
                };
                match e.response() {
                    Some(response) => Ok(response),
                    None => Err(std_error(e)),
                }
            }
        }
    }
}

struct R<H>(pub Arc<H>);

impl<H: Handler> Handler for R<H> {
    fn call(&self, req: &mut dyn RequestExt) -> HandlerResult {
        *req.path_mut() = req.params()["path"].to_string();
        let R(ref sub_router) = *self;
        sub_router.call(req)
    }
}

// Can't derive Debug because of RouteBuilder.
#[allow(missing_debug_implementations)]
pub struct R404(pub RouteBuilder);

impl Handler for R404 {
    fn call(&self, req: &mut dyn RequestExt) -> HandlerResult {
        let R404(ref router) = *self;
        match router.recognize(&req.method(), req.path()) {
            Ok(m) => {
                req.mut_extensions().insert(m.params().clone());
                m.handler().call(req)
            }
            Err(..) => Ok(NotFound.into()),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::util::errors::{
        bad_request, cargo_err, forbidden, internal, not_found, AppError, ChainError,
    };
    use crate::util::EndpointResult;

    use conduit::{Body, StatusCode};
    use conduit_test::MockRequest;
    use diesel::result::Error as DieselError;

    fn err<E: AppError>(err: E) -> EndpointResult {
        Err(Box::new(err))
    }

    #[test]
    fn http_error_responses() {
        let mut req = MockRequest::new(::conduit::Method::GET, "/");

        // Types for handling common error status codes
        assert_eq!(
            C(|_| Err(bad_request(""))).call(&mut req).unwrap().status(),
            StatusCode::BAD_REQUEST
        );
        assert_eq!(
            C(|_| Err(forbidden())).call(&mut req).unwrap().status(),
            StatusCode::FORBIDDEN
        );
        assert_eq!(
            C(|_| Err(DieselError::NotFound.into()))
                .call(&mut req)
                .unwrap()
                .status(),
            StatusCode::NOT_FOUND
        );
        assert_eq!(
            C(|_| Err(not_found())).call(&mut req).unwrap().status(),
            StatusCode::NOT_FOUND
        );

        // cargo_err errors are returned as 200 so that cargo displays this nicely on the command line
        assert_eq!(
            C(|_| Err(cargo_err(""))).call(&mut req).unwrap().status(),
            StatusCode::OK
        );

        // Inner errors are captured for logging when wrapped by a user facing error
        let response = C(|_| {
            Err("-1"
                .parse::<u8>()
                .chain_error(|| internal("middle error"))
                .chain_error(|| bad_request("outer user facing error"))
                .unwrap_err())
        })
        .call(&mut req)
        .unwrap();
        assert_eq!(response.status(), StatusCode::BAD_REQUEST);
        assert_eq!(
            crate::middleware::log_request::get_log_message(&req, "cause"),
            "middle error caused by invalid digit found in string"
        );

        // All other error types are propogated up the middleware, eventually becoming status 500
        assert!(C(|_| Err(internal(""))).call(&mut req).is_err());
        assert!(
            C(|_| err::<::serde_json::Error>(::serde::de::Error::custom("ExpectedColon")))
                .call(&mut req)
                .is_err()
        );
        assert!(
            C(|_| err(::std::io::Error::new(::std::io::ErrorKind::Other, "")))
                .call(&mut req)
                .is_err()
        );
    }

    #[test]
    fn router_produces_json_not_found() {
        let route_builder = RouteBuilder::new();
        let mut req = MockRequest::new(::conduit::Method::GET, "/");

        let (parts, body) = R404(route_builder).call(&mut req).unwrap().into_parts();
        assert_eq!(parts.status, StatusCode::NOT_FOUND);
        assert!(matches!(
            body,
            Body::Owned(vec) if vec == br#"{"errors":[{"detail":"Not Found"}]}"#
        ));
    }
}
<commit_msg>Simplify R404 handler<commit_after>use std::sync::Arc;

use conduit::{Handler, HandlerResult, RequestExt};
use conduit_router::{RequestParams, RouteBuilder, RouterError};

use crate::controllers::*;
use crate::util::errors::{std_error, AppError, NotFound};
use crate::util::EndpointResult;
use crate::{App, Env};

pub fn build_router(app: &App) -> R404 {
    let mut api_router = RouteBuilder::new();

    // Route used by both `cargo search` and the frontend
    api_router.get("/crates", C(krate::search::search));

    // Routes used by `cargo`
    api_router.put("/crates/new", C(krate::publish::publish));
    api_router.get("/crates/:crate_id/owners", C(krate::owners::owners));
    api_router.put("/crates/:crate_id/owners", C(krate::owners::add_owners));
    api_router.delete("/crates/:crate_id/owners", C(krate::owners::remove_owners));
    api_router.delete("/crates/:crate_id/:version/yank", C(version::yank::yank));
    api_router.put(
        "/crates/:crate_id/:version/unyank",
        C(version::yank::unyank),
    );
    api_router.get(
        "/crates/:crate_id/:version/download",
        C(version::downloads::download),
    );

    // Routes that appear to be unused
    api_router.get("/versions", C(version::deprecated::index));
    api_router.get("/versions/:version_id", C(version::deprecated::show_by_id));

    // Routes used by the frontend
    api_router.get("/crates/:crate_id", C(krate::metadata::show));
    api_router.get("/crates/:crate_id/:version", C(version::metadata::show));
    api_router.get(
        "/crates/:crate_id/:version/readme",
        C(krate::metadata::readme),
    );
    api_router.get(
        "/crates/:crate_id/:version/dependencies",
        C(version::metadata::dependencies),
    );
    api_router.get(
        "/crates/:crate_id/:version/downloads",
        C(version::downloads::downloads),
    );
    api_router.get(
        "/crates/:crate_id/:version/authors",
        C(version::metadata::authors),
    );
    api_router.get(
        "/crates/:crate_id/downloads",
        C(krate::downloads::downloads),
    );
    api_router.get("/crates/:crate_id/versions", C(krate::metadata::versions));
    api_router.put("/crates/:crate_id/follow", C(krate::follow::follow));
    api_router.delete("/crates/:crate_id/follow", C(krate::follow::unfollow));
    api_router.get("/crates/:crate_id/following", C(krate::follow::following));
    api_router.get("/crates/:crate_id/owner_team", C(krate::owners::owner_team));
    api_router.get("/crates/:crate_id/owner_user", C(krate::owners::owner_user));
    api_router.get(
        "/crates/:crate_id/reverse_dependencies",
        C(krate::metadata::reverse_dependencies),
    );
    api_router.get("/keywords", C(keyword::index));
    api_router.get("/keywords/:keyword_id", C(keyword::show));
    api_router.get("/categories", C(category::index));
    api_router.get("/categories/:category_id", C(category::show));
    api_router.get("/category_slugs", C(category::slugs));
    api_router.get("/users/:user_id", C(user::other::show));
    api_router.put("/users/:user_id", C(user::me::update_user));
    api_router.get("/users/:user_id/stats", C(user::other::stats));
    api_router.get("/teams/:team_id", C(team::show_team));
    api_router.get("/me", C(user::me::me));
    api_router.get("/me/updates", C(user::me::updates));
    api_router.get("/me/tokens", C(token::list));
    api_router.put("/me/tokens", C(token::new));
    api_router.delete("/me/tokens/:id", C(token::revoke));
    api_router.get(
        "/me/crate_owner_invitations",
        C(crate_owner_invitation::list),
    );
    api_router.put(
        "/me/crate_owner_invitations/:crate_id",
        C(crate_owner_invitation::handle_invite),
    );
    api_router.put(
        "/me/crate_owner_invitations/accept/:token",
        C(crate_owner_invitation::handle_invite_with_token),
    );
    api_router.put(
        "/me/email_notifications",
        C(user::me::update_email_notifications),
    );
    api_router.get("/summary", C(krate::metadata::summary));
    api_router.put("/confirm/:email_token", C(user::me::confirm_user_email));
    api_router.put(
        "/users/:user_id/resend",
        C(user::me::regenerate_token_and_send),
    );
    api_router.get("/site_metadata", C(site_metadata::show_deployed_sha));
    let api_router = Arc::new(R404(api_router));

    let mut router = RouteBuilder::new();

    // Mount the router under the /api/v1 path so we're at least somewhat at the
    // liberty to change things in the future!
    router.get("/api/v1/*path", R(Arc::clone(&api_router)));
    router.put("/api/v1/*path", R(Arc::clone(&api_router)));
    router.post("/api/v1/*path", R(Arc::clone(&api_router)));
    router.head("/api/v1/*path", R(Arc::clone(&api_router)));
    router.delete("/api/v1/*path", R(api_router));

    // Session management
    router.get("/api/private/session/begin", C(user::session::begin));
    router.get(
        "/api/private/session/authorize",
        C(user::session::authorize),
    );
    router.delete("/api/private/session", C(user::session::logout));

    // Only serve the local checkout of the git index in development mode.
    // In production, for crates.io, cargo gets the index from
    // https://github.com/rust-lang/crates.io-index directly.
    if app.config.env == Env::Development {
        let s = conduit_git_http_backend::Serve("./tmp/index-bare".into());
        let s = Arc::new(s);
        router.get("/git/index/*path", R(Arc::clone(&s)));
        router.post("/git/index/*path", R(s));
    }

    R404(router)
}

struct C(pub fn(&mut dyn RequestExt) -> EndpointResult);

impl Handler for C {
    fn call(&self, req: &mut dyn RequestExt) -> HandlerResult {
        let C(f) = *self;
        match f(req) {
            Ok(resp) => Ok(resp),
            Err(e) => {
                if let Some(cause) = e.cause() {
                    req.log_metadata("cause", cause.to_string())
                };
                match e.response() {
                    Some(response) => Ok(response),
                    None => Err(std_error(e)),
                }
            }
        }
    }
}

struct R<H>(pub Arc<H>);

impl<H: Handler> Handler for R<H> {
    fn call(&self, req: &mut dyn RequestExt) -> HandlerResult {
        *req.path_mut() = req.params()["path"].to_string();
        let R(ref sub_router) = *self;
        sub_router.call(req)
    }
}

// Can't derive Debug because of RouteBuilder.
#[allow(missing_debug_implementations)]
pub struct R404(pub RouteBuilder);

impl Handler for R404 {
    fn call(&self, req: &mut dyn RequestExt) -> HandlerResult {
        let R404(ref router) = *self;
        match router.call(req) {
            Err(e) if e.downcast_ref::<RouterError>().is_some() => Ok(NotFound.into()),
            other => other,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::util::errors::{
        bad_request, cargo_err, forbidden, internal, not_found, AppError, ChainError,
    };
    use crate::util::EndpointResult;

    use conduit::{Body, StatusCode};
    use conduit_test::MockRequest;
    use diesel::result::Error as DieselError;

    fn err<E: AppError>(err: E) -> EndpointResult {
        Err(Box::new(err))
    }

    #[test]
    fn http_error_responses() {
        let mut req = MockRequest::new(::conduit::Method::GET, "/");

        // Types for handling common error status codes
        assert_eq!(
            C(|_| Err(bad_request(""))).call(&mut req).unwrap().status(),
            StatusCode::BAD_REQUEST
        );
        assert_eq!(
            C(|_| Err(forbidden())).call(&mut req).unwrap().status(),
            StatusCode::FORBIDDEN
        );
        assert_eq!(
            C(|_| Err(DieselError::NotFound.into()))
                .call(&mut req)
                .unwrap()
                .status(),
            StatusCode::NOT_FOUND
        );
        assert_eq!(
            C(|_| Err(not_found())).call(&mut req).unwrap().status(),
            StatusCode::NOT_FOUND
        );

        // cargo_err errors are returned as 200 so that cargo displays this nicely on the command line
        assert_eq!(
            C(|_| Err(cargo_err(""))).call(&mut req).unwrap().status(),
            StatusCode::OK
        );

        // Inner errors are captured for logging when wrapped by a user facing error
        let response = C(|_| {
            Err("-1"
                .parse::<u8>()
                .chain_error(|| internal("middle error"))
                .chain_error(|| bad_request("outer user facing error"))
                .unwrap_err())
        })
        .call(&mut req)
        .unwrap();
        assert_eq!(response.status(), StatusCode::BAD_REQUEST);
        assert_eq!(
            crate::middleware::log_request::get_log_message(&req, "cause"),
            "middle error caused by invalid digit found in string"
        );

        // All other error types are propogated up the middleware, eventually becoming status 500
        assert!(C(|_| Err(internal(""))).call(&mut req).is_err());
        assert!(
            C(|_| err::<::serde_json::Error>(::serde::de::Error::custom("ExpectedColon")))
                .call(&mut req)
                .is_err()
        );
        assert!(
            C(|_| err(::std::io::Error::new(::std::io::ErrorKind::Other, "")))
                .call(&mut req)
                .is_err()
        );
    }

    #[test]
    fn router_produces_json_not_found() {
        let route_builder = RouteBuilder::new();
        let mut req = MockRequest::new(::conduit::Method::GET, "/");

        let (parts, body) = R404(route_builder).call(&mut req).unwrap().into_parts();
        assert_eq!(parts.status, StatusCode::NOT_FOUND);
        assert!(matches!(
            body,
            Body::Owned(vec) if vec == br#"{"errors":[{"detail":"Not Found"}]}"#
        ));
    }
}
<|endoftext|>


<commit_before>//! `core_arch`

#[macro_use]
mod macros;

#[cfg(any(target_arch = "arm", target_arch = "aarch64", dox))]
mod acle;

mod simd;

#[cfg_attr(
    bootstrap,
    doc(include = "../stdarch/crates/core_arch/src/core_arch_docs.md")
)]
#[cfg_attr(not(bootstrap), doc(include = "core_arch_docs.md"))]
#[stable(feature = "simd_arch", since = "1.27.0")]
pub mod arch {
    /// Platform-specific intrinsics for the `x86` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "x86", dox))]
    #[doc(cfg(target_arch = "x86"))]
    #[stable(feature = "simd_x86", since = "1.27.0")]
    pub mod x86 {
        #[stable(feature = "simd_x86", since = "1.27.0")]
        pub use crate::core_arch::x86::*;
    }

    /// Platform-specific intrinsics for the `x86_64` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "x86_64", dox))]
    #[doc(cfg(target_arch = "x86_64"))]
    #[stable(feature = "simd_x86", since = "1.27.0")]
    pub mod x86_64 {
        #[stable(feature = "simd_x86", since = "1.27.0")]
        pub use crate::core_arch::x86::*;
        #[stable(feature = "simd_x86", since = "1.27.0")]
        pub use crate::core_arch::x86_64::*;
    }

    /// Platform-specific intrinsics for the `arm` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "arm", dox))]
    #[doc(cfg(target_arch = "arm"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod arm {
        pub use crate::core_arch::arm::*;
    }

    /// Platform-specific intrinsics for the `aarch64` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "aarch64", dox))]
    #[doc(cfg(target_arch = "aarch64"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod aarch64 {
        pub use crate::core_arch::{aarch64::*, arm::*};
    }

    /// Platform-specific intrinsics for the `wasm32` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "wasm32", dox))]
    #[doc(cfg(target_arch = "wasm32"))]
    #[stable(feature = "simd_wasm32", since = "1.33.0")]
    pub mod wasm32 {
        #[stable(feature = "simd_wasm32", since = "1.33.0")]
        pub use crate::core_arch::wasm32::*;
    }

    /// Platform-specific intrinsics for the `mips` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "mips", dox))]
    #[doc(cfg(target_arch = "mips"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod mips {
        pub use crate::core_arch::mips::*;
    }

    /// Platform-specific intrinsics for the `mips64` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "mips64", dox))]
    #[doc(cfg(target_arch = "mips64"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod mips64 {
        pub use crate::core_arch::mips::*;
    }

    /// Platform-specific intrinsics for the `PowerPC` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "powerpc", dox))]
    #[doc(cfg(target_arch = "powerpc"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod powerpc {
        pub use crate::core_arch::powerpc::*;
    }

    /// Platform-specific intrinsics for the `PowerPC64` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "powerpc64", dox))]
    #[doc(cfg(target_arch = "powerpc64"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod powerpc64 {
        pub use crate::core_arch::powerpc64::*;
    }

    /// Platform-specific intrinsics for the `NVPTX` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "nvptx", target_arch = "nvptx64", dox))]
    #[doc(cfg(any(target_arch = "nvptx", target_arch = "nvptx64")))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod nvptx {
        pub use crate::core_arch::nvptx::*;
    }
}

mod simd_llvm;

#[cfg(any(target_arch = "x86", target_arch = "x86_64", dox))]
#[doc(cfg(any(target_arch = "x86", target_arch = "x86_64")))]
mod x86;
#[cfg(any(target_arch = "x86_64", dox))]
#[doc(cfg(target_arch = "x86_64"))]
mod x86_64;

#[cfg(any(target_arch = "aarch64", dox))]
#[doc(cfg(target_arch = "aarch64"))]
mod aarch64;
#[cfg(any(target_arch = "arm", target_arch = "aarch64", dox))]
#[doc(cfg(any(target_arch = "arm", target_arch = "aarch64")))]
mod arm;

#[cfg(any(target_arch = "wasm32", dox))]
#[doc(cfg(target_arch = "wasm32"))]
mod wasm32;

#[cfg(any(target_arch = "mips", target_arch = "mips64", dox))]
#[doc(cfg(any(target_arch = "mips", target_arch = "mips64")))]
mod mips;

#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64", dox))]
#[doc(cfg(any(target_arch = "powerpc", target_arch = "powerpc64")))]
mod powerpc;

#[cfg(any(target_arch = "powerpc64", dox))]
#[doc(cfg(target_arch = "powerpc64"))]
mod powerpc64;

#[cfg(any(target_arch = "nvptx", target_arch = "nvptx64", dox))]
#[doc(cfg(any(target_arch = "nvptx", target_arch = "nvptx64")))]
mod nvptx;
<commit_msg>Revert PR 769<commit_after>//! `core_arch`

#[macro_use]
mod macros;

#[cfg(any(target_arch = "arm", target_arch = "aarch64", dox))]
mod acle;

mod simd;

#[cfg_attr(
    not(core_arch_docs),
    doc(include = "../stdarch/crates/core_arch/src/core_arch_docs.md")
)]
#[cfg_attr(core_arch_docs, doc(include = "core_arch_docs.md"))]
#[stable(feature = "simd_arch", since = "1.27.0")]
pub mod arch {
    /// Platform-specific intrinsics for the `x86` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "x86", dox))]
    #[doc(cfg(target_arch = "x86"))]
    #[stable(feature = "simd_x86", since = "1.27.0")]
    pub mod x86 {
        #[stable(feature = "simd_x86", since = "1.27.0")]
        pub use crate::core_arch::x86::*;
    }

    /// Platform-specific intrinsics for the `x86_64` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "x86_64", dox))]
    #[doc(cfg(target_arch = "x86_64"))]
    #[stable(feature = "simd_x86", since = "1.27.0")]
    pub mod x86_64 {
        #[stable(feature = "simd_x86", since = "1.27.0")]
        pub use crate::core_arch::x86::*;
        #[stable(feature = "simd_x86", since = "1.27.0")]
        pub use crate::core_arch::x86_64::*;
    }

    /// Platform-specific intrinsics for the `arm` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "arm", dox))]
    #[doc(cfg(target_arch = "arm"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod arm {
        pub use crate::core_arch::arm::*;
    }

    /// Platform-specific intrinsics for the `aarch64` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "aarch64", dox))]
    #[doc(cfg(target_arch = "aarch64"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod aarch64 {
        pub use crate::core_arch::{aarch64::*, arm::*};
    }

    /// Platform-specific intrinsics for the `wasm32` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "wasm32", dox))]
    #[doc(cfg(target_arch = "wasm32"))]
    #[stable(feature = "simd_wasm32", since = "1.33.0")]
    pub mod wasm32 {
        #[stable(feature = "simd_wasm32", since = "1.33.0")]
        pub use crate::core_arch::wasm32::*;
    }

    /// Platform-specific intrinsics for the `mips` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "mips", dox))]
    #[doc(cfg(target_arch = "mips"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod mips {
        pub use crate::core_arch::mips::*;
    }

    /// Platform-specific intrinsics for the `mips64` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "mips64", dox))]
    #[doc(cfg(target_arch = "mips64"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod mips64 {
        pub use crate::core_arch::mips::*;
    }

    /// Platform-specific intrinsics for the `PowerPC` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "powerpc", dox))]
    #[doc(cfg(target_arch = "powerpc"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod powerpc {
        pub use crate::core_arch::powerpc::*;
    }

    /// Platform-specific intrinsics for the `PowerPC64` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "powerpc64", dox))]
    #[doc(cfg(target_arch = "powerpc64"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod powerpc64 {
        pub use crate::core_arch::powerpc64::*;
    }

    /// Platform-specific intrinsics for the `NVPTX` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "nvptx", target_arch = "nvptx64", dox))]
    #[doc(cfg(any(target_arch = "nvptx", target_arch = "nvptx64")))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod nvptx {
        pub use crate::core_arch::nvptx::*;
    }
}

mod simd_llvm;

#[cfg(any(target_arch = "x86", target_arch = "x86_64", dox))]
#[doc(cfg(any(target_arch = "x86", target_arch = "x86_64")))]
mod x86;
#[cfg(any(target_arch = "x86_64", dox))]
#[doc(cfg(target_arch = "x86_64"))]
mod x86_64;

#[cfg(any(target_arch = "aarch64", dox))]
#[doc(cfg(target_arch = "aarch64"))]
mod aarch64;
#[cfg(any(target_arch = "arm", target_arch = "aarch64", dox))]
#[doc(cfg(any(target_arch = "arm", target_arch = "aarch64")))]
mod arm;

#[cfg(any(target_arch = "wasm32", dox))]
#[doc(cfg(target_arch = "wasm32"))]
mod wasm32;

#[cfg(any(target_arch = "mips", target_arch = "mips64", dox))]
#[doc(cfg(any(target_arch = "mips", target_arch = "mips64")))]
mod mips;

#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64", dox))]
#[doc(cfg(any(target_arch = "powerpc", target_arch = "powerpc64")))]
mod powerpc;

#[cfg(any(target_arch = "powerpc64", dox))]
#[doc(cfg(target_arch = "powerpc64"))]
mod powerpc64;

#[cfg(any(target_arch = "nvptx", target_arch = "nvptx64", dox))]
#[doc(cfg(any(target_arch = "nvptx", target_arch = "nvptx64")))]
mod nvptx;
<|endoftext|>


<commit_before>// FIXME This is the simplest most naive implementation of an allocator. I
// basically envisioned it in C in my head and translated it on the fly. I hope
// to revisit this someday when I know the language better, but in the meantime
// don't take this as an example for anything ever.

#![feature(allocator)]
#![feature(asm)]
#![feature(const_fn)]

#![allocator]
#![allow(not_unsafe_ptr_arg_deref)]
#![allow(unknown_lints)]
#![no_std]

use core::fmt::{Write};
use core::ptr;
use core::mem;

extern crate spin;

use self::spin::Mutex;

#[macro_use]
extern crate log;

pub mod serial_logger_lite;

const SPLIT_FUDGE_FACTOR: usize = 32;

#[derive(Debug)]
#[repr(C)]
struct Region {
    size: usize,
    prev: Option<*mut Region>,
    next: Option<*mut Region>,
}

pub struct Allocator {
    heap_start: *mut u8,
    heap_size: usize,
    free_list: Option<*mut Region>,
}

static mut ALLOCATOR: Mutex<Allocator> = Mutex::new(Allocator {
    heap_start: 0 as *mut u8,
    heap_size: 0,
    free_list: None,
});

pub fn init_global_allocator(size: u64, raw_bytes: *mut u8) {
    static mut CALLED: bool = false;

    unsafe {
        assert!(!CALLED);
        init_allocator(&mut ALLOCATOR.lock(), size as usize, raw_bytes);
        CALLED = true;
    }
}

pub fn init_allocator(allocator: &mut Allocator, size: usize, raw_bytes: *mut u8) {

    assert!(!raw_bytes.is_null());

    let mut region = raw_bytes as *mut Region;
    unsafe {
        (*region).size = size;
        (*region).next = None;
        (*region).prev = None;
    }
    allocator.heap_size = size;
    allocator.heap_start = raw_bytes;
    allocator.free_list = Some(raw_bytes as *mut Region);
}

// Serial logger & allocator must be initialized before calling this function.
pub fn debug_allocator() {
    unsafe {
        let allocator = ALLOCATOR.lock();
        let mut current_region = allocator.free_list;
        let mut s: serial_logger_lite::SerialLogger = Default::default();

        while let Some(region) = current_region {
            let _ = write!(&mut s, "Region {:?} {:?}\n", region, region);
            current_region = (*region).next;
        }
    }
}

impl Allocator {
    pub fn free(&mut self, bytes: *mut u8) {

        let mut region: *mut Region;

        if bytes.is_null() {
            return;
        }

        unsafe {
            let offset = -(mem::size_of::<Region>() as isize);
            region = bytes.offset(offset) as *mut Region;

            assert!(region as *mut u8 >= self.heap_start);

            assert!(!region.is_null());

            (*region).prev = None;
            (*region).next = self.free_list;
        }

        self.free_list = Some(region);
    }

    pub fn alloc(&mut self, size: usize) -> *mut u8 {

        let region_offset = mem::size_of::<Region>() as isize;
        let real_size = size + mem::size_of::<Region>();
        let mut current_region = self.free_list;

        while let Some(region) = current_region {

            unsafe {
                if (*region).size >= real_size {
                    let new_next: Option<*mut Region>;
                    let new_prev: Option<*mut Region>;
                    let split = (*region).size - real_size;
                    if split > (region_offset as usize) + SPLIT_FUDGE_FACTOR {
                        let split_region =
                            (region as *mut u8)
                                .offset((size as isize) +
                                        region_offset) as *mut Region;
                        new_next = Some(split_region);
                        new_prev = Some(split_region);
                    } else {
                        new_next = (*region).next;
                        new_prev = (*region).prev;
                    }
                    match (*region).prev {
                        None => {}
                        Some(prev) => (*prev).next = new_next,
                    }
                    match (*region).next {
                        None => {}
                        Some(next) => (*next).prev = new_prev,
                    }
                    if new_next == None && new_prev == None {
                        self.free_list = None;
                    }
                    return (region as *mut u8).offset(region_offset);
                }
                current_region = (*region).next;
            }
        }

        ptr::null::<u8>() as *mut u8
    }
}

#[cfg(not(test))]
#[no_mangle]
pub extern "C" fn __rust_allocate(size: usize, _align: usize) -> *mut u8 {
    unsafe { ALLOCATOR.lock().alloc(size) }
}

#[cfg(not(test))]
#[no_mangle]
pub extern "C" fn __rust_deallocate(ptr: *mut u8, _old_size: usize, _align: usize) {
    unsafe {
        ALLOCATOR.lock().free(ptr);
    }
}

#[cfg(not(test))]
#[no_mangle]
pub extern "C" fn __rust_reallocate(ptr: *mut u8,
                                    old_size: usize,
                                    new_size: usize,
                                    align: usize)
                                    -> *mut u8 {
    use core::cmp;
    let new_ptr = __rust_allocate(new_size, align);
    unsafe { ptr::copy(ptr, new_ptr, cmp::min(old_size, new_size)) };
    __rust_deallocate(ptr, old_size, align);
    new_ptr
}

#[cfg(not(test))]
#[no_mangle]
pub extern "C" fn __rust_reallocate_inplace(_ptr: *mut u8,
                                            old_size: usize,
                                            _size: usize,
                                            _align: usize)
                                            -> usize {
    old_size
}

#[cfg(not(test))]
#[no_mangle]
pub extern "C" fn __rust_usable_size(size: usize, _align: usize) -> usize {
    size
}

#[cfg(test)]
mod tests {
    use core::mem;

    use super::Allocator;
    use super::Region;
    use super::init_allocator;

    #[test]
    fn test_init_allocator() {

        let mut al = Allocator {
            heap_size: 0,
            heap_start: 0 as *mut u8,
            free_list: None,
        };

        let mut memory: [u8; 100] = [0; 100];
        let pmemory: *mut u8 = memory.as_mut_ptr();
        init_allocator(&mut al, mem::size_of::<[u8; 100]>(), pmemory);
        assert_eq!(al.heap_size, 100);
        assert_eq!(al.heap_start, pmemory);

        match al.free_list {
            None => assert!(false),
            Some(fl) => {
                assert!(!fl.is_null());
                unsafe {
                    assert_eq!((*fl).size, 100);
                    assert_eq!((*fl).next, None);
                };
            }
        }
    }

    #[test]
    fn test_alloc_and_free() {

        let mut al = Allocator {
            heap_size: 0,
            heap_start: 0 as *mut u8,
            free_list: None,
        };

        let mut memory: [u8; 1000] = [0; 1000];
        let pmemory: *mut u8 = memory.as_mut_ptr();
        init_allocator(&mut al, mem::size_of::<[u8; 1000]>(), pmemory);

        let m0_size = 10000 - mem::size_of::<Region>();
        let m0 = al.alloc(m0_size);
        assert!(m0.is_null());

        let m1_size = 1000 - mem::size_of::<Region>();
        let m1 = al.alloc(m1_size);
        assert!(!m1.is_null());

        assert_eq!(al.free_list, None);
        al.free(m1);
        assert_ne!(al.free_list, None);

        let m2_size = 100;
        let m2 = al.alloc(m2_size);
        assert!(!m2.is_null());

        let m3_size = 10;
        let m3 = al.alloc(m3_size);
        assert!(!m3.is_null());

        let m4_size = 1;
        let m4 = al.alloc(m4_size);
        assert!(!m4.is_null());

        assert_ne!(al.free_list, None);
        al.free(m3);

        assert_ne!(al.free_list, None);
        al.free(m2);

        assert_ne!(al.free_list, None);
        al.free(m4);
    }
}
<commit_msg>Adjust size when splitting memory<commit_after>// FIXME This is the simplest most naive implementation of an allocator. I
// basically envisioned it in C in my head and translated it on the fly. I hope
// to revisit this someday when I know the language better, but in the meantime
// don't take this as an example for anything ever.

#![feature(allocator)]
#![feature(asm)]
#![feature(const_fn)]

#![allocator]
#![allow(not_unsafe_ptr_arg_deref)]
#![allow(unknown_lints)]
#![no_std]

use core::fmt::{Write};
use core::ptr;
use core::mem;

extern crate spin;

use self::spin::Mutex;

#[macro_use]
extern crate log;

pub mod serial_logger_lite;

const SPLIT_FUDGE_FACTOR: usize = 32;

#[derive(Debug)]
#[repr(C)]
struct Region {
    size: usize,
    prev: Option<*mut Region>,
    next: Option<*mut Region>,
}

pub struct Allocator {
    heap_start: *mut u8,
    heap_size: usize,
    free_list: Option<*mut Region>,
}

static mut ALLOCATOR: Mutex<Allocator> = Mutex::new(Allocator {
    heap_start: 0 as *mut u8,
    heap_size: 0,
    free_list: None,
});

pub fn init_global_allocator(size: u64, raw_bytes: *mut u8) {
    static mut CALLED: bool = false;

    unsafe {
        assert!(!CALLED);
        init_allocator(&mut ALLOCATOR.lock(), size as usize, raw_bytes);
        CALLED = true;
    }
}

pub fn init_allocator(allocator: &mut Allocator, size: usize, raw_bytes: *mut u8) {

    assert!(!raw_bytes.is_null());

    let mut region = raw_bytes as *mut Region;
    unsafe {
        (*region).size = size;
        (*region).next = None;
        (*region).prev = None;
    }
    allocator.heap_size = size;
    allocator.heap_start = raw_bytes;
    allocator.free_list = Some(raw_bytes as *mut Region);
}

// Serial logger & allocator must be initialized before calling this function.
pub fn debug_allocator() {
    unsafe {
        let allocator = ALLOCATOR.lock();
        let mut current_region = allocator.free_list;
        let mut s: serial_logger_lite::SerialLogger = Default::default();

        while let Some(region) = current_region {
            let _ = write!(&mut s, "Region {:?} {:?}\n", region, region);
            current_region = (*region).next;
        }
    }
}

impl Allocator {
    pub fn free(&mut self, bytes: *mut u8) {

        let mut region: *mut Region;

        if bytes.is_null() {
            return;
        }

        unsafe {
            let offset = -(mem::size_of::<Region>() as isize);
            region = bytes.offset(offset) as *mut Region;

            assert!(region as *mut u8 >= self.heap_start);

            assert!(!region.is_null());

            (*region).prev = None;
            (*region).next = self.free_list;
        }

        self.free_list = Some(region);
    }

    pub fn alloc(&mut self, size: usize) -> *mut u8 {

        let region_offset = mem::size_of::<Region>() as isize;
        let real_size = size + mem::size_of::<Region>();
        let mut current_region = self.free_list;

        while let Some(region) = current_region {

            unsafe {
                if (*region).size >= real_size {
                    let new_next: Option<*mut Region>;
                    let new_prev: Option<*mut Region>;
                    let split = (*region).size - real_size;
                    if split > (region_offset as usize) + SPLIT_FUDGE_FACTOR {
                        let split_region =
                            (region as *mut u8)
                                .offset((size as isize) +
                                        region_offset) as *mut Region;
                        (*region).size -= size + region_offset as usize;
                        new_next = Some(split_region);
                        new_prev = Some(split_region);
                    } else {
                        new_next = (*region).next;
                        new_prev = (*region).prev;
                    }
                    match (*region).prev {
                        None => {}
                        Some(prev) => (*prev).next = new_next,
                    }
                    match (*region).next {
                        None => {}
                        Some(next) => (*next).prev = new_prev,
                    }
                    if new_next == None && new_prev == None {
                        self.free_list = None;
                    }
                    return (region as *mut u8).offset(region_offset);
                }
                current_region = (*region).next;
            }
        }

        ptr::null::<u8>() as *mut u8
    }
}

#[cfg(not(test))]
#[no_mangle]
pub extern "C" fn __rust_allocate(size: usize, _align: usize) -> *mut u8 {
    unsafe { ALLOCATOR.lock().alloc(size) }
}

#[cfg(not(test))]
#[no_mangle]
pub extern "C" fn __rust_deallocate(ptr: *mut u8, _old_size: usize, _align: usize) {
    unsafe {
        ALLOCATOR.lock().free(ptr);
    }
}

#[cfg(not(test))]
#[no_mangle]
pub extern "C" fn __rust_reallocate(ptr: *mut u8,
                                    old_size: usize,
                                    new_size: usize,
                                    align: usize)
                                    -> *mut u8 {
    use core::cmp;
    let new_ptr = __rust_allocate(new_size, align);
    unsafe { ptr::copy(ptr, new_ptr, cmp::min(old_size, new_size)) };
    __rust_deallocate(ptr, old_size, align);
    new_ptr
}

#[cfg(not(test))]
#[no_mangle]
pub extern "C" fn __rust_reallocate_inplace(_ptr: *mut u8,
                                            old_size: usize,
                                            _size: usize,
                                            _align: usize)
                                            -> usize {
    old_size
}

#[cfg(not(test))]
#[no_mangle]
pub extern "C" fn __rust_usable_size(size: usize, _align: usize) -> usize {
    size
}

#[cfg(test)]
mod tests {
    use core::mem;

    use super::Allocator;
    use super::Region;
    use super::init_allocator;

    #[test]
    fn test_init_allocator() {

        let mut al = Allocator {
            heap_size: 0,
            heap_start: 0 as *mut u8,
            free_list: None,
        };

        let mut memory: [u8; 100] = [0; 100];
        let pmemory: *mut u8 = memory.as_mut_ptr();
        init_allocator(&mut al, mem::size_of::<[u8; 100]>(), pmemory);
        assert_eq!(al.heap_size, 100);
        assert_eq!(al.heap_start, pmemory);

        match al.free_list {
            None => assert!(false),
            Some(fl) => {
                assert!(!fl.is_null());
                unsafe {
                    assert_eq!((*fl).size, 100);
                    assert_eq!((*fl).next, None);
                };
            }
        }
    }

    #[test]
    fn test_alloc_and_free() {

        let mut al = Allocator {
            heap_size: 0,
            heap_start: 0 as *mut u8,
            free_list: None,
        };

        let mut memory: [u8; 1000] = [0; 1000];
        let pmemory: *mut u8 = memory.as_mut_ptr();
        init_allocator(&mut al, mem::size_of::<[u8; 1000]>(), pmemory);

        let m0_size = 10000 - mem::size_of::<Region>();
        let m0 = al.alloc(m0_size);
        assert!(m0.is_null());

        let m1_size = 1000 - mem::size_of::<Region>();
        let m1 = al.alloc(m1_size);
        assert!(!m1.is_null());

        assert_eq!(al.free_list, None);
        al.free(m1);
        assert_ne!(al.free_list, None);

        let m2_size = 100;
        let m2 = al.alloc(m2_size);
        assert!(!m2.is_null());

        let m3_size = 10;
        let m3 = al.alloc(m3_size);
        assert!(!m3.is_null());

        let m4_size = 1;
        let m4 = al.alloc(m4_size);
        assert!(!m4.is_null());

        assert_ne!(al.free_list, None);
        al.free(m3);

        assert_ne!(al.free_list, None);
        al.free(m2);

        assert_ne!(al.free_list, None);
        al.free(m4);
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016-2017 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]

use clap::{App, Arg};
use std::path::Path;
use std::result;
use std::str::FromStr;

use hcore::package::PackageIdent;
use url::Url;

/// The version of this library and program when built.
pub const VERSION: &'static str = include_str!(concat!(env!("OUT_DIR"), "/VERSION"));

/// A Docker-specific clap:App wrapper
#[derive(Clone)]
pub struct Cli<'a, 'b>
where
    'a: 'b,
{
    pub app: App<'a, 'b>,
}

impl<'a, 'b> Cli<'a, 'b> {
    pub fn new(name: &str, about: &'a str) -> Self {
        Cli {
            app: clap_app!(
            (name) =>
            (about: about)
            (version: VERSION)
            (author: "\nAuthors: The Habitat Maintainers <humans@habitat.sh>\n\n")
            (@arg IMAGE_NAME: --("image-name") -i +takes_value
                "Image name (default: \"{{pkg_origin}}/{{pkg_name}}\" supports: \
                 {{pkg_origin}}, {{pkg_name}}, {{pkg_version}}, {{pkg_release}}, {{channel}})")
            ),
        }
    }

    pub fn add_base_packages_args(self) -> Self {
        let app = self.app
            .arg(
                Arg::with_name("HAB_PKG")
                    .long("hab-pkg")
                    .value_name("HAB_PKG")
                    .validator(valid_ident_or_hart)
                    .help(
                        "Habitat CLI package identifier (ex: acme/redis) or filepath to a Habitat \
                        artifact (ex: /home/acme-redis-3.0.7-21120102031201-x86_64-linux.hart) to \
                        install (default: core/hab)",
                    ),
            )
            .arg(
                Arg::with_name("HAB_LAUNCHER_PKG")
                    .long("launcher-pkg")
                    .value_name("HAB_LAUNCHER_PKG")
                    .validator(valid_ident_or_hart)
                    .help(
                        "Launcher package identifier (ex: acme/redis) or filepath to a Habitat \
                        artifact (ex: /home/acme-redis-3.0.7-21120102031201-x86_64-linux.hart) to \
                        install (default: core/hab-launcher)",
                    ),
            )
            .arg(
                Arg::with_name("HAB_SUP_PKG")
                    .long("sup-pkg")
                    .value_name("HAB_SUP_PKG")
                    .validator(valid_ident_or_hart)
                    .help(
                        "Supervisor package identifier (ex: acme/redis) or filepath to a Habitat \
                        artifact (ex: /home/acme-redis-3.0.7-21120102031201-x86_64-linux.hart) to \
                        install (default: core/hab-sup)",
                    ),
            );

        Cli { app: app }
    }

    pub fn add_builder_args(self) -> Self {
        let app = self.app
            .arg(
                Arg::with_name("BLDR_URL")
                    .long("url")
                    .short("u")
                    .value_name("BLDR_URL")
                    .validator(valid_url)
                    .help(
                        "Install packages from Builder at the specified URL \
                        (default: https://bldr.habitat.sh)",
                    ),
            )
            .arg(
                Arg::with_name("CHANNEL")
                    .long("channel")
                    .short("c")
                    .value_name("CHANNEL")
                    .help(
                        "Install packages from the specified release channel (default: stable)",
                    ),
            )
            .arg(
                Arg::with_name("BASE_PKGS_BLDR_URL")
                    .long("base-pkgs-url")
                    .value_name("BASE_PKGS_BLDR_URL")
                    .validator(valid_url)
                    .help(
                        "Install base packages from Builder at the specified URL \
                        (default: https://bldr.habitat.sh)",
                    ),
            )
            .arg(
                Arg::with_name("BASE_PKGS_CHANNEL")
                    .long("base-pkgs-channel")
                    .value_name("BASE_PKGS_CHANNEL")
                    .help(
                        "Install base packages from the specified release channel \
                        (default: stable)",
                    ),
            );

        Cli { app: app }
    }

    pub fn add_tagging_args(self) -> Self {
        let app = self.app
            .arg(
                Arg::with_name("TAG_VERSION_RELEASE")
                    .long("tag-version-release")
                    .conflicts_with("NO_TAG_VERSION_RELEASE")
                    .help(
                        "Tag image with :\"{{pkg_version}}-{{pkg_release}}\" (default: yes)",
                    ),
            )
            .arg(
                Arg::with_name("NO_TAG_VERSION_RELEASE")
                    .long("no-tag-version-release")
                    .conflicts_with("TAG_VERSION_RELEASE")
                    .help(
                        "Do not tag image with :\"{{pkg_version}}-{{pkg_release}}\" (default: no)",
                    ),
            )
            .arg(
                Arg::with_name("TAG_VERSION")
                    .long("tag-version")
                    .conflicts_with("NO_TAG_VERSION")
                    .help("Tag image with :\"{{pkg_version}}\" (default: yes)"),
            )
            .arg(
                Arg::with_name("NO_TAG_VERSION")
                    .long("no-tag-version")
                    .conflicts_with("TAG_VERSION")
                    .help("Do not tag image with :\"{{pkg_version}}\" (default: no)"),
            )
            .arg(
                Arg::with_name("TAG_LATEST")
                    .long("tag-latest")
                    .conflicts_with("NO_TAG_LATEST")
                    .help("Tag image with :\"latest\" (default: yes)"),
            )
            .arg(
                Arg::with_name("NO_TAG_LATEST")
                    .long("no-tag-latest")
                    .conflicts_with("TAG_LATEST")
                    .help("Do not tag image with :\"latest\" (default: no)"),
            )
            .arg(
                Arg::with_name("TAG_CUSTOM")
                    .long("tag-custom")
                    .value_name("TAG_CUSTOM")
                    .help(
                        "Tag image with additional custom tag (supports: {{pkg_origin}}, \
                        {{pkg_name}}, {{pkg_version}}, {{pkg_release}}, {{channel}})",
                    ),
            );

        Cli { app: app }
    }

    pub fn add_publishing_args(self) -> Self {
        let app = self.app.arg(Arg::with_name("PUSH_IMAGE")
                 .long("push-image")
                 .conflicts_with("NO_PUSH_IMAGE")
                 .requires_all(&["REGISTRY_USERNAME", "REGISTRY_PASSWORD"])
                 .help("Push image to remote registry (default: no)"))
            .arg(Arg::with_name("NO_PUSH_IMAGE")
                 .long("no-push-image")
                 .conflicts_with("PUSH_IMAGE")
                 .help("Do not push image to remote registry (default: yes)"))
            .arg(Arg::with_name("REGISTRY_USERNAME")
                 .long("username")
                 .short("U")
                 .value_name("REGISTRY_USERNAME")
                 .requires("REGISTRY_PASSWORD")
                 .help("Remote registry username, required for pushing image to remote registry"))
            .arg(Arg::with_name("REGISTRY_PASSWORD")
                 .long("password")
                 .short("P")
                 .value_name("REGISTRY_PASSWORD")
                 .requires("REGISTRY_USERNAME")
                 .help("Remote registry password, required for pushing image to remote registry"))
            .arg(Arg::with_name("REGISTRY_TYPE")
                 .long("registry-type")
                 .short("R")
                 .value_name("REGISTRY_TYPE")
                 .help("Remote registry type, Ex: Amazon, Docker, Google (default: docker)"))
            .arg(Arg::with_name("REGISTRY_URL")
                 .long("registry-url")
                 .short("G")
                 .value_name("REGISTRY_URL")
                 .help("Remote registry url"))
            // Cleanup
            .arg(Arg::with_name("RM_IMAGE")
                 .long("rm-image")
                 .help("Remove local image from engine after build and/or push (default: no)"));

        Cli { app: app }
    }
}

fn valid_ident_or_hart(val: String) -> result::Result<(), String> {
    if Path::new(&val).is_file() {
        Ok(())
    } else if val.ends_with(".hart") {
        Err(format!("Habitat artifact file: '{}' not found", &val))
    } else {
        match PackageIdent::from_str(&val) {
            Ok(_) => Ok(()),
            Err(e) => Err(format!("{}", e)),
        }
    }
}

fn valid_url(val: String) -> result::Result<(), String> {
    match Url::parse(&val) {
        Ok(_) => Ok(()),
        Err(_) => Err(format!("URL: '{}' is not valid", &val)),
    }
}
<commit_msg>pkg-export-docker: More concrete examples in help message<commit_after>// Copyright (c) 2016-2017 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]

use clap::{App, Arg};
use std::path::Path;
use std::result;
use std::str::FromStr;

use hcore::package::PackageIdent;
use url::Url;

/// The version of this library and program when built.
pub const VERSION: &'static str = include_str!(concat!(env!("OUT_DIR"), "/VERSION"));

/// A Docker-specific clap:App wrapper
#[derive(Clone)]
pub struct Cli<'a, 'b>
where
    'a: 'b,
{
    pub app: App<'a, 'b>,
}

impl<'a, 'b> Cli<'a, 'b> {
    pub fn new(name: &str, about: &'a str) -> Self {
        Cli {
            app: clap_app!(
            (name) =>
            (about: about)
            (version: VERSION)
            (author: "\nAuthors: The Habitat Maintainers <humans@habitat.sh>\n\n")
            (@arg IMAGE_NAME: --("image-name") -i +takes_value
                "Image name (default: \"{{pkg_origin}}/{{pkg_name}}\" supports: \
                 {{pkg_origin}}, {{pkg_name}}, {{pkg_version}}, {{pkg_release}}, {{channel}})")
            ),
        }
    }

    pub fn add_base_packages_args(self) -> Self {
        let app = self.app
            .arg(
                Arg::with_name("HAB_PKG")
                    .long("hab-pkg")
                    .value_name("HAB_PKG")
                    .validator(valid_ident_or_hart)
                    .help(
                        "Habitat CLI package identifier (ex: acme/redis) or filepath to a Habitat \
                        artifact (ex: /home/acme-redis-3.0.7-21120102031201-x86_64-linux.hart) to \
                        install (default: core/hab)",
                    ),
            )
            .arg(
                Arg::with_name("HAB_LAUNCHER_PKG")
                    .long("launcher-pkg")
                    .value_name("HAB_LAUNCHER_PKG")
                    .validator(valid_ident_or_hart)
                    .help(
                        "Launcher package identifier (ex: core/hab-launcher) or filepath to a \
                        Habitat artifact (ex: \
                        /home/core-hab-launcher-6083-20171101045646-x86_64-linux.hart) to install \
                        (default: core/hab-launcher)",
                    ),
            )
            .arg(
                Arg::with_name("HAB_SUP_PKG")
                    .long("sup-pkg")
                    .value_name("HAB_SUP_PKG")
                    .validator(valid_ident_or_hart)
                    .help(
                        "Supervisor package identifier (ex: core/hab-sup) or filepath to a Habitat \
                        artifact (ex: \
                        /home/ore-hab-sup-0.39.1-20171118011657-x86_64-linux.hart) to install \
                        (default: core/hab-sup)",
                    ),
            );

        Cli { app: app }
    }

    pub fn add_builder_args(self) -> Self {
        let app = self.app
            .arg(
                Arg::with_name("BLDR_URL")
                    .long("url")
                    .short("u")
                    .value_name("BLDR_URL")
                    .validator(valid_url)
                    .help(
                        "Install packages from Builder at the specified URL \
                        (default: https://bldr.habitat.sh)",
                    ),
            )
            .arg(
                Arg::with_name("CHANNEL")
                    .long("channel")
                    .short("c")
                    .value_name("CHANNEL")
                    .help(
                        "Install packages from the specified release channel (default: stable)",
                    ),
            )
            .arg(
                Arg::with_name("BASE_PKGS_BLDR_URL")
                    .long("base-pkgs-url")
                    .value_name("BASE_PKGS_BLDR_URL")
                    .validator(valid_url)
                    .help(
                        "Install base packages from Builder at the specified URL \
                        (default: https://bldr.habitat.sh)",
                    ),
            )
            .arg(
                Arg::with_name("BASE_PKGS_CHANNEL")
                    .long("base-pkgs-channel")
                    .value_name("BASE_PKGS_CHANNEL")
                    .help(
                        "Install base packages from the specified release channel \
                        (default: stable)",
                    ),
            );

        Cli { app: app }
    }

    pub fn add_tagging_args(self) -> Self {
        let app = self.app
            .arg(
                Arg::with_name("TAG_VERSION_RELEASE")
                    .long("tag-version-release")
                    .conflicts_with("NO_TAG_VERSION_RELEASE")
                    .help(
                        "Tag image with :\"{{pkg_version}}-{{pkg_release}}\" (default: yes)",
                    ),
            )
            .arg(
                Arg::with_name("NO_TAG_VERSION_RELEASE")
                    .long("no-tag-version-release")
                    .conflicts_with("TAG_VERSION_RELEASE")
                    .help(
                        "Do not tag image with :\"{{pkg_version}}-{{pkg_release}}\" (default: no)",
                    ),
            )
            .arg(
                Arg::with_name("TAG_VERSION")
                    .long("tag-version")
                    .conflicts_with("NO_TAG_VERSION")
                    .help("Tag image with :\"{{pkg_version}}\" (default: yes)"),
            )
            .arg(
                Arg::with_name("NO_TAG_VERSION")
                    .long("no-tag-version")
                    .conflicts_with("TAG_VERSION")
                    .help("Do not tag image with :\"{{pkg_version}}\" (default: no)"),
            )
            .arg(
                Arg::with_name("TAG_LATEST")
                    .long("tag-latest")
                    .conflicts_with("NO_TAG_LATEST")
                    .help("Tag image with :\"latest\" (default: yes)"),
            )
            .arg(
                Arg::with_name("NO_TAG_LATEST")
                    .long("no-tag-latest")
                    .conflicts_with("TAG_LATEST")
                    .help("Do not tag image with :\"latest\" (default: no)"),
            )
            .arg(
                Arg::with_name("TAG_CUSTOM")
                    .long("tag-custom")
                    .value_name("TAG_CUSTOM")
                    .help(
                        "Tag image with additional custom tag (supports: {{pkg_origin}}, \
                        {{pkg_name}}, {{pkg_version}}, {{pkg_release}}, {{channel}})",
                    ),
            );

        Cli { app: app }
    }

    pub fn add_publishing_args(self) -> Self {
        let app = self.app.arg(Arg::with_name("PUSH_IMAGE")
                 .long("push-image")
                 .conflicts_with("NO_PUSH_IMAGE")
                 .requires_all(&["REGISTRY_USERNAME", "REGISTRY_PASSWORD"])
                 .help("Push image to remote registry (default: no)"))
            .arg(Arg::with_name("NO_PUSH_IMAGE")
                 .long("no-push-image")
                 .conflicts_with("PUSH_IMAGE")
                 .help("Do not push image to remote registry (default: yes)"))
            .arg(Arg::with_name("REGISTRY_USERNAME")
                 .long("username")
                 .short("U")
                 .value_name("REGISTRY_USERNAME")
                 .requires("REGISTRY_PASSWORD")
                 .help("Remote registry username, required for pushing image to remote registry"))
            .arg(Arg::with_name("REGISTRY_PASSWORD")
                 .long("password")
                 .short("P")
                 .value_name("REGISTRY_PASSWORD")
                 .requires("REGISTRY_USERNAME")
                 .help("Remote registry password, required for pushing image to remote registry"))
            .arg(Arg::with_name("REGISTRY_TYPE")
                 .long("registry-type")
                 .short("R")
                 .value_name("REGISTRY_TYPE")
                 .help("Remote registry type, Ex: Amazon, Docker, Google (default: docker)"))
            .arg(Arg::with_name("REGISTRY_URL")
                 .long("registry-url")
                 .short("G")
                 .value_name("REGISTRY_URL")
                 .help("Remote registry url"))
            // Cleanup
            .arg(Arg::with_name("RM_IMAGE")
                 .long("rm-image")
                 .help("Remove local image from engine after build and/or push (default: no)"));

        Cli { app: app }
    }
}

fn valid_ident_or_hart(val: String) -> result::Result<(), String> {
    if Path::new(&val).is_file() {
        Ok(())
    } else if val.ends_with(".hart") {
        Err(format!("Habitat artifact file: '{}' not found", &val))
    } else {
        match PackageIdent::from_str(&val) {
            Ok(_) => Ok(()),
            Err(e) => Err(format!("{}", e)),
        }
    }
}

fn valid_url(val: String) -> result::Result<(), String> {
    match Url::parse(&val) {
        Ok(_) => Ok(()),
        Err(_) => Err(format!("URL: '{}' is not valid", &val)),
    }
}
<|endoftext|>


<commit_before>#![feature(rustc_private, plugin_registrar)]

extern crate rustc;
extern crate syntax;

mod derive_action;

use rustc::plugin::Registry;
use syntax::parse::token::intern;
use syntax::ext::base::SyntaxExtension;

use derive_action::expand_derive_action_annotation;

#[plugin_registrar]
#[doc(hidden)]
pub fn plugin_registrar(registry: &mut Registry) {
    registry.register_syntax_extension(intern("derive_Action"),
                                       SyntaxExtension::MultiDecorator(
                                           Box::new(expand_derive_action_annotation)));
}<commit_msg>Add `extern crate rebind` to `rebind_plugins`'s `lib.rs`<commit_after>#![feature(rustc_private, plugin_registrar)]

extern crate rebind;
extern crate rustc;
extern crate syntax;

mod derive_action;

use rustc::plugin::Registry;
use syntax::parse::token::intern;
use syntax::ext::base::SyntaxExtension;

use derive_action::expand_derive_action_annotation;

#[plugin_registrar]
#[doc(hidden)]
pub fn plugin_registrar(registry: &mut Registry) {
    registry.register_syntax_extension(intern("derive_Action"),
                                       SyntaxExtension::MultiDecorator(
                                           Box::new(expand_derive_action_annotation)));
}<|endoftext|>