<commit_before>//! Logging scopes for slog-rs
//!
//! Logging scopes are convinience functionality for slog-rs to free user from manually passing
//! `Logger` objects around.
//!
//! Set of macros is also provided as an alternative to original `slog` crate macros, for logging
//! directly to `Logger` of the current logging scope.
//!
//! Note: Part of a `slog` logging philosophy is ability to freely express logging contexts
//! according to logical structure, rather than code structure. By using logging scopes the logging
//! context is tied to code flow again, which is less expressive.
//!
//! It is generally advised **NOT** to use `slog_scope` in libraries. Read more in
//! [slog-rs FAQ](https://github.com/slog-rs/slog/wiki/FAQ#do-i-have-to-pass-logger-around)
//!
//! ```
//! #[macro_use(slog_o, slog_info, slog_log, slog_record, slog_record_static, slog_b, slog_kv)]
//! extern crate slog;
//! #[macro_use]
//! extern crate slog_scope;
//! extern crate slog_term;
//!
//! use slog::Drain;
//!
//! fn foo() {
//!     slog_info!(slog_scope::logger(), "foo");
//!     info!("foo"); // Same as above, but more ergonomic.
//! }
//!
//! fn main() {
//!     let plain = slog_term::PlainSyncDecorator::new(std::io::stdout());
//!     let log = slog::Logger::root(
//!         slog_term::FullFormat::new(plain)
//!         .build().fuse(), slog_o!()
//!     );
//!
//!     // Make sure to save the guard, see documentation for more information
//!     let _guard = slog_scope::set_global_logger(log);
//!     slog_scope::scope(slog_scope::logger().new(slog_o!("scope" => "1")),
//!         || foo()
//!     );
//! }

#![warn(missing_docs)]

#[macro_use(o)]
extern crate slog;
#[macro_use]
extern crate lazy_static;
extern crate crossbeam;

use slog::*;

use std::sync::Arc;
use std::cell::RefCell;
use crossbeam::sync::ArcCell;

/// Log a critical level message using current scope logger
#[macro_export]
macro_rules! crit( ($($args:tt)+) => { slog_crit![$crate::logger(), $($args)+]; };);
/// Log a error level message using current scope logger
#[macro_export]
macro_rules! error( ($($args:tt)+) => { slog_error![$crate::logger(), $($args)+]; };);
/// Log a warning level message using current scope logger
#[macro_export]
macro_rules! warn( ($($args:tt)+) => { slog_warn![$crate::logger(), $($args)+]; };);
/// Log a info level message using current scope logger
#[macro_export]
macro_rules! info( ($($args:tt)+) => { slog_info![$crate::logger(), $($args)+]; };);
/// Log a debug level message using current scope logger
#[macro_export]
macro_rules! debug( ($($args:tt)+) => { slog_debug![$crate::logger(), $($args)+]; };);
/// Log a trace level message using current scope logger
#[macro_export]
macro_rules! trace( ($($args:tt)+) => { slog_trace![$crate::logger(), $($args)+]; };);

thread_local! {
    static TL_SCOPES: RefCell<Vec<slog::Logger>> = RefCell::new(Vec::with_capacity(8))
}

lazy_static! {
    static ref GLOBAL_LOGGER : ArcCell<slog::Logger> = ArcCell::new(
        Arc::new(
            slog::Logger::root(slog::Discard, o!())
        )
    );
}

/// Guard resetting global logger
///
/// On drop it will reset global logger to `slog::Discard`.
/// This will `drop` any existing global logger.
#[must_use]
pub struct GlobalLoggerGuard {
    canceled : bool,
}

impl GlobalLoggerGuard {

    fn new() -> Self {
        GlobalLoggerGuard {
            canceled: false,
        }
    }

    /// Cancel resetting global logger
    pub fn cancel_reset(mut self) {
        self.canceled = true;
    }
}

impl Drop for GlobalLoggerGuard {
    fn drop(&mut self) {
        if !self.canceled {
            let _ = GLOBAL_LOGGER.set(
                Arc::new(
                    slog::Logger::root(slog::Discard, o!())
                    )
                );
        }
    }
}

/// Set global `Logger` that is returned by calls like `logger()` outside of any logging scope.
pub fn set_global_logger(l: slog::Logger) -> GlobalLoggerGuard {
    let _ = GLOBAL_LOGGER.set(Arc::new(l));

    GlobalLoggerGuard::new()
}

struct ScopeGuard;

impl ScopeGuard {
    fn new(logger: slog::Logger) -> Self {
        TL_SCOPES.with(|s| { s.borrow_mut().push(logger); });

        ScopeGuard
    }
}

impl Drop for ScopeGuard {
    fn drop(&mut self) {
        TL_SCOPES.with(|s| { s.borrow_mut().pop().expect("TL_SCOPES should contain a logger"); })
    }
}

/// Access the `Logger` for the current logging scope
pub fn logger() -> Logger {
    TL_SCOPES.with(|s| {
        let s = s.borrow();
        match s.last() {
            Some(logger) => logger.clone(),
            None => (*GLOBAL_LOGGER.get()).clone(),
        }
    })
}

/// Execute code in a logging scope
///
/// Logging scopes allow using a `slog::Logger` without explicitly
/// passing it in the code.
///
/// At any time current active `Logger` for a given thread can be retrived
/// with `logger()` call.
///
/// Logging scopes can be nested and are panic safe.
///
/// `logger` is the `Logger` to use during the duration of `f`.
/// `with_current_logger` can be used to build it as a child of currently active
/// logger.
///
/// `f` is a code to be executed in the logging scope.
///
/// Note: Thread scopes are thread-local. Each newly spawned thread starts
/// with a global logger, as a current logger.
pub fn scope<SF, R>(logger: slog::Logger, f: SF) -> R
    where SF: FnOnce() -> R
{
    let _guard = ScopeGuard::new(logger);
    f()
}
<commit_msg>Store references to prevent cloning<commit_after>//! Logging scopes for slog-rs
//!
//! Logging scopes are convenience functionality for slog-rs to free user from manually passing
//! `Logger` objects around.
//!
//! Set of macros is also provided as an alternative to original `slog` crate macros, for logging
//! directly to `Logger` of the current logging scope.
//!
//! Note: Part of a `slog` logging philosophy is ability to freely express logging contexts
//! according to logical structure, rather than code structure. By using logging scopes the logging
//! context is tied to code flow again, which is less expressive.
//!
//! It is generally advised **NOT** to use `slog_scope` in libraries. Read more in
//! [slog-rs FAQ](https://github.com/slog-rs/slog/wiki/FAQ#do-i-have-to-pass-logger-around)
//!
//! ```
//! #[macro_use(slog_o, slog_info, slog_log, slog_record, slog_record_static, slog_b, slog_kv)]
//! extern crate slog;
//! #[macro_use]
//! extern crate slog_scope;
//! extern crate slog_term;
//!
//! use slog::Drain;
//!
//! fn foo() {
//!     slog_info!(slog_scope::logger(), "foo");
//!     info!("foo"); // Same as above, but more ergonomic.
//! }
//!
//! fn main() {
//!     let plain = slog_term::PlainSyncDecorator::new(std::io::stdout());
//!     let log = slog::Logger::root(
//!         slog_term::FullFormat::new(plain)
//!         .build().fuse(), slog_o!()
//!     );
//!
//!     // Make sure to save the guard, see documentation for more information
//!     let _guard = slog_scope::set_global_logger(log);
//!     slog_scope::scope(slog_scope::logger().new(slog_o!("scope" => "1")),
//!         || foo()
//!     );
//! }

#![warn(missing_docs)]

#[macro_use(o)]
extern crate slog;
#[macro_use]
extern crate lazy_static;
extern crate crossbeam;

use slog::*;

use std::sync::Arc;
use std::cell::RefCell;
use crossbeam::sync::ArcCell;

/// Log a critical level message using current scope logger
#[macro_export]
macro_rules! crit( ($($args:tt)+) => { slog_crit![$crate::logger(), $($args)+]; };);
/// Log a error level message using current scope logger
#[macro_export]
macro_rules! error( ($($args:tt)+) => { slog_error![$crate::logger(), $($args)+]; };);
/// Log a warning level message using current scope logger
#[macro_export]
macro_rules! warn( ($($args:tt)+) => { slog_warn![$crate::logger(), $($args)+]; };);
/// Log a info level message using current scope logger
#[macro_export]
macro_rules! info( ($($args:tt)+) => { slog_info![$crate::logger(), $($args)+]; };);
/// Log a debug level message using current scope logger
#[macro_export]
macro_rules! debug( ($($args:tt)+) => { slog_debug![$crate::logger(), $($args)+]; };);
/// Log a trace level message using current scope logger
#[macro_export]
macro_rules! trace( ($($args:tt)+) => { slog_trace![$crate::logger(), $($args)+]; };);

thread_local! {
    static TL_SCOPES: RefCell<Vec<*const slog::Logger>> = RefCell::new(Vec::with_capacity(8))
}

lazy_static! {
    static ref GLOBAL_LOGGER : ArcCell<slog::Logger> = ArcCell::new(
        Arc::new(
            slog::Logger::root(slog::Discard, o!())
        )
    );
}

/// Guard resetting global logger
///
/// On drop it will reset global logger to `slog::Discard`.
/// This will `drop` any existing global logger.
#[must_use]
pub struct GlobalLoggerGuard {
    canceled : bool,
}

impl GlobalLoggerGuard {

    fn new() -> Self {
        GlobalLoggerGuard {
            canceled: false,
        }
    }

    /// Cancel resetting global logger
    pub fn cancel_reset(mut self) {
        self.canceled = true;
    }
}

impl Drop for GlobalLoggerGuard {
    fn drop(&mut self) {
        if !self.canceled {
            let _ = GLOBAL_LOGGER.set(
                Arc::new(
                    slog::Logger::root(slog::Discard, o!())
                    )
                );
        }
    }
}

/// Set global `Logger` that is returned by calls like `logger()` outside of any logging scope.
pub fn set_global_logger(l: slog::Logger) -> GlobalLoggerGuard {
    let _ = GLOBAL_LOGGER.set(Arc::new(l));

    GlobalLoggerGuard::new()
}

struct ScopeGuard;

impl ScopeGuard {
    fn new(logger: &slog::Logger) -> Self {
        TL_SCOPES.with(|s| { s.borrow_mut().push(logger as *const Logger); });

        ScopeGuard
    }
}

impl Drop for ScopeGuard {
    fn drop(&mut self) {
        TL_SCOPES.with(|s| { s.borrow_mut().pop().expect("TL_SCOPES should contain a logger"); })
    }
}

/// Access the `Logger` for the current logging scope
pub fn logger() -> Logger {
    TL_SCOPES.with(|s| {
        let s = s.borrow();
        match s.last() {
            Some(logger) => (unsafe {&**logger}).clone(),
            None => (*GLOBAL_LOGGER.get()).clone(),
        }
    })
}

/// Access the `Logger` for the current logging scope
///
/// This function doesn't have to clone the Logger
/// so it might be a bit faster.
pub fn with_logger<F, R>(f : F) -> R
where F : FnOnce(&Logger) -> R {
    TL_SCOPES.with(|s| {
        let s = s.borrow();
        match s.last() {
            Some(logger) => f(unsafe {&**logger}),
            None => f(&(*GLOBAL_LOGGER.get())),
        }
    })
}

/// Execute code in a logging scope
///
/// Logging scopes allow using a `slog::Logger` without explicitly
/// passing it in the code.
///
/// At any time current active `Logger` for a given thread can be retrived
/// with `logger()` call.
///
/// Logging scopes can be nested and are panic safe.
///
/// `logger` is the `Logger` to use during the duration of `f`.
/// `with_current_logger` can be used to build it as a child of currently active
/// logger.
///
/// `f` is a code to be executed in the logging scope.
///
/// Note: Thread scopes are thread-local. Each newly spawned thread starts
/// with a global logger, as a current logger.
pub fn scope<SF, R>(logger: &slog::Logger, f: SF) -> R
    where SF: FnOnce() -> R
{
    let _guard = ScopeGuard::new(&logger);
    f()
}
<|endoftext|>


<commit_before>// Copyright 2014 The rust-pcre authors.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern mod rustc;

use rustc::driver::driver::host_triple;
use std::from_str::{from_str};
use std::io;
use std::io::fs::{mkdir, File};
use std::option::{Option};
use std::os;
use std::run;
use std::str;

struct Version {
    major: uint,
    minor: uint
}

impl Version {
    pub fn parse(version_str: &str) -> Option<Version> {
        let mut it = version_str.split('.');
        match (it.next().and_then(from_str::<uint>), it.next().and_then(from_str::<uint>)) {
            (Some(major), Some(minor)) => Some(Version { major: major, minor: minor }),
            _                          => None
        }
    }
}

impl ToStr for Version {
    fn to_str(&self) -> ~str {
        format!("{:u}.{:u}", self.major, self.minor)
    }
}

impl Ord for Version {
    fn lt(&self, other: &Version) -> bool {
        self.major < other.major || (self.major == other.major && self.minor < other.minor)
    }
}

fn cd(path: &Path) {
    if !os::change_dir(path) {
        fail!("Package script error: Failed to `cd` into `{}`", path.display());
    }
}

fn main() {
    let pcre_libdir = match os::getenv("PCRE_LIBDIR") {
        None            => {
            let pcre_config_output = io::io_error::cond.trap(|e: io::IoError| {
                match e.kind {
                    io::FileNotFound => fail!("Package script error: Could not run `pcre-config` because no such executable is in the executable search PATH. Make sure that you have installed a dev package for libpcre and/or make sure that libpcre's bindir is added to your PATH (currently \"{}\").", os::getenv("PATH").unwrap_or(~"")),
                    _ => fail!("Package script error: Could not run `pcre-config`: {}", e.to_str())
                }
            }).inside(|| -> run::ProcessOutput {
                run::process_output("pcre-config", [~"--prefix"]).expect("failed to exec `pcre-config`")
            });
            if !pcre_config_output.status.success() {
                fail!("Package script error: `pcre-config --prefix` failed");
            }
            let output_ptr = pcre_config_output.output.as_ptr();
            let output_len = pcre_config_output.output.len();
            let prefix_str = unsafe { str::raw::from_buf_len(output_ptr, output_len) };
            // `pcre-config` adds a newline to the end, which we need to trim away.
            prefix_str.trim() + "/lib"
        },
        Some(pcre_libdir) => pcre_libdir
    };
    let pcre_lib_path = Path::new(pcre_libdir);

    let workspace_path = os::getcwd();

    // Check the version
    let target_build_path = workspace_path.join("build").join(host_triple());
    if !target_build_path.exists() {
        if !io::result(|| mkdir(&target_build_path, 0x1FF)).is_ok() {
            fail!("Package script error: Failed to create target build directory `{}`", target_build_path.display());
        }
    }
    let out_path = target_build_path.join("pcre");
    if !out_path.exists() {
        if !io::result(|| mkdir(&out_path, 0x1FF)).is_ok() {
            fail!("Package script error: Failed to create output directory `{}`", out_path.display());
        }
    }

    let versioncheck_rs_path = out_path.join("versioncheck.rs");
    {
        let mut w = match File::create(&versioncheck_rs_path) {
            None    => fail!("Package script error: Failed to open `{}` for writing", versioncheck_rs_path.display()),
            Some(w) => w
        };
        write!(&mut w as &mut Writer, "\
use std::c_str::\\{CString\\};
use std::libc::\\{c_char, c_int, c_uchar, c_void\\};
use std::ptr;
use std::vec;

type options = c_int;
struct pcre;
struct pcre_extra;

\\#[link(name = \"pcre\")]
extern \\{
    static pcre_free: extern \"C\" fn(ptr: *c_void);

    fn pcre_compile(pattern: *c_char, options: options, errptr: *mut *c_char, erroffset: *mut c_int, tableptr: *c_uchar) -> *pcre;
    fn pcre_exec(code: *pcre, extra: *pcre_extra, subject: *c_char, length: c_int, startoffset: c_int, options: options, ovector: *mut c_int, ovecsize: c_int) -> c_int;
    fn pcre_version() -> *c_char;
\\}

fn main () \\{
    unsafe \\{
        let version_cstring = CString::new(pcre_version(), false);
        let version_str = version_cstring.as_str().unwrap().to_owned();

        let pattern = \"^\\\\\\\\d+\\\\\\\\.\\\\\\\\d+\";
        pattern.with_c_str(|pattern_c_str| \\{
            let mut err: *c_char = ptr::null();
            let mut erroffset: c_int = 0;
            let code = pcre_compile(pattern_c_str, 0, &mut err, &mut erroffset, ptr::null());
            if ptr::is_null(code) \\{
                if ptr::is_null(code) \\{
                    let err_cstring = CString::new(err, false);
                    match err_cstring.as_str() \\{
                        None          => fail!(\"pcre_compile() failed at offset \\{\\}\", erroffset as uint),
                        Some(err_str) => fail!(\"pcre_compile() failed at offset \\{\\}: \\{\\}\", erroffset as uint, err_str)
                    \\}
                \\}
            \\}
            assert!(ptr::is_not_null(code));

            let ovecsize = 1 * 3;
            let mut ovector: ~[c_int] = vec::from_elem(ovecsize, 0 as c_int);
            version_str.with_c_str_unchecked(|version_c_str| \\{
                let rc = pcre_exec(code, ptr::null(), version_c_str, version_str.len() as c_int, 0, 0, ovector.as_mut_ptr(), ovecsize as c_int);
                if rc < 0 \\{
                    fail!(\"pcre_exec() failed\");
                \\}

                print!(\"\\{\\}\", version_str.slice_to(ovector[1] as uint));
            \\});

            pcre_free(code as *c_void);
        \\});
    \\}
\\}
");
    }

    // Compile and run `versioncheck.rs`
    cd(&out_path);
    let rustc_run_output = run::process_output("rustc", [~"versioncheck.rs", ~"-L", pcre_lib_path.display().to_str()]).expect("failed to exec `rustc`");
    if !rustc_run_output.status.success() {
        println!("{}", str::from_utf8(rustc_run_output.output));
        println!("{}", str::from_utf8(rustc_run_output.error));
        fail!("Package script error: `rustc versioncheck.rs` failed: {}", rustc_run_output.status);
    }
    let version_check_output = run::process_output("./versioncheck", []).expect("failed to exec `./versioncheck`");
    if !version_check_output.status.success() {
        println!("{}", str::from_utf8(version_check_output.output));
        println!("{}", str::from_utf8(version_check_output.error));
        fail!("versioncheck error: {}", version_check_output.status);
    }
    cd(&workspace_path);

    let output_ptr = version_check_output.output.as_ptr();
    let output_len = version_check_output.output.len();
    let output_str = unsafe { str::raw::from_buf_len(output_ptr, output_len) };
    debug!("output_str = `{}`", output_str);

    // The "no debug symbols in executable" warning may be present in the output.
    // https://github.com/mozilla/rust/issues/3495
    let mut output_rsplit_iter = output_str.rsplit('\n');
    let version_str: ~str = match output_rsplit_iter.next() {
        None              => output_str.clone(),
        Some(version_str) => version_str.to_owned()
    };

    debug!("libpcre version {:s}", version_str);

    let min_required_version = Version::parse("8.20").unwrap();
    let pcre_version = match Version::parse(version_str) {
        None               => fail!("Package script error: Failed to parse version string '{}'", version_str),
        Some(pcre_version) => pcre_version
    };

    if pcre_version < min_required_version {
        fail!("Package script error: Found libpcre version {}, but at least version {} is required", version_str, min_required_version.to_str());
    }

    // Create directories `bin` and `lib`
    let bin_path = workspace_path.join("bin");
    if !bin_path.exists() {
        if !io::result(|| mkdir(&bin_path, 0x1FF)).is_ok() {
            fail!("Package script error: Failed to create the `bin` directory");
        }
    }
    let lib_path = workspace_path.join("lib");
    if !lib_path.exists() {
        if !io::result(|| mkdir(&lib_path, 0x1FF)).is_ok() {
            fail!("Package script error: Failed to create the `lib` directory");
        }
    }

    // Compile libpcre-*.rlib
    run::process_output("rustc", [~"--out-dir", lib_path.display().to_str(), ~"src/pcre/mod.rs", ~"-L", pcre_lib_path.display().to_str()]);

    run::process_output("rustc", [~"-o", bin_path.join("pcredemo").display().to_str(), ~"src/pcredemo/main.rs", ~"-L", ~"lib", ~"-L", pcre_lib_path.display().to_str()]);
}
<commit_msg>Update for io::io_error being removed<commit_after>// Copyright 2014 The rust-pcre authors.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern mod rustc;

use rustc::driver::driver::host_triple;
use std::from_str::{from_str};
use std::io;
use std::io::fs::{mkdir, File};
use std::option::{Option};
use std::os;
use std::run;
use std::str;

struct Version {
    major: uint,
    minor: uint
}

impl Version {
    pub fn parse(version_str: &str) -> Option<Version> {
        let mut it = version_str.split('.');
        match (it.next().and_then(from_str::<uint>), it.next().and_then(from_str::<uint>)) {
            (Some(major), Some(minor)) => Some(Version { major: major, minor: minor }),
            _                          => None
        }
    }
}

impl ToStr for Version {
    fn to_str(&self) -> ~str {
        format!("{:u}.{:u}", self.major, self.minor)
    }
}

impl Ord for Version {
    fn lt(&self, other: &Version) -> bool {
        self.major < other.major || (self.major == other.major && self.minor < other.minor)
    }
}

fn cd(path: &Path) {
    if !os::change_dir(path) {
        fail!("Package script error: Failed to `cd` into `{}`", path.display());
    }
}

fn main() {
    let pcre_libdir = match os::getenv("PCRE_LIBDIR") {
        None            => {
            let pcre_config_output = match run::process_output("pcre-config", [~"--prefix"]) {
                Err(e) => {
                    match e.kind {
                        io::FileNotFound => fail!("Package script error: Could not run `pcre-config` because no such executable is in the executable search PATH. Make sure that you have installed a dev package for libpcre and/or make sure that libpcre's bindir is added to your PATH (currently \"{}\").", os::getenv("PATH").unwrap_or(~"")),
                        _ => fail!("Package script error: Could not run `pcre-config`: {}", e.to_str())
                    }
                },
                Ok(pcre_config_output) => pcre_config_output
            };
            if !pcre_config_output.status.success() {
                fail!("Package script error: `pcre-config --prefix` failed");
            }
            let output_ptr = pcre_config_output.output.as_ptr();
            let output_len = pcre_config_output.output.len();
            let prefix_str = unsafe { str::raw::from_buf_len(output_ptr, output_len) };
            // `pcre-config` adds a newline to the end, which we need to trim away.
            prefix_str.trim() + "/lib"
        },
        Some(pcre_libdir) => pcre_libdir
    };
    let pcre_lib_path = Path::new(pcre_libdir);

    let workspace_path = os::getcwd();

    // Check the version
    let target_build_path = workspace_path.join("build").join(host_triple());
    if !target_build_path.exists() {
        if mkdir(&target_build_path, 0x1FF).is_err() {
            fail!("Package script error: Failed to create target build directory `{}`", target_build_path.display());
        }
    }
    let out_path = target_build_path.join("pcre");
    if !out_path.exists() {
        if mkdir(&out_path, 0x1FF).is_err() {
            fail!("Package script error: Failed to create output directory `{}`", out_path.display());
        }
    }

    let versioncheck_rs_path = out_path.join("versioncheck.rs");
    {
        let mut f = match File::create(&versioncheck_rs_path) {
            Err(e) => fail!("Package script error: Failed to open `{}` for writing: {:s}", versioncheck_rs_path.display(), e.to_str()),
            Ok(f) => f
        };
        let contents = format!("\
use std::c_str::\\{CString\\};
use std::libc::\\{c_char, c_int, c_uchar, c_void\\};
use std::ptr;
use std::vec;

type options = c_int;
struct pcre;
struct pcre_extra;

\\#[link(name = \"pcre\")]
extern \\{
    static pcre_free: extern \"C\" fn(ptr: *c_void);

    fn pcre_compile(pattern: *c_char, options: options, errptr: *mut *c_char, erroffset: *mut c_int, tableptr: *c_uchar) -> *pcre;
    fn pcre_exec(code: *pcre, extra: *pcre_extra, subject: *c_char, length: c_int, startoffset: c_int, options: options, ovector: *mut c_int, ovecsize: c_int) -> c_int;
    fn pcre_version() -> *c_char;
\\}

fn main () \\{
    unsafe \\{
        let version_cstring = CString::new(pcre_version(), false);
        let version_str = version_cstring.as_str().unwrap().to_owned();

        let pattern = \"^\\\\\\\\d+\\\\\\\\.\\\\\\\\d+\";
        pattern.with_c_str(|pattern_c_str| \\{
            let mut err: *c_char = ptr::null();
            let mut erroffset: c_int = 0;
            let code = pcre_compile(pattern_c_str, 0, &mut err, &mut erroffset, ptr::null());
            if ptr::is_null(code) \\{
                if ptr::is_null(code) \\{
                    let err_cstring = CString::new(err, false);
                    match err_cstring.as_str() \\{
                        None          => fail!(\"pcre_compile() failed at offset \\{\\}\", erroffset as uint),
                        Some(err_str) => fail!(\"pcre_compile() failed at offset \\{\\}: \\{\\}\", erroffset as uint, err_str)
                    \\}
                \\}
            \\}
            assert!(ptr::is_not_null(code));

            let ovecsize = 1 * 3;
            let mut ovector: ~[c_int] = vec::from_elem(ovecsize, 0 as c_int);
            version_str.with_c_str_unchecked(|version_c_str| \\{
                let rc = pcre_exec(code, ptr::null(), version_c_str, version_str.len() as c_int, 0, 0, ovector.as_mut_ptr(), ovecsize as c_int);
                if rc < 0 \\{
                    fail!(\"pcre_exec() failed\");
                \\}

                print!(\"\\{\\}\", version_str.slice_to(ovector[1] as uint));
            \\});

            pcre_free(code as *c_void);
        \\});
    \\}
\\}
");
        f.write_str(contents).map_err(|e| -> () {
            fail!("Package script error: Failed to write to `{}`: {:s}", versioncheck_rs_path.display(), e.to_str());
        });
    }

    // Compile and run `versioncheck.rs`
    cd(&out_path);
    let rustc_output = match run::process_output("rustc", [~"versioncheck.rs", ~"-L", pcre_lib_path.display().to_str()]) {
        Err(e) => fail!("Package script error: Failed to run `rustc`: {:s}", e.to_str()),
        Ok(rustc_output) => rustc_output
    };
    if !rustc_output.status.success() {
        println!("{}", str::from_utf8(rustc_output.output));
        println!("{}", str::from_utf8(rustc_output.error));
        fail!("Package script error: `rustc versioncheck.rs` failed: {}", rustc_output.status);
    }
    let versioncheck_output = match run::process_output("./versioncheck", []) {
        Err(e) => fail!("Package script error: Failed to run `./versioncheck`: {:s}", e.to_str()),
        Ok(versioncheck_output) => versioncheck_output
    };
    if !versioncheck_output.status.success() {
        println!("{}", str::from_utf8(versioncheck_output.output));
        println!("{}", str::from_utf8(versioncheck_output.error));
        fail!("versioncheck error: {}", versioncheck_output.status);
    }
    cd(&workspace_path);

    let output_ptr = versioncheck_output.output.as_ptr();
    let output_len = versioncheck_output.output.len();
    let output_str = unsafe { str::raw::from_buf_len(output_ptr, output_len) };
    debug!("output_str = `{}`", output_str);

    // The "no debug symbols in executable" warning may be present in the output.
    // https://github.com/mozilla/rust/issues/3495
    let mut output_rsplit_iter = output_str.rsplit('\n');
    let version_str: ~str = match output_rsplit_iter.next() {
        None              => output_str.clone(),
        Some(version_str) => version_str.to_owned()
    };

    debug!("libpcre version {:s}", version_str);

    let min_required_version = Version::parse("8.20").unwrap();
    let pcre_version = match Version::parse(version_str) {
        None               => fail!("Package script error: Failed to parse version string '{}'", version_str),
        Some(pcre_version) => pcre_version
    };

    if pcre_version < min_required_version {
        fail!("Package script error: Found libpcre version {}, but at least version {} is required", version_str, min_required_version.to_str());
    }

    // Create directories `bin` and `lib`
    let bin_path = workspace_path.join("bin");
    if !bin_path.exists() {
        if mkdir(&bin_path, 0x1FF).is_err() {
            fail!("Package script error: Failed to create the `bin` directory");
        }
    }
    let lib_path = workspace_path.join("lib");
    if !lib_path.exists() {
        if mkdir(&lib_path, 0x1FF).is_err() {
            fail!("Package script error: Failed to create the `lib` directory");
        }
    }

    // Compile libpcre-*.rlib
    match run::process_output("rustc", [~"--out-dir", lib_path.display().to_str(), ~"src/pcre/mod.rs", ~"-L", pcre_lib_path.display().to_str()]) {
        Err(e) => fail!("Package script error: Failed to run `rustc`: {:s}", e.to_str()),
        Ok(rustc_output) => {
            if !rustc_output.status.success() {
                println!("{}", str::from_utf8(rustc_output.output));
                println!("{}", str::from_utf8(rustc_output.error));
                fail!("Package script error: `rustc src/pcre/mod.rs` failed: {}", rustc_output.status);
            }
        }
    }

    match run::process_output("rustc", [~"-o", bin_path.join("pcredemo").display().to_str(), ~"src/pcredemo/main.rs", ~"-L", ~"lib", ~"-L", pcre_lib_path.display().to_str()]) {
        Err(e) => fail!("Package script error: Failed to run `rustc`: {:s}", e.to_str()),
        Ok(rustc_output) => {
            if !rustc_output.status.success() {
                println!("{}", str::from_utf8(rustc_output.output));
                println!("{}", str::from_utf8(rustc_output.error));
                fail!("Package script error: `rustc src/pcredemo/main.rs` failed: {}", rustc_output.status);
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 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.

use std::collections::VecDeque;
use std::net::SocketAddr;
use std::sync::{Arc, RwLock};

use futures::Future;
use rand::Rng;
use rand::os::OsRng;
use tokio_core::net::TcpStream;

use core::core::target::Difficulty;
use core::ser;
use msg::*;
use types::*;
use protocol::ProtocolV1;
use util::LOGGER;

const NONCES_CAP: usize = 100;

/// Handles the handshake negotiation when two peers connect and decides on
/// protocol.
pub struct Handshake {
	/// Ring buffer of nonces sent to detect self connections without requiring
	/// a node id.
	nonces: Arc<RwLock<VecDeque<u64>>>,
}

unsafe impl Sync for Handshake {}
unsafe impl Send for Handshake {}

impl Handshake {
	/// Creates a new handshake handler
	pub fn new() -> Handshake {
		Handshake {
			nonces: Arc::new(RwLock::new(VecDeque::with_capacity(NONCES_CAP))),
		}
	}

	/// Handles connecting to a new remote peer, starting the version handshake.
	pub fn connect(
		&self,
		capab: Capabilities,
		total_difficulty: Difficulty,
		self_addr: SocketAddr,
		conn: TcpStream,
	) -> Box<Future<Item = (TcpStream, ProtocolV1, PeerInfo), Error = Error>> {
		// prepare the first part of the hanshake
		let nonce = self.next_nonce();
		let hand = Hand {
			version: PROTOCOL_VERSION,
			capabilities: capab,
			nonce: nonce,
			total_difficulty: total_difficulty,
			sender_addr: SockAddr(self_addr),
			receiver_addr: SockAddr(conn.peer_addr().unwrap()),
			user_agent: USER_AGENT.to_string(),
		};

		// write and read the handshake response
		Box::new(
			write_msg(conn, hand, Type::Hand)
				.and_then(|conn| read_msg::<Shake>(conn))
				.and_then(|(conn, shake)| {
					if shake.version != 1 {
						Err(Error::Serialization(ser::Error::UnexpectedData {
							expected: vec![PROTOCOL_VERSION as u8],
							received: vec![shake.version as u8],
						}))
					} else {
						let peer_info = PeerInfo {
							capabilities: shake.capabilities,
							user_agent: shake.user_agent,
							addr: conn.peer_addr().unwrap(),
							version: shake.version,
							total_difficulty: shake.total_difficulty,
						};

						info!(LOGGER, "Connected to peer {:?}", peer_info);
						// when more than one protocol version is supported, choosing should go here
						Ok((conn, ProtocolV1::new(), peer_info))
					}
				}),
		)
	}

	/// Handles receiving a connection from a new remote peer that started the
	/// version handshake.
	pub fn handshake(
		&self,
		capab: Capabilities,
		total_difficulty: Difficulty,
		conn: TcpStream,
	) -> Box<Future<Item = (TcpStream, ProtocolV1, PeerInfo), Error = Error>> {
		let nonces = self.nonces.clone();
		Box::new(
			read_msg::<Hand>(conn)
				.and_then(move |(conn, hand)| {
					if hand.version != 1 {
						return Err(Error::Serialization(ser::Error::UnexpectedData {
							expected: vec![PROTOCOL_VERSION as u8],
							received: vec![hand.version as u8],
						}));
					}
					{
						// check the nonce to see if we could be trying to connect to ourselves
						let nonces = nonces.read().unwrap();
						if nonces.contains(&hand.nonce) {
							return Err(Error::Serialization(ser::Error::UnexpectedData {
								expected: vec![],
								received: vec![],
							}));
						}
					}

					// all good, keep peer info
					let peer_info = PeerInfo {
						capabilities: hand.capabilities,
						user_agent: hand.user_agent,
						addr: extract_ip(&hand.sender_addr.0, &conn),
						version: hand.version,
						total_difficulty: hand.total_difficulty,
					};
					// send our reply with our info
					let shake = Shake {
						version: PROTOCOL_VERSION,
						capabilities: capab,
						total_difficulty: total_difficulty,
						user_agent: USER_AGENT.to_string(),
					};
					Ok((conn, shake, peer_info))
				})
				.and_then(|(conn, shake, peer_info)| {
					debug!(LOGGER, "Success handshake with {}.", peer_info.addr);
					write_msg(conn, shake, Type::Shake)
				  // when more than one protocol version is supported, choosing should go here
					.map(|conn| (conn, ProtocolV1::new(), peer_info))
				}),
		)
	}

	/// Generate a new random nonce and store it in our ring buffer
	fn next_nonce(&self) -> u64 {
		let mut rng = OsRng::new().unwrap();
		let nonce = rng.next_u64();

		let mut nonces = self.nonces.write().unwrap();
		nonces.push_back(nonce);
		if nonces.len() >= NONCES_CAP {
			nonces.pop_front();
		}
		nonce
	}
}

// Attempts to make a best guess at the correct remote IP by checking if the
// advertised address is the loopback and our TCP connection. Note that the
// port reported by the connection is always incorrect for receiving
// connections as it's dynamically allocated by the server.
fn extract_ip(advertised: &SocketAddr, conn: &TcpStream) -> SocketAddr {
  match advertised {
    &SocketAddr::V4(v4sock) => {
      if v4sock.ip().is_loopback() {
        if let Ok(addr) =  conn.peer_addr() {
          return SocketAddr::new(addr.ip(), advertised.port());
        }
      }
    }
    &SocketAddr::V6(v6sock) => {
      if v6sock.ip().is_loopback() {
        if let Ok(addr) =  conn.peer_addr() {
          return SocketAddr::new(addr.ip(), advertised.port());
        }
      }
    }
  }
  advertised.clone()
}
<commit_msg>Detect unspecified IP and use TCP conn IP instead<commit_after>// Copyright 2016 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.

use std::collections::VecDeque;
use std::net::SocketAddr;
use std::sync::{Arc, RwLock};

use futures::Future;
use rand::Rng;
use rand::os::OsRng;
use tokio_core::net::TcpStream;

use core::core::target::Difficulty;
use core::ser;
use msg::*;
use types::*;
use protocol::ProtocolV1;
use util::LOGGER;

const NONCES_CAP: usize = 100;

/// Handles the handshake negotiation when two peers connect and decides on
/// protocol.
pub struct Handshake {
	/// Ring buffer of nonces sent to detect self connections without requiring
	/// a node id.
	nonces: Arc<RwLock<VecDeque<u64>>>,
}

unsafe impl Sync for Handshake {}
unsafe impl Send for Handshake {}

impl Handshake {
	/// Creates a new handshake handler
	pub fn new() -> Handshake {
		Handshake {
			nonces: Arc::new(RwLock::new(VecDeque::with_capacity(NONCES_CAP))),
		}
	}

	/// Handles connecting to a new remote peer, starting the version handshake.
	pub fn connect(
		&self,
		capab: Capabilities,
		total_difficulty: Difficulty,
		self_addr: SocketAddr,
		conn: TcpStream,
	) -> Box<Future<Item = (TcpStream, ProtocolV1, PeerInfo), Error = Error>> {
		// prepare the first part of the hanshake
		let nonce = self.next_nonce();
		let hand = Hand {
			version: PROTOCOL_VERSION,
			capabilities: capab,
			nonce: nonce,
			total_difficulty: total_difficulty,
			sender_addr: SockAddr(self_addr),
			receiver_addr: SockAddr(conn.peer_addr().unwrap()),
			user_agent: USER_AGENT.to_string(),
		};

		// write and read the handshake response
		Box::new(
			write_msg(conn, hand, Type::Hand)
				.and_then(|conn| read_msg::<Shake>(conn))
				.and_then(|(conn, shake)| {
					if shake.version != 1 {
						Err(Error::Serialization(ser::Error::UnexpectedData {
							expected: vec![PROTOCOL_VERSION as u8],
							received: vec![shake.version as u8],
						}))
					} else {
						let peer_info = PeerInfo {
							capabilities: shake.capabilities,
							user_agent: shake.user_agent,
							addr: conn.peer_addr().unwrap(),
							version: shake.version,
							total_difficulty: shake.total_difficulty,
						};

						info!(LOGGER, "Connected to peer {:?}", peer_info);
						// when more than one protocol version is supported, choosing should go here
						Ok((conn, ProtocolV1::new(), peer_info))
					}
				}),
		)
	}

	/// Handles receiving a connection from a new remote peer that started the
	/// version handshake.
	pub fn handshake(
		&self,
		capab: Capabilities,
		total_difficulty: Difficulty,
		conn: TcpStream,
	) -> Box<Future<Item = (TcpStream, ProtocolV1, PeerInfo), Error = Error>> {
		let nonces = self.nonces.clone();
		Box::new(
			read_msg::<Hand>(conn)
				.and_then(move |(conn, hand)| {
					if hand.version != 1 {
						return Err(Error::Serialization(ser::Error::UnexpectedData {
							expected: vec![PROTOCOL_VERSION as u8],
							received: vec![hand.version as u8],
						}));
					}
					{
						// check the nonce to see if we could be trying to connect to ourselves
						let nonces = nonces.read().unwrap();
						if nonces.contains(&hand.nonce) {
							return Err(Error::Serialization(ser::Error::UnexpectedData {
								expected: vec![],
								received: vec![],
							}));
						}
					}

					// all good, keep peer info
					let peer_info = PeerInfo {
						capabilities: hand.capabilities,
						user_agent: hand.user_agent,
						addr: extract_ip(&hand.sender_addr.0, &conn),
						version: hand.version,
						total_difficulty: hand.total_difficulty,
					};
					// send our reply with our info
					let shake = Shake {
						version: PROTOCOL_VERSION,
						capabilities: capab,
						total_difficulty: total_difficulty,
						user_agent: USER_AGENT.to_string(),
					};
					Ok((conn, shake, peer_info))
				})
				.and_then(|(conn, shake, peer_info)| {
					debug!(LOGGER, "Success handshake with {}.", peer_info.addr);
					write_msg(conn, shake, Type::Shake)
				  // when more than one protocol version is supported, choosing should go here
					.map(|conn| (conn, ProtocolV1::new(), peer_info))
				}),
		)
	}

	/// Generate a new random nonce and store it in our ring buffer
	fn next_nonce(&self) -> u64 {
		let mut rng = OsRng::new().unwrap();
		let nonce = rng.next_u64();

		let mut nonces = self.nonces.write().unwrap();
		nonces.push_back(nonce);
		if nonces.len() >= NONCES_CAP {
			nonces.pop_front();
		}
		nonce
	}
}

// Attempts to make a best guess at the correct remote IP by checking if the
// advertised address is the loopback and our TCP connection. Note that the
// port reported by the connection is always incorrect for receiving
// connections as it's dynamically allocated by the server.
fn extract_ip(advertised: &SocketAddr, conn: &TcpStream) -> SocketAddr {
  match advertised {
    &SocketAddr::V4(v4sock) => {
      let ip = v4sock.ip();
      if ip.is_loopback() || ip.is_unspecified() {
        if let Ok(addr) =  conn.peer_addr() {
          return SocketAddr::new(addr.ip(), advertised.port());
        }
      }
    }
    &SocketAddr::V6(v6sock) => {
      let ip = v6sock.ip();
      if ip.is_loopback() || ip.is_unspecified() {
        if let Ok(addr) =  conn.peer_addr() {
          return SocketAddr::new(addr.ip(), advertised.port());
        }
      }
    }
  }
  advertised.clone()
}
<|endoftext|>


<commit_before>use std::util;
use std::uint;
use std::num::{Zero, One};
use std::iterator::IteratorUtil;
use std::vec;
use extra::treemap::TreeMap;
use nalgebra::traits::norm::Norm;
use nalgebra::traits::division_ring::DivisionRing;
use nalgebra::traits::dim::Dim;
use nalgebra::traits::sub_dot::SubDot;
use nalgebra::traits::scalar_op::{ScalarMul, ScalarDiv};
use narrow::algorithm::simplex::Simplex;

#[deriving(Eq, ToStr, Clone)]
pub struct JohnsonSimplex<V, N>
{
  priv points:              ~[V],
  priv exchange_points:     ~[V],
  priv cofactors:           ~[N]
}

#[deriving(Eq, Clone)]
struct RecursionTemplate
{
  permutation_list: ~[uint],
  offsets:          ~[uint],
  sub_cofactors:    ~[uint],
  num_cofactors:    uint,
  num_leaves:       uint // useful only for printing…
}

// XXX: we use an Either instead of an Option since the compiler will generate
// something buggy with Option.
// static mut templates: Option<~[RecursionTemplate]> = None;
// FIXME: wont work with concurency…
static mut templates: Either<int, ~[RecursionTemplate]> = Left(42);

impl<V: Clone         +
        SubDot<N>    +
        ScalarMul<N> +
        ScalarDiv<N> +
        Zero         +
        Add<V, V>    +
        Dim,
     N: Ord          +
        Clone        +
        Copy         + // FIXME: needed?
        Eq           +
        DivisionRing +
        Ord          +
        Bounded>
JohnsonSimplex<V, N>
{
  pub fn new(initial_point: V) -> JohnsonSimplex<V, N>
  {
    let _dim       = Dim::dim::<V>();
    let expoints   = vec::with_capacity(_dim);
    let mut points = vec::with_capacity(_dim);

    JohnsonSimplex::make_permutation_lists::<V, N>();

    points.push(initial_point);

    let res = JohnsonSimplex {
      points:            points
      , exchange_points: expoints
      , cofactors:       vec::from_elem(
        unsafe {
          match templates
          {
            Right(ref mut l) => l[_dim].num_cofactors,
            Left(_)          => fail!("Recursion template was not intialized.")
          }
        }, Zero::zero())
    };

    res
  }

  fn make_permutation_lists()
  {
    unsafe {
      if templates.is_left()
      { templates = Right(~[]) }

      match templates
      {
        Left(_) => fail!("There seem to be a compiler error for the implementation" +
                         " of mutable static variables."),
        Right(ref mut t) =>
          for uint::iterate(t.len(), Dim::dim::<V>() + 1u) |dim|
          {
            t.push(JohnsonSimplex::make_permutation_list::<V, N>(dim));

            println("Recursion template for dimension: " + dim.to_str());
            println(t[t.len() - 1].to_str());
          }
      }
    }
  }

  // This is the tricky part of the algorithm. This generates all datas needed
  // to run the johson subalgorithm fastly. This should _not_ be run every time
  // the algorithm is executed. Instead, it should be pre-computed, or computed
  // only once for all. The resulting GC-managed list is intented to be shared
  // between all other simplicis with the same dimension.
  fn make_permutation_list(dim: uint) -> RecursionTemplate
  {
    // FIXME: the permutation list should be computed once for all, at compile
    // time. I dont know how to do that though…

    // The number of points on the biggest subsimplex
    let max_num_points      = dim + 1;

    let mut pts             = ~[]; // the result
    let mut offsets         = ~[];
    let mut sub_cofactors   = ~[];

    // the beginning of the last subsimplices list
    let mut last_dim_begin  = 0;

    // the end of the last subsimplices list
    let mut last_dim_end    = dim + 1 + 1;

    // the number of points of the last subsimplices
    let mut last_num_points = dim + 1;

    let mut map             = TreeMap::new::<~[uint], uint>();

    let mut cofactor_index  = 0;

    for uint::iterate(0, max_num_points) |i|
    { pts.push(i) }

    // initially push the whole simplex (will be removed at the end)
    pts.push(0);

    offsets.push(max_num_points + 1);

    // ... then remove one point each time
    for uint::iterate(0, dim + 1) |i|
    {
      // for each sub-simplex ...
      let mut curr      = last_dim_begin;
      let mut num_added = 0;

      while (curr != last_dim_end)
      {
        // ... iterate on it ...
        for uint::iterate(0, last_num_points) |j|
        {
          // ... and build all the sublist with one last point
          let mut sublist = ~[];

          // then extract the sub-simplex
          for uint::iterate(0, last_num_points) |k|
          {
            // we remove the j'th point
            if pts[curr + j] != pts[curr + k]
            { sublist.push(pts[curr + k]); }
          }

          // keep a trace of the removed point
          sublist.push(pts[curr + j]);

          match map.find(&sublist)
          {
            Some(&v) => sub_cofactors.push(v),
            None     => {
                          for sublist.iter().advance |&e|
                          {
                            pts.push(e);
                            num_added = num_added + 1;
                          }
                          sub_cofactors.push(cofactor_index);
                          map.insert(sublist, cofactor_index);
                          cofactor_index = cofactor_index + 1;
                        }
          }
        }

        let mut parent = ~[];
        for uint::iterate(0, last_num_points + 1) |k|
        { parent.push(pts[curr + k]) }

        match map.find(&parent)
        {
          Some(&p) => sub_cofactors.push(p),
          None => {
            sub_cofactors.push(cofactor_index);
            // There is no need to keep a place for the full simplex cofactor.
            // So we dont increase the cofactor buffer index for the first
            // iteration.
            cofactor_index = cofactor_index + if i == 0 { 0 } else { 1 };
          }
        }

        curr = curr + last_num_points + 1;
      }

      // initialize the next iteration with one less point
      last_dim_begin = last_dim_end ;
      last_dim_end = last_dim_end + num_added;
      offsets.push(last_dim_end);
      last_num_points = last_num_points - 1;
    }

    // cofactor indices for leaves
    for uint::iterate(0, max_num_points) |i|
    { sub_cofactors.push(*map.find(&~[max_num_points - 1 - i]).unwrap()) }

    // end to begin offsets
    offsets.unshift(0u);
    offsets.reverse();
    offsets.pop();

    let rev_offsets = offsets.map(|&e| pts.len() - e);
    let num_leaves = rev_offsets[0];

    // reverse points and cofectors
    pts.reverse();
    sub_cofactors.reverse();

    // remove the full simplex
    let num_pts = pts.len();
    pts.truncate(num_pts - max_num_points - 1);
    sub_cofactors.truncate(num_pts - max_num_points - 1);

    RecursionTemplate {
      offsets:          rev_offsets,
      permutation_list: pts,
      num_cofactors:    sub_cofactors[0] + 1,
      sub_cofactors:    sub_cofactors,
      num_leaves:       num_leaves
    }
  }

  pub fn reset(&mut self, pt: V)
  {
    self.points.clear();
    self.points.push(pt);
  }

  fn do_project_origin(&mut self, reduce: bool) -> V
  {
    // FIXME: for optimization: do special case when there are only 1 point ?
    let _0                   = Zero::zero::<N>();
    let _1                   = One::one::<N>();
    let max_num_pts          = self.points.len();
    let recursion            =
      unsafe {
        match templates
        {
          Left(_) => fail!("There seem to be a compiler error for the implementation" +
                        " of mutable static variables."),
          Right(ref mut t) => &t[max_num_pts - 1]
        }
      };
    let mut curr_num_pts     = 1u;
    let mut curr             = max_num_pts;

    for uint::iterate(0u, max_num_pts) |i|
    { self.cofactors[recursion.num_cofactors - 1 - i] = _1.clone(); }

    /*
     * first loop: compute all the cofactors
     */
    let mut recursion_offsets_skip_2 = recursion.offsets.iter();
    recursion_offsets_skip_2.next(); // Skip the two first entries
    recursion_offsets_skip_2.next();
    for recursion_offsets_skip_2.advance |&end|
    {
      // for each sub-simplex ...
      let mut _i = curr;
      while (_i != end)
      {
        let mut cofactor = Zero::zero::<N>();
        let j_pid        = recursion.permutation_list[curr];
        let k_pid        = recursion.permutation_list[curr + 1u];

        // ... with curr_num_pts points ...
        for uint::iterate(0u, curr_num_pts) |i|
        {
          // ... compute its cofactor.
          let i_pid        = recursion.permutation_list[curr + 1 + i];
          let sub_cofactor = self.cofactors[recursion.sub_cofactors[curr + 1 + i]].clone();
          let delta = sub_cofactor *
                      self.points[k_pid].sub_dot(&self.points[j_pid],
                                                 &self.points[i_pid]);

          cofactor = cofactor + delta;
        }

        self.cofactors[recursion.sub_cofactors[curr]] = cofactor;
        curr = curr + curr_num_pts + 1; // points + removed point + cofactor id

        _i = _i + curr_num_pts + 1;
      }

      curr_num_pts = curr_num_pts + 1;
    }

    /*
     * second loop: find the subsimplex containing the projection
     */
    let _invalid_cofactor = Bounded::max_value::<N>();
    let mut offsets_iter = recursion.offsets.rev_iter();
    offsets_iter.next(); // skip the first offset
    for offsets_iter.advance |&end|
    {
      // for each sub-simplex ...
      let mut _i = curr;
      while (_i != end)
      {
        let mut foundit = true;
        // ... with curr_num_pts points permutations ...
        for uint::iterate(0u, curr_num_pts) |i|
        {
          // ... see if its cofactor is positive
          let cof_id = _i - (i + 1) * curr_num_pts;
          let cof    = self.cofactors[recursion.sub_cofactors[cof_id]].clone();
          if cof > _0
          {
            // invalidate the children cofactor
            if curr_num_pts > 1
            {
              let subcofid = recursion.sub_cofactors[cof_id + 1];

              if self.cofactors[subcofid] > _0
              { self.cofactors[subcofid] = _invalid_cofactor.clone() }
            }

            // dont concider this sub-simplex if it has been invalidated by its
            // parent(s)
            if cof == _invalid_cofactor
            { foundit = false }
          }
          else // we found a negative cofactor: no projection possible here
          { foundit = false }
        }

        if foundit
        {
          // we found a projection!
          // re-run the same iteration but, this time, compute the projection
          let mut total_cof = _0.clone();
          let mut proj      = Zero::zero::<V>();

          for uint::iterate(0u, curr_num_pts) |i|
          {
            // ... see if its cofactor is positive
            let id    = _i - (i + 1) * curr_num_pts;
            let cof   = self.cofactors[recursion.sub_cofactors[id]].clone();

            total_cof = total_cof + cof;
            proj = proj +
              self.points[recursion.permutation_list[id]].scalar_mul(&cof);
          }

          if reduce // we need to reduce the simplex
          {
            // FIXME: is it possible to do that without copy?
            // Maybe with some kind of cross-vector-swap?
            for uint::iterate(0u, curr_num_pts) |i|
            {
              let id = _i - (i + 1) * curr_num_pts;
              self.exchange_points.push(self.points[recursion.permutation_list[id]].clone());
            }

            util::swap(&mut self.exchange_points, &mut self.points);
            self.exchange_points.clear();
          }

          proj.scalar_div_inplace(&total_cof);

          return proj
        }

        _i = _i - curr_num_pts * curr_num_pts;
      }

      curr = end;
      curr_num_pts = curr_num_pts - 1;
    }

    util::unreachable();
  }
}

impl<V: Clone         +
        SubDot<N>    +
        ScalarMul<N> +
        ScalarDiv<N> +
        Zero         +
        Add<V, V>    +
        Norm<N>      +
        Eq           +
        Dim,
     N: Ord          +
        Clone        +
        Copy         + // FIXME: needed?
        Eq           +
        DivisionRing +
        Ord          +
        Bounded>
     Simplex<V, N> for JohnsonSimplex<V, N>
{
  pub fn new(initial_point: V) -> JohnsonSimplex<V, N>
  { JohnsonSimplex::new(initial_point) }

  pub fn dimension(&self) -> uint
  { self.points.len() - 1 }

  pub fn max_sq_len(&self) -> N
  { self.points.iter().transform(|v| v.sqnorm()).max().unwrap() }

  pub fn contains_point(&self, pt: &V) -> bool
  { self.points.iter().any_(|v| pt == v) }

  pub fn add_point(&mut self, pt: V)
  {
    assert!(self.points.len() <= Dim::dim::<V>());
    self.points.push(pt)
  }

  pub fn project_origin_and_reduce(&mut self) -> V
  { self.do_project_origin(true) }

  pub fn project_origin(&mut self) -> V
  { self.do_project_origin(false) }
}

impl ToStr for RecursionTemplate
{
  fn to_str(&self) -> ~str
  {
    let mut res  = ~"RecursionTemplate { ";
    let mut curr = self.num_leaves;
    let mut dim  = 1;

    res = res + "num_cofactors: " + self.num_cofactors.to_str();

    let mut recursion_offsets_skip_1 = self.offsets.iter();
    recursion_offsets_skip_1.next(); // Skip the two first entries

    for recursion_offsets_skip_1.advance |&off|
    {
      while (curr != off)
      {
        res = res + "\n(@" + self.sub_cofactors[curr].to_str() + " -> ";

        for uint::iterate(0u, dim) |i|
        {
          res = res + self.permutation_list[i + curr].to_str();
          if i != dim - 1
          { res = res + " "; }
        }

        res = res + " - ";

        for uint::iterate(1u, dim) |i|
        {
          res = res + self.sub_cofactors[i + curr].to_str();
          if i != dim - 1
          { res = res + " "; }
        }

        res  = res + ")";
        curr = curr + dim;
      }

      dim += 1;
    }

    res = res + " }\n";

    res = res + "offsets: " + self.offsets.to_str();

    res
  }
}
<commit_msg>Removed a debug println.<commit_after>use std::util;
use std::uint;
use std::num::{Zero, One};
use std::iterator::IteratorUtil;
use std::vec;
use extra::treemap::TreeMap;
use nalgebra::traits::norm::Norm;
use nalgebra::traits::division_ring::DivisionRing;
use nalgebra::traits::dim::Dim;
use nalgebra::traits::sub_dot::SubDot;
use nalgebra::traits::scalar_op::{ScalarMul, ScalarDiv};
use narrow::algorithm::simplex::Simplex;

#[deriving(Eq, ToStr, Clone)]
pub struct JohnsonSimplex<V, N>
{
  priv points:              ~[V],
  priv exchange_points:     ~[V],
  priv cofactors:           ~[N]
}

#[deriving(Eq, Clone)]
struct RecursionTemplate
{
  permutation_list: ~[uint],
  offsets:          ~[uint],
  sub_cofactors:    ~[uint],
  num_cofactors:    uint,
  num_leaves:       uint // useful only for printing…
}

// XXX: we use an Either instead of an Option since the compiler will generate
// something buggy with Option.
// static mut templates: Option<~[RecursionTemplate]> = None;
// FIXME: wont work with concurency…
static mut templates: Either<int, ~[RecursionTemplate]> = Left(42);

impl<V: Clone         +
        SubDot<N>    +
        ScalarMul<N> +
        ScalarDiv<N> +
        Zero         +
        Add<V, V>    +
        Dim,
     N: Ord          +
        Clone        +
        Copy         + // FIXME: needed?
        Eq           +
        DivisionRing +
        Ord          +
        Bounded>
JohnsonSimplex<V, N>
{
  pub fn new(initial_point: V) -> JohnsonSimplex<V, N>
  {
    let _dim       = Dim::dim::<V>();
    let expoints   = vec::with_capacity(_dim);
    let mut points = vec::with_capacity(_dim);

    JohnsonSimplex::make_permutation_lists::<V, N>();

    points.push(initial_point);

    let res = JohnsonSimplex {
      points:            points
      , exchange_points: expoints
      , cofactors:       vec::from_elem(
        unsafe {
          match templates
          {
            Right(ref mut l) => l[_dim].num_cofactors,
            Left(_)          => fail!("Recursion template was not intialized.")
          }
        }, Zero::zero())
    };

    res
  }

  fn make_permutation_lists()
  {
    unsafe {
      if templates.is_left()
      { templates = Right(~[]) }

      match templates
      {
        Left(_) => fail!("There seem to be a compiler error for the implementation" +
                         " of mutable static variables."),
        Right(ref mut t) =>
          for uint::iterate(t.len(), Dim::dim::<V>() + 1u) |dim|
          { t.push(JohnsonSimplex::make_permutation_list::<V, N>(dim)) }
      }
    }
  }

  // This is the tricky part of the algorithm. This generates all datas needed
  // to run the johson subalgorithm fastly. This should _not_ be run every time
  // the algorithm is executed. Instead, it should be pre-computed, or computed
  // only once for all. The resulting GC-managed list is intented to be shared
  // between all other simplicis with the same dimension.
  fn make_permutation_list(dim: uint) -> RecursionTemplate
  {
    // FIXME: the permutation list should be computed once for all, at compile
    // time. I dont know how to do that though…

    // The number of points on the biggest subsimplex
    let max_num_points      = dim + 1;

    let mut pts             = ~[]; // the result
    let mut offsets         = ~[];
    let mut sub_cofactors   = ~[];

    // the beginning of the last subsimplices list
    let mut last_dim_begin  = 0;

    // the end of the last subsimplices list
    let mut last_dim_end    = dim + 1 + 1;

    // the number of points of the last subsimplices
    let mut last_num_points = dim + 1;

    let mut map             = TreeMap::new::<~[uint], uint>();

    let mut cofactor_index  = 0;

    for uint::iterate(0, max_num_points) |i|
    { pts.push(i) }

    // initially push the whole simplex (will be removed at the end)
    pts.push(0);

    offsets.push(max_num_points + 1);

    // ... then remove one point each time
    for uint::iterate(0, dim + 1) |i|
    {
      // for each sub-simplex ...
      let mut curr      = last_dim_begin;
      let mut num_added = 0;

      while (curr != last_dim_end)
      {
        // ... iterate on it ...
        for uint::iterate(0, last_num_points) |j|
        {
          // ... and build all the sublist with one last point
          let mut sublist = ~[];

          // then extract the sub-simplex
          for uint::iterate(0, last_num_points) |k|
          {
            // we remove the j'th point
            if pts[curr + j] != pts[curr + k]
            { sublist.push(pts[curr + k]); }
          }

          // keep a trace of the removed point
          sublist.push(pts[curr + j]);

          match map.find(&sublist)
          {
            Some(&v) => sub_cofactors.push(v),
            None     => {
                          for sublist.iter().advance |&e|
                          {
                            pts.push(e);
                            num_added = num_added + 1;
                          }
                          sub_cofactors.push(cofactor_index);
                          map.insert(sublist, cofactor_index);
                          cofactor_index = cofactor_index + 1;
                        }
          }
        }

        let mut parent = ~[];
        for uint::iterate(0, last_num_points + 1) |k|
        { parent.push(pts[curr + k]) }

        match map.find(&parent)
        {
          Some(&p) => sub_cofactors.push(p),
          None => {
            sub_cofactors.push(cofactor_index);
            // There is no need to keep a place for the full simplex cofactor.
            // So we dont increase the cofactor buffer index for the first
            // iteration.
            cofactor_index = cofactor_index + if i == 0 { 0 } else { 1 };
          }
        }

        curr = curr + last_num_points + 1;
      }

      // initialize the next iteration with one less point
      last_dim_begin = last_dim_end ;
      last_dim_end = last_dim_end + num_added;
      offsets.push(last_dim_end);
      last_num_points = last_num_points - 1;
    }

    // cofactor indices for leaves
    for uint::iterate(0, max_num_points) |i|
    { sub_cofactors.push(*map.find(&~[max_num_points - 1 - i]).unwrap()) }

    // end to begin offsets
    offsets.unshift(0u);
    offsets.reverse();
    offsets.pop();

    let rev_offsets = offsets.map(|&e| pts.len() - e);
    let num_leaves = rev_offsets[0];

    // reverse points and cofectors
    pts.reverse();
    sub_cofactors.reverse();

    // remove the full simplex
    let num_pts = pts.len();
    pts.truncate(num_pts - max_num_points - 1);
    sub_cofactors.truncate(num_pts - max_num_points - 1);

    RecursionTemplate {
      offsets:          rev_offsets,
      permutation_list: pts,
      num_cofactors:    sub_cofactors[0] + 1,
      sub_cofactors:    sub_cofactors,
      num_leaves:       num_leaves
    }
  }

  pub fn reset(&mut self, pt: V)
  {
    self.points.clear();
    self.points.push(pt);
  }

  fn do_project_origin(&mut self, reduce: bool) -> V
  {
    // FIXME: for optimization: do special case when there are only 1 point ?
    let _0                   = Zero::zero::<N>();
    let _1                   = One::one::<N>();
    let max_num_pts          = self.points.len();
    let recursion            =
      unsafe {
        match templates
        {
          Left(_) => fail!("There seem to be a compiler error for the implementation" +
                        " of mutable static variables."),
          Right(ref mut t) => &t[max_num_pts - 1]
        }
      };
    let mut curr_num_pts     = 1u;
    let mut curr             = max_num_pts;

    for uint::iterate(0u, max_num_pts) |i|
    { self.cofactors[recursion.num_cofactors - 1 - i] = _1.clone(); }

    /*
     * first loop: compute all the cofactors
     */
    let mut recursion_offsets_skip_2 = recursion.offsets.iter();
    recursion_offsets_skip_2.next(); // Skip the two first entries
    recursion_offsets_skip_2.next();
    for recursion_offsets_skip_2.advance |&end|
    {
      // for each sub-simplex ...
      let mut _i = curr;
      while (_i != end)
      {
        let mut cofactor = Zero::zero::<N>();
        let j_pid        = recursion.permutation_list[curr];
        let k_pid        = recursion.permutation_list[curr + 1u];

        // ... with curr_num_pts points ...
        for uint::iterate(0u, curr_num_pts) |i|
        {
          // ... compute its cofactor.
          let i_pid        = recursion.permutation_list[curr + 1 + i];
          let sub_cofactor = self.cofactors[recursion.sub_cofactors[curr + 1 + i]].clone();
          let delta = sub_cofactor *
                      self.points[k_pid].sub_dot(&self.points[j_pid],
                                                 &self.points[i_pid]);

          cofactor = cofactor + delta;
        }

        self.cofactors[recursion.sub_cofactors[curr]] = cofactor;
        curr = curr + curr_num_pts + 1; // points + removed point + cofactor id

        _i = _i + curr_num_pts + 1;
      }

      curr_num_pts = curr_num_pts + 1;
    }

    /*
     * second loop: find the subsimplex containing the projection
     */
    let _invalid_cofactor = Bounded::max_value::<N>();
    let mut offsets_iter = recursion.offsets.rev_iter();
    offsets_iter.next(); // skip the first offset
    for offsets_iter.advance |&end|
    {
      // for each sub-simplex ...
      let mut _i = curr;
      while (_i != end)
      {
        let mut foundit = true;
        // ... with curr_num_pts points permutations ...
        for uint::iterate(0u, curr_num_pts) |i|
        {
          // ... see if its cofactor is positive
          let cof_id = _i - (i + 1) * curr_num_pts;
          let cof    = self.cofactors[recursion.sub_cofactors[cof_id]].clone();
          if cof > _0
          {
            // invalidate the children cofactor
            if curr_num_pts > 1
            {
              let subcofid = recursion.sub_cofactors[cof_id + 1];

              if self.cofactors[subcofid] > _0
              { self.cofactors[subcofid] = _invalid_cofactor.clone() }
            }

            // dont concider this sub-simplex if it has been invalidated by its
            // parent(s)
            if cof == _invalid_cofactor
            { foundit = false }
          }
          else // we found a negative cofactor: no projection possible here
          { foundit = false }
        }

        if foundit
        {
          // we found a projection!
          // re-run the same iteration but, this time, compute the projection
          let mut total_cof = _0.clone();
          let mut proj      = Zero::zero::<V>();

          for uint::iterate(0u, curr_num_pts) |i|
          {
            // ... see if its cofactor is positive
            let id    = _i - (i + 1) * curr_num_pts;
            let cof   = self.cofactors[recursion.sub_cofactors[id]].clone();

            total_cof = total_cof + cof;
            proj = proj +
              self.points[recursion.permutation_list[id]].scalar_mul(&cof);
          }

          if reduce // we need to reduce the simplex
          {
            // FIXME: is it possible to do that without copy?
            // Maybe with some kind of cross-vector-swap?
            for uint::iterate(0u, curr_num_pts) |i|
            {
              let id = _i - (i + 1) * curr_num_pts;
              self.exchange_points.push(self.points[recursion.permutation_list[id]].clone());
            }

            util::swap(&mut self.exchange_points, &mut self.points);
            self.exchange_points.clear();
          }

          proj.scalar_div_inplace(&total_cof);

          return proj
        }

        _i = _i - curr_num_pts * curr_num_pts;
      }

      curr = end;
      curr_num_pts = curr_num_pts - 1;
    }

    util::unreachable();
  }
}

impl<V: Clone         +
        SubDot<N>    +
        ScalarMul<N> +
        ScalarDiv<N> +
        Zero         +
        Add<V, V>    +
        Norm<N>      +
        Eq           +
        Dim,
     N: Ord          +
        Clone        +
        Copy         + // FIXME: needed?
        Eq           +
        DivisionRing +
        Ord          +
        Bounded>
     Simplex<V, N> for JohnsonSimplex<V, N>
{
  pub fn new(initial_point: V) -> JohnsonSimplex<V, N>
  { JohnsonSimplex::new(initial_point) }

  pub fn dimension(&self) -> uint
  { self.points.len() - 1 }

  pub fn max_sq_len(&self) -> N
  { self.points.iter().transform(|v| v.sqnorm()).max().unwrap() }

  pub fn contains_point(&self, pt: &V) -> bool
  { self.points.iter().any_(|v| pt == v) }

  pub fn add_point(&mut self, pt: V)
  {
    assert!(self.points.len() <= Dim::dim::<V>());
    self.points.push(pt)
  }

  pub fn project_origin_and_reduce(&mut self) -> V
  { self.do_project_origin(true) }

  pub fn project_origin(&mut self) -> V
  { self.do_project_origin(false) }
}

impl ToStr for RecursionTemplate
{
  fn to_str(&self) -> ~str
  {
    let mut res  = ~"RecursionTemplate { ";
    let mut curr = self.num_leaves;
    let mut dim  = 1;

    res = res + "num_cofactors: " + self.num_cofactors.to_str();

    let mut recursion_offsets_skip_1 = self.offsets.iter();
    recursion_offsets_skip_1.next(); // Skip the two first entries

    for recursion_offsets_skip_1.advance |&off|
    {
      while (curr != off)
      {
        res = res + "\n(@" + self.sub_cofactors[curr].to_str() + " -> ";

        for uint::iterate(0u, dim) |i|
        {
          res = res + self.permutation_list[i + curr].to_str();
          if i != dim - 1
          { res = res + " "; }
        }

        res = res + " - ";

        for uint::iterate(1u, dim) |i|
        {
          res = res + self.sub_cofactors[i + curr].to_str();
          if i != dim - 1
          { res = res + " "; }
        }

        res  = res + ")";
        curr = curr + dim;
      }

      dim += 1;
    }

    res = res + " }\n";

    res = res + "offsets: " + self.offsets.to_str();

    res
  }
}
<|endoftext|>


<commit_before>// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

extern crate libc;
extern crate utils;

use std::convert::TryInto;

use seccomp::{
    allow_syscall, allow_syscall_if, BpfProgram, Error, SeccompAction, SeccompCmpArgLen as ArgLen,
    SeccompCmpOp::Eq, SeccompCondition as Cond, SeccompError, SeccompFilter, SeccompLevel,
    SeccompRule,
};
use utils::signal::sigrtmin;

/// The default filter containing the white listed syscall rules required by `Firecracker` to
/// function.
pub fn default_filter() -> Result<SeccompFilter, Error> {
    Ok(SeccompFilter::new(
        vec![
            allow_syscall(libc::SYS_accept4),
            allow_syscall(libc::SYS_brk),
            allow_syscall(libc::SYS_clock_gettime),
            allow_syscall(libc::SYS_close),
            allow_syscall(libc::SYS_connect),
            allow_syscall(libc::SYS_dup),
            allow_syscall(libc::SYS_epoll_ctl),
            allow_syscall(libc::SYS_epoll_pwait),
            #[cfg(all(target_env = "gnu", target_arch = "x86_64"))]
            allow_syscall(libc::SYS_epoll_wait),
            allow_syscall(libc::SYS_exit),
            allow_syscall(libc::SYS_exit_group),
            allow_syscall_if(
                libc::SYS_fcntl,
                or![and![
                    Cond::new(1, ArgLen::DWORD, Eq, super::FCNTL_F_SETFD)?,
                    Cond::new(2, ArgLen::QWORD, Eq, super::FCNTL_FD_CLOEXEC)?,
                ]],
            ),
            allow_syscall(libc::SYS_fstat),
            #[cfg(target_arch = "x86_64")]
            allow_syscall(libc::SYS_ftruncate),
            allow_syscall_if(
                libc::SYS_futex,
                or![
                    and![Cond::new(1, ArgLen::DWORD, Eq, super::FUTEX_WAIT_PRIVATE)?],
                    and![Cond::new(1, ArgLen::DWORD, Eq, super::FUTEX_WAKE_PRIVATE)?],
                    and![Cond::new(
                        1,
                        ArgLen::DWORD,
                        Eq,
                        super::FUTEX_REQUEUE_PRIVATE
                    )?],
                    #[cfg(target_env = "gnu")]
                    and![Cond::new(
                        1,
                        ArgLen::DWORD,
                        Eq,
                        super::FUTEX_CMP_REQUEUE_PRIVATE
                    )?],
                ],
            ),
            allow_syscall(libc::SYS_getrandom),
            allow_syscall_if(libc::SYS_ioctl, super::create_ioctl_seccomp_rule()?),
            allow_syscall(libc::SYS_lseek),
            #[cfg(target_env = "musl")]
            allow_syscall_if(
                libc::SYS_madvise,
                or![and![Cond::new(
                    2,
                    ArgLen::DWORD,
                    Eq,
                    libc::MADV_DONTNEED as u64
                )?],],
            ),
            allow_syscall(libc::SYS_mmap),
            allow_syscall(libc::SYS_mremap),
            allow_syscall(libc::SYS_munmap),
            #[cfg(target_arch = "aarch64")]
            allow_syscall(libc::SYS_newfstatat),
            #[cfg(target_arch = "x86_64")]
            allow_syscall(libc::SYS_open),
            allow_syscall(libc::SYS_openat),
            #[cfg(target_arch = "x86_64")]
            allow_syscall(libc::SYS_pipe),
            allow_syscall(libc::SYS_read),
            allow_syscall(libc::SYS_readv),
            allow_syscall(libc::SYS_recvfrom),
            // SYS_rt_sigreturn is needed in case a fault does occur, so that the signal handler
            // can return. Otherwise we get stuck in a fault loop.
            allow_syscall(libc::SYS_rt_sigreturn),
            allow_syscall(libc::SYS_sigaltstack),
            allow_syscall_if(
                libc::SYS_socket,
                or![and![Cond::new(0, ArgLen::DWORD, Eq, libc::AF_UNIX as u64)?],],
            ),
            #[cfg(target_arch = "x86_64")]
            allow_syscall(libc::SYS_stat),
            allow_syscall_if(
                libc::SYS_tkill,
                or![and![Cond::new(
                    1,
                    ArgLen::DWORD,
                    Eq,
                    (sigrtmin() + super::super::vstate::VCPU_RTSIG_OFFSET) as u64
                )?]],
            ),
            allow_syscall(libc::SYS_timerfd_create),
            allow_syscall(libc::SYS_timerfd_settime),
            allow_syscall(libc::SYS_write),
            allow_syscall(libc::SYS_writev),
        ]
        .into_iter()
        .collect(),
        SeccompAction::Trap,
    )?)
}

/// Generate a BPF program based on a seccomp level value.
pub fn get_seccomp_filter(seccomp_level: SeccompLevel) -> Result<BpfProgram, SeccompError> {
    match seccomp_level {
        SeccompLevel::None => Ok(vec![]),
        SeccompLevel::Basic => default_filter()
            .and_then(|filter| Ok(filter.allow_all()))
            .and_then(|filter| filter.try_into())
            .map_err(SeccompError::SeccompFilter),
        SeccompLevel::Advanced => default_filter()
            .and_then(|filter| filter.try_into())
            .map_err(SeccompError::SeccompFilter),
    }
}

#[cfg(test)]
mod tests {
    use super::get_seccomp_filter;
    use seccomp::SeccompLevel;

    #[test]
    fn test_get_seccomp_filter() {
        assert!(get_seccomp_filter(SeccompLevel::None).is_ok());
        assert!(get_seccomp_filter(SeccompLevel::Basic).is_ok());
        assert!(get_seccomp_filter(SeccompLevel::Advanced).is_ok());
    }
}
<commit_msg>whitelist getpid and tgkill syscalls for gnu libc<commit_after>// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

extern crate libc;
extern crate utils;

use std::convert::TryInto;

use seccomp::{
    allow_syscall, allow_syscall_if, BpfProgram, Error, SeccompAction, SeccompCmpArgLen as ArgLen,
    SeccompCmpOp::Eq, SeccompCondition as Cond, SeccompError, SeccompFilter, SeccompLevel,
    SeccompRule,
};
use utils::signal::sigrtmin;

/// The default filter containing the white listed syscall rules required by `Firecracker` to
/// function.
pub fn default_filter() -> Result<SeccompFilter, Error> {
    Ok(SeccompFilter::new(
        vec![
            allow_syscall(libc::SYS_accept4),
            allow_syscall(libc::SYS_brk),
            allow_syscall(libc::SYS_clock_gettime),
            allow_syscall(libc::SYS_close),
            allow_syscall(libc::SYS_connect),
            allow_syscall(libc::SYS_dup),
            allow_syscall(libc::SYS_epoll_ctl),
            allow_syscall(libc::SYS_epoll_pwait),
            #[cfg(all(target_env = "gnu", target_arch = "x86_64"))]
            allow_syscall(libc::SYS_epoll_wait),
            allow_syscall(libc::SYS_exit),
            allow_syscall(libc::SYS_exit_group),
            allow_syscall_if(
                libc::SYS_fcntl,
                or![and![
                    Cond::new(1, ArgLen::DWORD, Eq, super::FCNTL_F_SETFD)?,
                    Cond::new(2, ArgLen::QWORD, Eq, super::FCNTL_FD_CLOEXEC)?,
                ]],
            ),
            allow_syscall(libc::SYS_fstat),
            #[cfg(target_arch = "x86_64")]
            allow_syscall(libc::SYS_ftruncate),
            allow_syscall_if(
                libc::SYS_futex,
                or![
                    and![Cond::new(1, ArgLen::DWORD, Eq, super::FUTEX_WAIT_PRIVATE)?],
                    and![Cond::new(1, ArgLen::DWORD, Eq, super::FUTEX_WAKE_PRIVATE)?],
                    and![Cond::new(
                        1,
                        ArgLen::DWORD,
                        Eq,
                        super::FUTEX_REQUEUE_PRIVATE
                    )?],
                    #[cfg(target_env = "gnu")]
                    and![Cond::new(
                        1,
                        ArgLen::DWORD,
                        Eq,
                        super::FUTEX_CMP_REQUEUE_PRIVATE
                    )?],
                ],
            ),
            #[cfg(target_env = "gnu")]
            allow_syscall(libc::SYS_getpid),
            allow_syscall(libc::SYS_getrandom),
            allow_syscall_if(libc::SYS_ioctl, super::create_ioctl_seccomp_rule()?),
            allow_syscall(libc::SYS_lseek),
            #[cfg(target_env = "musl")]
            allow_syscall_if(
                libc::SYS_madvise,
                or![and![Cond::new(
                    2,
                    ArgLen::DWORD,
                    Eq,
                    libc::MADV_DONTNEED as u64
                )?],],
            ),
            allow_syscall(libc::SYS_mmap),
            allow_syscall(libc::SYS_mremap),
            allow_syscall(libc::SYS_munmap),
            #[cfg(target_arch = "aarch64")]
            allow_syscall(libc::SYS_newfstatat),
            #[cfg(target_arch = "x86_64")]
            allow_syscall(libc::SYS_open),
            allow_syscall(libc::SYS_openat),
            #[cfg(target_arch = "x86_64")]
            allow_syscall(libc::SYS_pipe),
            allow_syscall(libc::SYS_read),
            allow_syscall(libc::SYS_readv),
            allow_syscall(libc::SYS_recvfrom),
            // SYS_rt_sigreturn is needed in case a fault does occur, so that the signal handler
            // can return. Otherwise we get stuck in a fault loop.
            allow_syscall(libc::SYS_rt_sigreturn),
            allow_syscall(libc::SYS_sigaltstack),
            allow_syscall_if(
                libc::SYS_socket,
                or![and![Cond::new(0, ArgLen::DWORD, Eq, libc::AF_UNIX as u64)?],],
            ),
            #[cfg(target_arch = "x86_64")]
            allow_syscall(libc::SYS_stat),
            allow_syscall_if(
                libc::SYS_tkill,
                or![and![Cond::new(
                    1,
                    ArgLen::DWORD,
                    Eq,
                    (sigrtmin() + super::super::vstate::VCPU_RTSIG_OFFSET) as u64
                )?]],
            ),
            #[cfg(target_env = "gnu")]
            allow_syscall(libc::SYS_tgkill),
            allow_syscall(libc::SYS_timerfd_create),
            allow_syscall(libc::SYS_timerfd_settime),
            allow_syscall(libc::SYS_write),
            allow_syscall(libc::SYS_writev),
        ]
        .into_iter()
        .collect(),
        SeccompAction::Trap,
    )?)
}

/// Generate a BPF program based on a seccomp level value.
pub fn get_seccomp_filter(seccomp_level: SeccompLevel) -> Result<BpfProgram, SeccompError> {
    match seccomp_level {
        SeccompLevel::None => Ok(vec![]),
        SeccompLevel::Basic => default_filter()
            .and_then(|filter| Ok(filter.allow_all()))
            .and_then(|filter| filter.try_into())
            .map_err(SeccompError::SeccompFilter),
        SeccompLevel::Advanced => default_filter()
            .and_then(|filter| filter.try_into())
            .map_err(SeccompError::SeccompFilter),
    }
}

#[cfg(test)]
mod tests {
    use super::get_seccomp_filter;
    use seccomp::SeccompLevel;

    #[test]
    fn test_get_seccomp_filter() {
        assert!(get_seccomp_filter(SeccompLevel::None).is_ok());
        assert!(get_seccomp_filter(SeccompLevel::Basic).is_ok());
        assert!(get_seccomp_filter(SeccompLevel::Advanced).is_ok());
    }
}
<|endoftext|>


<commit_before>//! The `expressionparser` module parses every expression
//! to an AST (abstract syntax tree).
//! The idea is explained here: http://programmers.stackexchange.com/questions/254074/

//use frontend::ast::*;
use frontend::ast::{ASTNode, NodeDefault};
use frontend::lexer::Token;
use frontend::lexer::Token::*;

pub struct ExpressionParser {
    expr_stack: Vec<ASTNode>,
    oper_stack: Vec<Token>,
}

impl ExpressionParser {
    pub fn parse(node: &mut NodeDefault) {
        let mut expr_parser = ExpressionParser {
            expr_stack: Vec::new(),
            oper_stack: Vec::new(),
        };
        expr_parser.parse_expressions(node);
    }

    /// parse the expression node and creates mutliple ast nodes
    fn parse_expressions(&mut self, node: &mut NodeDefault) {

        node.childs.reverse();
        while let Some(top) = node.childs.pop() {
            match top.category() {
                tok @ TokBoolean  { .. } |
                tok @ TokInt      { .. } |
                tok @ TokFunction { .. } |
                tok @ TokVariable { .. } => {
                    let childs_copy = top.as_default().childs.to_vec();
                    self.expr_stack.push( ASTNode::Default(NodeDefault { category: tok.clone(), childs: childs_copy }) );
                },
                tok @ TokNumOp  { .. } |
                tok @ TokCompOp { .. } |
                tok @ TokLogOp  { .. } => {
                    let length = self.oper_stack.len();

                    // cycle through the oper_stack stack backwards
                    // if the rank of the current operator is <= the top of the
                    // stack, we create a new node
                    for i in 0..length {
                        let i_rev = length - i - 1;
                        let token: Token = self.oper_stack.get(i_rev).unwrap().clone();
                        if is_ranking_not_higher(token, tok.clone()) {
                            self.new_operator_node();
                        }
                    }

                    self.oper_stack.push(tok.clone());
                },
                _ => ()
            }
        }

        // parse the last elements of the stack
        // to avoid endless loop we try max expr_stack.len()
        for _ in 0..self.expr_stack.len() {
            if self.expr_stack.len() > 0 {
                self.new_operator_node();
            }
        }

        // finished. so add the root of the expressions as child.
        assert!{self.expr_stack.len() == 1, "Only one expression can be the root. But there are {:?}.", self.expr_stack.len()};
        if let Some(root) = self.expr_stack.pop() {
            node.childs.push(root);
        }
    }

    /// creates a node with an operator on top
    fn new_operator_node(&mut self) {
        if let Some(top_op) = self.oper_stack.pop() {
            let e2: ASTNode = self.expr_stack.pop().unwrap();
            let e1: ASTNode = self.expr_stack.pop().unwrap();

            let new_node = ASTNode::Default(NodeDefault { category: top_op.clone(), childs: vec![e1, e2] });
            self.expr_stack.push( new_node );
        }
    }
}

/// checks the operatores of two tokens returns true if operator of token1
/// is more important then operator of token2
/// the ranking is set in "operator_precedence"
fn is_ranking_not_higher(token1: Token, token2: Token) -> bool {
    let mut op1: String = "".to_string();
    let mut op2: String = "".to_string();
    match token1 {
        TokNumOp  { op_name, .. } |
        TokCompOp { op_name, .. } |
        TokLogOp  { op_name, .. } => {
            op1 = op_name.clone();
        },
        _ => ()
    }
    match token2 {
        TokNumOp  { op_name, .. } |
        TokCompOp { op_name, .. } |
        TokLogOp  { op_name, .. } => {
            op2 = op_name.clone();
        },
        _ => ()
    }

    if operator_rank(op1) >= operator_rank(op2) {
        return true
    }

    false
}

/// ranking of the operators
fn operator_rank(op: String) -> u8 {
    match op.as_ref() {
        "or"                => 1,
        "and"               => 2,
        "is" | "==" | "eq" | "neq" | ">" | "gt" | ">=" | "gte" | "<" | "lt" | "<=" | "lte"
                            => 3,
        "+" | "-"           => 4,
        "*" | "/" | "%"     => 5,
        "not"               => 6,
        _                   => panic!{"This operator is not implemented"}
    }
}
<commit_msg>expression parser for parenthese-support<commit_after>//! The `expressionparser` module parses every expression
//! to an AST (abstract syntax tree).
//! The idea is explained here: http://programmers.stackexchange.com/questions/254074/

//use frontend::ast::*;
use frontend::ast::{ASTNode, NodeDefault};
use frontend::lexer::Token;
use frontend::lexer::Token::*;

pub struct ExpressionParser {
    expr_stack: Vec<ASTNode>,
    oper_stack: Vec<Token>,
}

impl ExpressionParser {
    pub fn parse(node: &mut NodeDefault) {
        let mut expr_parser = ExpressionParser {
            expr_stack: Vec::new(),
            oper_stack: Vec::new(),
        };
        expr_parser.parse_expressions(node);
    }

    /// parse the expression node and creates mutliple ast nodes
    fn parse_expressions(&mut self, node: &mut NodeDefault) {

        node.childs.reverse();
        while let Some(top) = node.childs.pop() {
            match top.category() {
                tok @ TokBoolean  { .. } |
                tok @ TokInt      { .. } |
                tok @ TokFunction { .. } |
                tok @ TokVariable { .. } => {
                    let childs_copy = top.as_default().childs.to_vec();
                    self.expr_stack.push( ASTNode::Default(NodeDefault { category: tok.clone(), childs: childs_copy }) );
                },
                tok @ TokNumOp  { .. } |
                tok @ TokCompOp { .. } |
                tok @ TokLogOp  { .. } => {
                    let length = self.oper_stack.len();

                    // cycle through the oper_stack stack backwards
                    // if the rank of the current operator is <= the top of the
                    // stack, we create a new node
                    for i in 0..length {
                        let i_rev = length - i - 1;
                        let token: Token = self.oper_stack.get(i_rev).unwrap().clone();
                        if is_ranking_not_higher(token, tok.clone()) {
                            self.new_operator_node();
                        }
                    }

                    self.oper_stack.push(tok.clone());
                },
                tok @ TokParenOpen { .. } => {
                    self.oper_stack.push(tok.clone());
                }
                TokParenClose { .. } => {
                    let length = self.oper_stack.len();

                    for i in 0..length {
                        let i_rev = length - i - 1;
                        let token: Token = self.oper_stack.get(i_rev).unwrap().clone();
                        //if is_ranking_not_higher(token, tok.clone()) {
                        //    self.new_operator_node();
                        //}
                        match token {
                            TokParenOpen { .. } => {
                                break;
                            }
                            _ => {
                                self.new_operator_node();
                            }
                        }
                    }

                    self.oper_stack.pop();

                }
                _ => ()
            }
        }
        println!("LENGTH {:?}", self.expr_stack.len());

        // parse the last elements of the stack
        // to avoid endless loop we try max expr_stack.len()
        for _ in 0..self.expr_stack.len() {
            if self.expr_stack.len() > 0 {
                self.new_operator_node();
            }
        }

        // finished. so add the root of the expressions as child.
        assert!{self.expr_stack.len() == 1, "Only one expression can be the root. But there are {:?}.", self.expr_stack.len()};
        if let Some(root) = self.expr_stack.pop() {
            node.childs.push(root);
        }
    }

    /// creates a node with an operator on top
    fn new_operator_node(&mut self) {
        if let Some(top_op) = self.oper_stack.pop() {
            let e2: ASTNode = self.expr_stack.pop().unwrap();
            let e1: ASTNode = self.expr_stack.pop().unwrap();

            let new_node = ASTNode::Default(NodeDefault { category: top_op.clone(), childs: vec![e1, e2] });
            self.expr_stack.push( new_node );
        }
    }
}

/// checks the operatores of two tokens returns true if operator of token1
/// is more important then operator of token2
/// the ranking is set in "operator_precedence"
fn is_ranking_not_higher(token1: Token, token2: Token) -> bool {
    let mut op1: String = "".to_string();
    let mut op2: String = "".to_string();
    match token1 {
        TokNumOp  { op_name, .. } |
        TokCompOp { op_name, .. } |
        TokLogOp  { op_name, .. } => {
            op1 = op_name.clone();
        },
        _ => ()
    }
    match token2 {
        TokNumOp  { op_name, .. } |
        TokCompOp { op_name, .. } |
        TokLogOp  { op_name, .. } => {
            op2 = op_name.clone();
        },
        _ => ()
    }

    if operator_rank(op1) >= operator_rank(op2) {
        return true
    }

    false
}

/// ranking of the operators
fn operator_rank(op: String) -> u8 {
    match op.as_ref() {
        "or"                => 1,
        "and"               => 2,
        "is" | "==" | "eq" | "neq" | ">" | "gt" | ">=" | "gte" | "<" | "lt" | "<=" | "lte"
                            => 3,
        "+" | "-"           => 4,
        "*" | "/" | "%"     => 5,
        "not"               => 6,
        _                   => panic!{"This operator is not implemented"}
    }
}
<|endoftext|>