<commit_before>extern crate pkg_config;
extern crate gcc;

use std::env;
use std::ffi::OsString;
use std::fs;
use std::path::PathBuf;
use std::process::Command;

macro_rules! t {
    ($e:expr) => (match $e {
        Ok(t) => t,
        Err(e) => panic!("{} return the error {}", stringify!($e), e),
    })
}

#[allow(deprecated)] // needed for `connect()`, since Rust 1.1 is supported
fn main() {
    let target = env::var("TARGET").unwrap();
    let src = env::current_dir().unwrap();
    let dst = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    let windows = target.contains("windows");

    // OSX ships libcurl by default, so we just use that version
    // unconditionally.
    if target.contains("apple") {
        return println!("cargo:rustc-flags=-l curl");
    }

    // Next, fall back and try to use pkg-config if its available.
    match pkg_config::find_library("libcurl") {
        Ok(..) => return,
        Err(..) => {}
    }

    println!("cargo:rustc-link-search={}/lib", dst.display());
    println!("cargo:rustc-link-lib=static=curl");
    println!("cargo:root={}", dst.display());
    println!("cargo:include={}/include", dst.display());
    if windows {
        println!("cargo:rustc-flags=-l ws2_32");
    }

    // MSVC builds are just totally different
    if target.contains("msvc") {
        return build_msvc(&target);
    }

    let mut cflags = env::var("CFLAGS").unwrap_or(String::new());
    cflags.push_str(" -ffunction-sections -fdata-sections");

    if target.contains("i686") {
        cflags.push_str(" -m32");
    } else if target.contains("x86_64") {
        cflags.push_str(" -m64");
    }
    if !target.contains("i686") {
        cflags.push_str(" -fPIC");
    }

    let _ = fs::create_dir(&dst.join("build"));

    let mut config_opts = Vec::new();
    if windows {
        config_opts.push("--with-winssl".to_string());
    } else {
        config_opts.push("--without-ca-bundle".to_string());
        config_opts.push("--without-ca-path".to_string());

        match env::var("DEP_OPENSSL_ROOT") {
            Ok(s) => config_opts.push(format!("--with-ssl={}", s)),
            Err(..) => {}
        }
    }
    config_opts.push("--enable-static=yes".to_string());
    config_opts.push("--enable-shared=no".to_string());
    config_opts.push("--enable-optimize".to_string());
    config_opts.push(format!("--prefix={}", dst.display()));

    config_opts.push("--without-librtmp".to_string());
    config_opts.push("--without-libidn".to_string());
    config_opts.push("--without-libssh2".to_string());
    config_opts.push("--without-nghttp2".to_string());
    config_opts.push("--disable-ldap".to_string());
    config_opts.push("--disable-ldaps".to_string());
    config_opts.push("--disable-ftp".to_string());
    config_opts.push("--disable-rtsp".to_string());
    config_opts.push("--disable-dict".to_string());
    config_opts.push("--disable-telnet".to_string());
    config_opts.push("--disable-tftp".to_string());
    config_opts.push("--disable-pop3".to_string());
    config_opts.push("--disable-imap".to_string());
    config_opts.push("--disable-smtp".to_string());
    config_opts.push("--disable-gopher".to_string());
    config_opts.push("--disable-manual".to_string());

    // Can't run ./configure directly on msys2 b/c we're handing in
    // Windows-style paths (those starting with C:\), but it chokes on those.
    // For that reason we build up a shell script with paths converted to
    // posix versions hopefully...
    //
    // Also apparently the buildbots choke unless we manually set LD, who knows
    // why?!
    run(Command::new("sh")
                .env("CFLAGS", &cflags)
                .env("LD", &which("ld").unwrap())
                .current_dir(&dst.join("build"))
                .arg("-c")
                .arg(&format!("{} {}", src.join("curl/configure").display(),
                              config_opts.connect(" "))
                             .replace("C:\\", "/c/")
                             .replace("\\", "/")));
    run(Command::new(make())
                .arg(&format!("-j{}", env::var("NUM_JOBS").unwrap()))
                .current_dir(&dst.join("build")));

    // Don't run `make install` because apparently it's a little buggy on mingw
    // for windows.
    let _ = fs::create_dir_all(&dst.join("lib/pkgconfig"));

    // Which one does windows generate? Who knows!
    let p1 = dst.join("build/lib/.libs/libcurl.a");
    let p2 = dst.join("build/lib/.libs/libcurl.lib");
    if fs::metadata(&p1).is_ok() {
        t!(fs::copy(&p1, &dst.join("lib/libcurl.a")));
    } else {
        t!(fs::copy(&p2, &dst.join("lib/libcurl.a")));
    }
    t!(fs::copy(&dst.join("build/libcurl.pc"),
                  &dst.join("lib/pkgconfig/libcurl.pc")));
}

fn run(cmd: &mut Command) {
    println!("running: {:?}", cmd);
    assert!(t!(cmd.status()).success());
}

fn make() -> &'static str {
    if cfg!(target_os = "freebsd") {"gmake"} else {"make"}
}

fn which(cmd: &str) -> Option<PathBuf> {
    let cmd = format!("{}{}", cmd, env::consts::EXE_SUFFIX);
    let paths = env::var_os("PATH").unwrap();
    env::split_paths(&paths).map(|p| p.join(&cmd)).find(|p| {
        fs::metadata(p).is_ok()
    })
}

fn build_msvc(target: &str) {
    let cmd = gcc::windows_registry::find(target, "nmake.exe");
    let mut cmd = cmd.unwrap_or(Command::new("nmake.exe"));
    let src = env::current_dir().unwrap();
    let dst = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    let machine = if target.starts_with("x86_64") {
        "x64"
    } else if target.starts_with("i686") {
        "x86"
    } else {
        panic!("unknown msvc target: {}", target);
    };

    t!(fs::create_dir_all(dst.join("include/curl")));
    t!(fs::create_dir_all(dst.join("lib")));

    cmd.current_dir(src.join("curl/winbuild"));
    cmd.arg("/f").arg("Makefile.vc")
       .arg("MODE=static")
       .arg("ENABLE_IDN=yes")
       .arg("DEBUG=no")
       .arg("GEN_PDB=no")
       .arg("ENABLE_WINSSL=yes")
       .arg("ENABLE_SSPI=yes")
       .arg(format!("MACHINE={}", machine));

    if let Some(inc) = env::var_os("DEP_Z_ROOT") {
        let inc = PathBuf::from(inc);
        let mut s = OsString::from("WITH_DEVEL=");
        s.push(&inc);
        cmd.arg("WITH_ZLIB=static").arg(s);

        // the build system for curl expects this library to be called
        // zlib_a.lib, so make sure it's named correctly (where libz-sys just
        // produces zlib.lib)
        let _ = fs::remove_file(&inc.join("lib/zlib_a.lib"));
        t!(fs::hard_link(inc.join("lib/zlib.lib"), inc.join("lib/zlib_a.lib")));
    }
    run(&mut cmd);

    let name = format!("libcurl-vc-{}-release-static-zlib-static-\
                        ipv6-sspi-winssl", machine);
    let libs = src.join("curl/builds").join(name);

    t!(fs::copy(libs.join("lib/libcurl_a.lib"), dst.join("lib/curl.lib")));
    for f in t!(fs::read_dir(libs.join("include/curl"))) {
        let path = t!(f).path();
        let dst = dst.join("include/curl").join(path.file_name().unwrap());
        t!(fs::copy(path, dst));
    }
    t!(fs::remove_dir_all(src.join("curl/builds")));
    println!("cargo:rustc-link-lib=wldap32");
    println!("cargo:rustc-link-lib=advapi32");
    println!("cargo:rustc-link-lib=normaliz");
}
<commit_msg>Pick up CFLAGS/CC from gcc + use Command<commit_after>extern crate pkg_config;
extern crate gcc;

use std::env;
use std::ffi::OsString;
use std::fs;
use std::path::PathBuf;
use std::process::Command;

macro_rules! t {
    ($e:expr) => (match $e {
        Ok(t) => t,
        Err(e) => panic!("{} return the error {}", stringify!($e), e),
    })
}

#[allow(deprecated)] // needed for `connect()`, since Rust 1.1 is supported
fn main() {
    let target = env::var("TARGET").unwrap();
    let src = env::current_dir().unwrap();
    let dst = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    let windows = target.contains("windows");

    // OSX ships libcurl by default, so we just use that version
    // unconditionally.
    if target.contains("apple") {
        return println!("cargo:rustc-flags=-l curl");
    }

    // Next, fall back and try to use pkg-config if its available.
    match pkg_config::find_library("libcurl") {
        Ok(..) => return,
        Err(..) => {}
    }

    println!("cargo:rustc-link-search={}/lib", dst.display());
    println!("cargo:rustc-link-lib=static=curl");
    println!("cargo:root={}", dst.display());
    println!("cargo:include={}/include", dst.display());
    if windows {
        println!("cargo:rustc-flags=-l ws2_32");
    }

    // MSVC builds are just totally different
    if target.contains("msvc") {
        return build_msvc(&target);
    }

    let cfg = gcc::Config::new();
    let compiler = cfg.get_compiler();

    let _ = fs::create_dir(&dst.join("build"));

    let mut cmd = Command::new("sh");
    cmd.env("CC", compiler.path())
       .env("CFLAGS", compiler.args().iter().map(|s| s.to_str().unwrap())
                              .collect::<Vec<_>>().join(" "))
       .env("LD", &which("ld").unwrap())
       .current_dir(&dst.join("build"))
       .arg(src.join("curl/configure").to_str().unwrap()
               .replace("C:\\", "/c/")
               .replace("\\", "/"));
    if windows {
        cmd.arg("--with-winssl");
    } else {
        cmd.arg("--without-ca-bundle");
        cmd.arg("--without-ca-path");

        if let Ok(s) = env::var("DEP_OPENSSL_ROOT") {
            cmd.arg(format!("--with-ssl={}", s));
        }
    }
    cmd.arg("--enable-static=yes");
    cmd.arg("--enable-shared=no");
    cmd.arg("--enable-optimize");
    cmd.arg(format!("--prefix={}", dst.display()));

    cmd.arg("--without-librtmp");
    cmd.arg("--without-libidn");
    cmd.arg("--without-libssh2");
    cmd.arg("--without-nghttp2");
    cmd.arg("--disable-ldap");
    cmd.arg("--disable-ldaps");
    cmd.arg("--disable-ftp");
    cmd.arg("--disable-rtsp");
    cmd.arg("--disable-dict");
    cmd.arg("--disable-telnet");
    cmd.arg("--disable-tftp");
    cmd.arg("--disable-pop3");
    cmd.arg("--disable-imap");
    cmd.arg("--disable-smtp");
    cmd.arg("--disable-gopher");
    cmd.arg("--disable-manual");

    // Can't run ./configure directly on msys2 b/c we're handing in
    // Windows-style paths (those starting with C:\), but it chokes on those.
    // For that reason we build up a shell script with paths converted to
    // posix versions hopefully...
    //
    // Also apparently the buildbots choke unless we manually set LD, who knows
    // why?!
    run(&mut cmd);
    run(Command::new(make())
                .arg(&format!("-j{}", env::var("NUM_JOBS").unwrap()))
                .current_dir(&dst.join("build")));

    // Don't run `make install` because apparently it's a little buggy on mingw
    // for windows.
    let _ = fs::create_dir_all(&dst.join("lib/pkgconfig"));

    // Which one does windows generate? Who knows!
    let p1 = dst.join("build/lib/.libs/libcurl.a");
    let p2 = dst.join("build/lib/.libs/libcurl.lib");
    if fs::metadata(&p1).is_ok() {
        t!(fs::copy(&p1, &dst.join("lib/libcurl.a")));
    } else {
        t!(fs::copy(&p2, &dst.join("lib/libcurl.a")));
    }
    t!(fs::copy(&dst.join("build/libcurl.pc"),
                  &dst.join("lib/pkgconfig/libcurl.pc")));
}

fn run(cmd: &mut Command) {
    println!("running: {:?}", cmd);
    assert!(t!(cmd.status()).success());
}

fn make() -> &'static str {
    if cfg!(target_os = "freebsd") {"gmake"} else {"make"}
}

fn which(cmd: &str) -> Option<PathBuf> {
    let cmd = format!("{}{}", cmd, env::consts::EXE_SUFFIX);
    let paths = env::var_os("PATH").unwrap();
    env::split_paths(&paths).map(|p| p.join(&cmd)).find(|p| {
        fs::metadata(p).is_ok()
    })
}

fn build_msvc(target: &str) {
    let cmd = gcc::windows_registry::find(target, "nmake.exe");
    let mut cmd = cmd.unwrap_or(Command::new("nmake.exe"));
    let src = env::current_dir().unwrap();
    let dst = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    let machine = if target.starts_with("x86_64") {
        "x64"
    } else if target.starts_with("i686") {
        "x86"
    } else {
        panic!("unknown msvc target: {}", target);
    };

    t!(fs::create_dir_all(dst.join("include/curl")));
    t!(fs::create_dir_all(dst.join("lib")));

    cmd.current_dir(src.join("curl/winbuild"));
    cmd.arg("/f").arg("Makefile.vc")
       .arg("MODE=static")
       .arg("ENABLE_IDN=yes")
       .arg("DEBUG=no")
       .arg("GEN_PDB=no")
       .arg("ENABLE_WINSSL=yes")
       .arg("ENABLE_SSPI=yes")
       .arg(format!("MACHINE={}", machine));

    if let Some(inc) = env::var_os("DEP_Z_ROOT") {
        let inc = PathBuf::from(inc);
        let mut s = OsString::from("WITH_DEVEL=");
        s.push(&inc);
        cmd.arg("WITH_ZLIB=static").arg(s);

        // the build system for curl expects this library to be called
        // zlib_a.lib, so make sure it's named correctly (where libz-sys just
        // produces zlib.lib)
        let _ = fs::remove_file(&inc.join("lib/zlib_a.lib"));
        t!(fs::hard_link(inc.join("lib/zlib.lib"), inc.join("lib/zlib_a.lib")));
    }
    run(&mut cmd);

    let name = format!("libcurl-vc-{}-release-static-zlib-static-\
                        ipv6-sspi-winssl", machine);
    let libs = src.join("curl/builds").join(name);

    t!(fs::copy(libs.join("lib/libcurl_a.lib"), dst.join("lib/curl.lib")));
    for f in t!(fs::read_dir(libs.join("include/curl"))) {
        let path = t!(f).path();
        let dst = dst.join("include/curl").join(path.file_name().unwrap());
        t!(fs::copy(path, dst));
    }
    t!(fs::remove_dir_all(src.join("curl/builds")));
    println!("cargo:rustc-link-lib=wldap32");
    println!("cargo:rustc-link-lib=advapi32");
    println!("cargo:rustc-link-lib=normaliz");
}
<|endoftext|>


<commit_before>#![crate_name = "uu_uptime"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Jordi Boggiano <j.boggiano@seld.be>
 * (c) Jian Zeng <anonymousknight86@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

/* last synced with: cat (GNU coreutils) 8.13 */

extern crate getopts;
extern crate time;

#[macro_use]
extern crate uucore;
// import crate time from utmpx
pub use uucore::libc;
use uucore::libc::time_t;

use getopts::Options;

static NAME: &str = "uptime";
static VERSION: &str = env!("CARGO_PKG_VERSION");

#[cfg(unix)]
use libc::getloadavg;

#[cfg(windows)]
extern "C" {
    fn GetTickCount() -> libc::uint32_t;
}

pub fn uumain(args: Vec<String>) -> i32 {
    let mut opts = Options::new();

    opts.optflag("v", "version", "output version information and exit");
    opts.optflag("h", "help", "display this help and exit");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => crash!(1, "Invalid options\n{}", f),
    };
    if matches.opt_present("version") {
        println!("{} {}", NAME, VERSION);
        return 0;
    }
    if matches.opt_present("help") || !matches.free.is_empty() {
        println!("{} {}", NAME, VERSION);
        println!();
        println!("Usage:");
        println!("  {0} [OPTION]", NAME);
        println!();
        println!(
            "{}",
            opts.usage(
                "Print the current time, the length of time the system has been up,\n\
                 the number of users on the system, and the average number of jobs\n\
                 in the run queue over the last 1, 5 and 15 minutes."
            )
        );
        return 0;
    }

    print_time();
    let (boot_time, user_count) = process_utmpx();
    let uptime = get_uptime(boot_time);
    if uptime < 0 {
        show_error!("could not retrieve system uptime");

        1
    } else {
        let upsecs = uptime / 100;
        print_uptime(upsecs);
        print_nusers(user_count);
        print_loadavg();

        0
    }
}

#[cfg(unix)]
fn print_loadavg() {
    use libc::c_double;

    let mut avg: [c_double; 3] = [0.0; 3];
    let loads: i32 = unsafe { getloadavg(avg.as_mut_ptr(), 3) };

    if loads == -1 {
        println!();
    } else {
        print!("load average: ");
        for n in 0..loads {
            print!(
                "{:.2}{}",
                avg[n as usize],
                if n == loads - 1 { "\n" } else { ", " }
            );
        }
    }
}

#[cfg(windows)]
fn print_loadavg() {
    // XXX: currently this is a noop as Windows does not seem to have anything comparable to
    //      getloadavg()
}

#[cfg(unix)]
fn process_utmpx() -> (Option<time_t>, usize) {
    use uucore::utmpx::*;

    let mut nusers = 0;
    let mut boot_time = None;

    for line in Utmpx::iter_all_records() {
        match line.record_type() {
            USER_PROCESS => nusers += 1,
            BOOT_TIME => {
                let t = line.login_time().to_timespec();
                if t.sec > 0 {
                    boot_time = Some(t.sec as time_t);
                }
            }
            _ => continue,
        }
    }
    (boot_time, nusers)
}

#[cfg(windows)]
fn process_utmpx() -> (Option<time_t>, usize) {
    (None, 0) // TODO: change 0 to number of users
}

fn print_nusers(nusers: usize) {
    match nusers.cmp(&1) {
        std::cmp::Ordering::Equal => print!("1 user,  "),
        std::cmp::Ordering::Greater => print!("{} users,  ", nusers),
        _ => {}
    };
}

fn print_time() {
    let local_time = time::now();

    print!(
        " {:02}:{:02}:{:02} ",
        local_time.tm_hour, local_time.tm_min, local_time.tm_sec
    );
}

#[cfg(unix)]
fn get_uptime(boot_time: Option<time_t>) -> i64 {
    use std::fs::File;
    use std::io::Read;

    let mut proc_uptime = String::new();

    if let Some(n) = File::open("/proc/uptime")
        .ok()
        .and_then(|mut f| f.read_to_string(&mut proc_uptime).ok())
        .and_then(|_| proc_uptime.split_whitespace().next())
        .and_then(|s| s.replace(".", "").parse().ok())
    {
        n
    } else {
        match boot_time {
            Some(t) => {
                let now = time::get_time().sec;
                let boottime = t as i64;
                ((now - boottime) * 100)
            }
            _ => -1,
        }
    }
}

#[cfg(windows)]
fn get_uptime(_boot_time: Option<time_t>) -> i64 {
    unsafe { GetTickCount() as i64 }
}

fn print_uptime(upsecs: i64) {
    let updays = upsecs / 86400;
    let uphours = (upsecs - (updays * 86400)) / 3600;
    let upmins = (upsecs - (updays * 86400) - (uphours * 3600)) / 60;
    match updays.cmp(&1) {
        std::cmp::Ordering::Equal => print!("up {:1} day, {:2}:{:02},  ", updays, uphours, upmins),
        std::cmp::Ordering::Greater => {
            print!("up {:1} days, {:2}:{:02},  ", updays, uphours, upmins)
        }
        _ => print!("up  {:2}:{:02}, ", uphours, upmins),
    };
}
<commit_msg>refactor/polish ~ fix `rustc` complaints (unused_parens)<commit_after>#![crate_name = "uu_uptime"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Jordi Boggiano <j.boggiano@seld.be>
 * (c) Jian Zeng <anonymousknight86@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

/* last synced with: cat (GNU coreutils) 8.13 */

extern crate getopts;
extern crate time;

#[macro_use]
extern crate uucore;
// import crate time from utmpx
pub use uucore::libc;
use uucore::libc::time_t;

use getopts::Options;

static NAME: &str = "uptime";
static VERSION: &str = env!("CARGO_PKG_VERSION");

#[cfg(unix)]
use libc::getloadavg;

#[cfg(windows)]
extern "C" {
    fn GetTickCount() -> libc::uint32_t;
}

pub fn uumain(args: Vec<String>) -> i32 {
    let mut opts = Options::new();

    opts.optflag("v", "version", "output version information and exit");
    opts.optflag("h", "help", "display this help and exit");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => crash!(1, "Invalid options\n{}", f),
    };
    if matches.opt_present("version") {
        println!("{} {}", NAME, VERSION);
        return 0;
    }
    if matches.opt_present("help") || !matches.free.is_empty() {
        println!("{} {}", NAME, VERSION);
        println!();
        println!("Usage:");
        println!("  {0} [OPTION]", NAME);
        println!();
        println!(
            "{}",
            opts.usage(
                "Print the current time, the length of time the system has been up,\n\
                 the number of users on the system, and the average number of jobs\n\
                 in the run queue over the last 1, 5 and 15 minutes."
            )
        );
        return 0;
    }

    print_time();
    let (boot_time, user_count) = process_utmpx();
    let uptime = get_uptime(boot_time);
    if uptime < 0 {
        show_error!("could not retrieve system uptime");

        1
    } else {
        let upsecs = uptime / 100;
        print_uptime(upsecs);
        print_nusers(user_count);
        print_loadavg();

        0
    }
}

#[cfg(unix)]
fn print_loadavg() {
    use libc::c_double;

    let mut avg: [c_double; 3] = [0.0; 3];
    let loads: i32 = unsafe { getloadavg(avg.as_mut_ptr(), 3) };

    if loads == -1 {
        println!();
    } else {
        print!("load average: ");
        for n in 0..loads {
            print!(
                "{:.2}{}",
                avg[n as usize],
                if n == loads - 1 { "\n" } else { ", " }
            );
        }
    }
}

#[cfg(windows)]
fn print_loadavg() {
    // XXX: currently this is a noop as Windows does not seem to have anything comparable to
    //      getloadavg()
}

#[cfg(unix)]
fn process_utmpx() -> (Option<time_t>, usize) {
    use uucore::utmpx::*;

    let mut nusers = 0;
    let mut boot_time = None;

    for line in Utmpx::iter_all_records() {
        match line.record_type() {
            USER_PROCESS => nusers += 1,
            BOOT_TIME => {
                let t = line.login_time().to_timespec();
                if t.sec > 0 {
                    boot_time = Some(t.sec as time_t);
                }
            }
            _ => continue,
        }
    }
    (boot_time, nusers)
}

#[cfg(windows)]
fn process_utmpx() -> (Option<time_t>, usize) {
    (None, 0) // TODO: change 0 to number of users
}

fn print_nusers(nusers: usize) {
    match nusers.cmp(&1) {
        std::cmp::Ordering::Equal => print!("1 user,  "),
        std::cmp::Ordering::Greater => print!("{} users,  ", nusers),
        _ => {}
    };
}

fn print_time() {
    let local_time = time::now();

    print!(
        " {:02}:{:02}:{:02} ",
        local_time.tm_hour, local_time.tm_min, local_time.tm_sec
    );
}

#[cfg(unix)]
fn get_uptime(boot_time: Option<time_t>) -> i64 {
    use std::fs::File;
    use std::io::Read;

    let mut proc_uptime = String::new();

    if let Some(n) = File::open("/proc/uptime")
        .ok()
        .and_then(|mut f| f.read_to_string(&mut proc_uptime).ok())
        .and_then(|_| proc_uptime.split_whitespace().next())
        .and_then(|s| s.replace(".", "").parse().ok())
    {
        n
    } else {
        match boot_time {
            Some(t) => {
                let now = time::get_time().sec;
                let boottime = t as i64;
                (now - boottime) * 100
            }
            _ => -1,
        }
    }
}

#[cfg(windows)]
fn get_uptime(_boot_time: Option<time_t>) -> i64 {
    unsafe { GetTickCount() as i64 }
}

fn print_uptime(upsecs: i64) {
    let updays = upsecs / 86400;
    let uphours = (upsecs - (updays * 86400)) / 3600;
    let upmins = (upsecs - (updays * 86400) - (uphours * 3600)) / 60;
    match updays.cmp(&1) {
        std::cmp::Ordering::Equal => print!("up {:1} day, {:2}:{:02},  ", updays, uphours, upmins),
        std::cmp::Ordering::Greater => {
            print!("up {:1} days, {:2}:{:02},  ", updays, uphours, upmins)
        }
        _ => print!("up  {:2}:{:02}, ", uphours, upmins),
    };
}
<|endoftext|>


<commit_before>use nom::{IResult, Needed};

use std::io::{self, Read};
use std::ptr;
use std::cmp;

use super::StreamProducer;

#[derive(Debug)]
pub enum ErrorKind {
  IO(io::ErrorKind),
  Incomplete(usize),
  Continue,
  EndOfInput,
  Unknown,
  // Parser Error
  HeaderParser,
  MetadataHeaderParser,
  StreamInfoParser,
  PaddingParser,
  ApplicationParser,
  SeekTableParser,
  VorbisCommentParser,
  CueSheetParser,
  PictureParser,
  UnknowParser,
  // Invalid Error
  InvalidBlockType,
}

/// Structure that hold a slice of bytes.
pub struct ByteStream<'a> {
  offset: usize,
  bytes: &'a [u8],
}

impl<'a> ByteStream<'a> {
  /// Construct a `ByteStream` based on the passed in byte slice.
  pub fn new(bytes: &'a [u8]) -> Self {
    ByteStream {
      offset: 0,
      bytes: bytes,
    }
  }

  /// Return the number of bytes that haven't been consumed yet.
  #[inline]
  pub fn len(&self) -> usize {
    self.bytes.len() - self.offset
  }

  /// Return true if the stream contains no more bytes.
  #[inline]
  pub fn is_empty(&self) -> bool {
    self.len() == 0
  }
}

impl<'a> StreamProducer for ByteStream<'a> {
  fn parse<F, T, E>(&mut self, f: F) -> Result<T, ErrorKind>
   where F: FnOnce(&[u8]) -> IResult<&[u8], T, E> {
    if self.is_empty() {
      return Err(ErrorKind::EndOfInput);
    }

    match f(&self.bytes[self.offset..]) {
      IResult::Done(i, o)    => {
        self.offset += self.len() - i.len();

        Ok(o)
      }
      IResult::Incomplete(n) => {
        let mut needed = self.len();

        if let Needed::Size(size) = n {
          needed = size;
        }

        Err(ErrorKind::Incomplete(needed))
      }
      IResult::Error(_)      => Err(ErrorKind::Unknown),
    }
  }
}

// Growable buffer of bytes.
//
// Mainly used to the `ReadStream` structure but can be used seperately for
// manually filling with some `Read` source.
pub struct Buffer {
  data: Vec<u8>,
  filled: usize,
  offset: usize,
}

impl Buffer {
  // Default constructor for `Buffer`
  pub fn new() -> Self {
    Self::with_capacity(1024)
  }

  // Explicitly set the buffer capacity.
  pub fn with_capacity(capacity: usize) -> Self {
    let mut buffer = Vec::with_capacity(capacity);

    unsafe {
      buffer.set_len(capacity);
    }

    Buffer {
      data: buffer,
      filled: 0,
      offset: 0,
    }
  }

  // Return the number of read bytes that haven't been consumed yet.
  #[inline]
  pub fn len(&self) -> usize {
    self.filled - self.offset
  }

  // Return true if buffer contains no more bytes.
  #[inline]
  pub fn is_empty(&self) -> bool {
    self.len() == 0
  }

  // The set length of the unlining buffer.
  #[inline]
  pub fn capacity(&self) -> usize {
    self.data.len()
  }

  // Return a reference to the slice of unread bytes.
  pub fn as_slice(&self) -> &[u8] {
    &self.data[self.offset..self.filled]
  }

  // Fill the buffer with bytes from a `Read` source.
  pub fn fill<R: Read>(&mut self, reader: &mut R) -> io::Result<usize> {
    reader.read(&mut self.data[self.filled..]).map(|consumed| {
      self.filled += consumed;

      consumed
    })
  }

  // Resize the current buffer
  //
  // This will only allocate data when the size requests is larger than the
  // current capacity of the buffer, otherwise it moves the currently filled
  // data to the beginning of the buffer.
  pub fn resize(&mut self, size: usize) {
    if size > self.data.capacity() {
      self.data.reserve(size);

      let capacity = self.data.capacity();

      unsafe {
        self.data.set_len(capacity);
      }
    }

    if self.data.len() - self.filled < size  {
      let length  = self.filled - self.offset;
      let mut_ptr = self.data.as_mut_ptr();

      unsafe {
        let offset_ptr  = self.data.as_ptr().offset(self.offset as isize);

        ptr::copy(offset_ptr, mut_ptr, length);
      }

      self.filled -= self.offset;
      self.offset  = 0;
    }
  }

  // Move the offset by the amount of consumed bytes.
  pub fn consume(&mut self, consumed: usize) {
    self.offset += consumed;
  }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum ParserState {
  Incomplete,
  EndOfInput,
}

fn fill<R: Read>(buffer: &mut Buffer, reader: &mut R, needed: usize)
                 -> io::Result<usize> {
  let mut read = 0;

  if buffer.len() < needed {
    buffer.resize(needed);

    while buffer.len() < needed {
      let size_read = try!(buffer.fill(reader));

      if size_read > 0 {
        read += size_read;
      } else {
        break;
      }
    }
  }

  Ok(read)
}

/// Structure that hold a reader for a source of bytes.
pub struct ReadStream<R: Read> {
  reader: R,
  buffer: Buffer,
  needed: usize,
  state: ParserState,
}

impl<R> ReadStream<R> where R: Read {
  /// Constructor for `ReadStream` based on a `Read` source.
  pub fn new(reader: R) -> Self {
    ReadStream {
      reader: reader,
      buffer: Buffer::new(),
      needed: 0,
      state: ParserState::Incomplete,
    }
  }

  // Fill the stream with bytes from a `Read` source.
  fn fill(&mut self) -> io::Result<usize> {
    let needed = cmp::max(1, self.needed);

    fill(&mut self.buffer, &mut self.reader, needed).map(|consumed| {
      if self.buffer.len() < needed {
        self.state = ParserState::EndOfInput;
      }

      consumed
    })
  }
}

fn from_iresult<T, E>(buffer: &Buffer, result: IResult<&[u8], T, E>)
                      -> Result<(usize, T), ErrorKind> {
  match result {
    IResult::Done(i, o)    => Ok((buffer.len() - i.len(), o)),
    IResult::Incomplete(n) => {
      let mut needed = buffer.capacity() + 1024;

      if let Needed::Size(size) = n {
        needed = size;
      }

      Err(ErrorKind::Incomplete(needed))
    }
    IResult::Error(_)      => Err(ErrorKind::Unknown),
  }
}

impl<R> StreamProducer for ReadStream<R> where R: Read {
  fn parse<F, T, E>(&mut self, f: F) -> Result<T, ErrorKind>
   where F: FnOnce(&[u8]) -> IResult<&[u8], T, E> {
    if self.state != ParserState::EndOfInput {
      try!(self.fill().map_err(|e| ErrorKind::IO(e.kind())));
    }

    let mut buffer = &mut self.buffer;

    if buffer.is_empty() {
      self.state = ParserState::EndOfInput;

      return Err(ErrorKind::EndOfInput);
    }

    let result = {
      let iresult = f(buffer.as_slice());

      from_iresult(&buffer, iresult)
    };

    match result {
      Ok((consumed, o)) => {
        buffer.consume(consumed);

        Ok(o)
      }
      Err(kind)         => {
        if let ErrorKind::Incomplete(needed) = kind {
          self.needed = needed;

          Err(ErrorKind::Continue)
        } else {
          Err(kind)
        }
      }
    }
  }
}

#[cfg(test)]
mod tests {
  use super::*;
  use utility::StreamProducer;
  use nom::be_u32;

  #[test]
  fn test_buffer() {
    let mut buffer = Buffer::new();
    let bytes      = b"Hello World";
    let mut reader = &bytes[..];

    assert!(buffer.is_empty());
    assert_eq!(buffer.capacity(), 1024);

    let bytes_read = buffer.fill(&mut reader).unwrap_or(0);
    let bytes_len  = bytes.len();

    assert_eq!(bytes_read, bytes_len);
    assert_eq!(buffer.len(), bytes_len);
    assert_eq!(buffer.as_slice(), bytes);

    buffer.resize(512);
    assert_eq!(buffer.capacity(), 1024);
  }

  #[test]
  fn test_byte_stream() {
    let bytes      = b"Hello World";
    let mut stream = ByteStream::new(bytes);

    assert_eq!(stream.len(), bytes.len());

    let result = stream.parse(be_u32).unwrap_or(0);

    assert_eq!(result, 1214606444);
    assert_eq!(stream.len(), 7);
  }

  #[test]
  fn test_read_stream() {
    let bytes      = b"Hello World";
    let mut stream = ReadStream::new(&bytes[..]);

    let result = stream.parse(be_u32).unwrap_or(0);

    assert_eq!(result, 1214606444)
  }
}
<commit_msg>Allow for `ErrorKind` comparisons<commit_after>use nom::{IResult, Needed};

use std::io::{self, Read};
use std::ptr;
use std::cmp;

use super::StreamProducer;

#[derive(Debug, Eq, PartialEq)]
pub enum ErrorKind {
  IO(io::ErrorKind),
  Incomplete(usize),
  Continue,
  EndOfInput,
  Unknown,
  // Parser Error
  HeaderParser,
  MetadataHeaderParser,
  StreamInfoParser,
  PaddingParser,
  ApplicationParser,
  SeekTableParser,
  VorbisCommentParser,
  CueSheetParser,
  PictureParser,
  UnknowParser,
  // Invalid Error
  InvalidBlockType,
}

/// Structure that hold a slice of bytes.
pub struct ByteStream<'a> {
  offset: usize,
  bytes: &'a [u8],
}

impl<'a> ByteStream<'a> {
  /// Construct a `ByteStream` based on the passed in byte slice.
  pub fn new(bytes: &'a [u8]) -> Self {
    ByteStream {
      offset: 0,
      bytes: bytes,
    }
  }

  /// Return the number of bytes that haven't been consumed yet.
  #[inline]
  pub fn len(&self) -> usize {
    self.bytes.len() - self.offset
  }

  /// Return true if the stream contains no more bytes.
  #[inline]
  pub fn is_empty(&self) -> bool {
    self.len() == 0
  }
}

impl<'a> StreamProducer for ByteStream<'a> {
  fn parse<F, T, E>(&mut self, f: F) -> Result<T, ErrorKind>
   where F: FnOnce(&[u8]) -> IResult<&[u8], T, E> {
    if self.is_empty() {
      return Err(ErrorKind::EndOfInput);
    }

    match f(&self.bytes[self.offset..]) {
      IResult::Done(i, o)    => {
        self.offset += self.len() - i.len();

        Ok(o)
      }
      IResult::Incomplete(n) => {
        let mut needed = self.len();

        if let Needed::Size(size) = n {
          needed = size;
        }

        Err(ErrorKind::Incomplete(needed))
      }
      IResult::Error(_)      => Err(ErrorKind::Unknown),
    }
  }
}

// Growable buffer of bytes.
//
// Mainly used to the `ReadStream` structure but can be used seperately for
// manually filling with some `Read` source.
pub struct Buffer {
  data: Vec<u8>,
  filled: usize,
  offset: usize,
}

impl Buffer {
  // Default constructor for `Buffer`
  pub fn new() -> Self {
    Self::with_capacity(1024)
  }

  // Explicitly set the buffer capacity.
  pub fn with_capacity(capacity: usize) -> Self {
    let mut buffer = Vec::with_capacity(capacity);

    unsafe {
      buffer.set_len(capacity);
    }

    Buffer {
      data: buffer,
      filled: 0,
      offset: 0,
    }
  }

  // Return the number of read bytes that haven't been consumed yet.
  #[inline]
  pub fn len(&self) -> usize {
    self.filled - self.offset
  }

  // Return true if buffer contains no more bytes.
  #[inline]
  pub fn is_empty(&self) -> bool {
    self.len() == 0
  }

  // The set length of the unlining buffer.
  #[inline]
  pub fn capacity(&self) -> usize {
    self.data.len()
  }

  // Return a reference to the slice of unread bytes.
  pub fn as_slice(&self) -> &[u8] {
    &self.data[self.offset..self.filled]
  }

  // Fill the buffer with bytes from a `Read` source.
  pub fn fill<R: Read>(&mut self, reader: &mut R) -> io::Result<usize> {
    reader.read(&mut self.data[self.filled..]).map(|consumed| {
      self.filled += consumed;

      consumed
    })
  }

  // Resize the current buffer
  //
  // This will only allocate data when the size requests is larger than the
  // current capacity of the buffer, otherwise it moves the currently filled
  // data to the beginning of the buffer.
  pub fn resize(&mut self, size: usize) {
    if size > self.data.capacity() {
      self.data.reserve(size);

      let capacity = self.data.capacity();

      unsafe {
        self.data.set_len(capacity);
      }
    }

    if self.data.len() - self.filled < size  {
      let length  = self.filled - self.offset;
      let mut_ptr = self.data.as_mut_ptr();

      unsafe {
        let offset_ptr  = self.data.as_ptr().offset(self.offset as isize);

        ptr::copy(offset_ptr, mut_ptr, length);
      }

      self.filled -= self.offset;
      self.offset  = 0;
    }
  }

  // Move the offset by the amount of consumed bytes.
  pub fn consume(&mut self, consumed: usize) {
    self.offset += consumed;
  }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum ParserState {
  Incomplete,
  EndOfInput,
}

fn fill<R: Read>(buffer: &mut Buffer, reader: &mut R, needed: usize)
                 -> io::Result<usize> {
  let mut read = 0;

  if buffer.len() < needed {
    buffer.resize(needed);

    while buffer.len() < needed {
      let size_read = try!(buffer.fill(reader));

      if size_read > 0 {
        read += size_read;
      } else {
        break;
      }
    }
  }

  Ok(read)
}

/// Structure that hold a reader for a source of bytes.
pub struct ReadStream<R: Read> {
  reader: R,
  buffer: Buffer,
  needed: usize,
  state: ParserState,
}

impl<R> ReadStream<R> where R: Read {
  /// Constructor for `ReadStream` based on a `Read` source.
  pub fn new(reader: R) -> Self {
    ReadStream {
      reader: reader,
      buffer: Buffer::new(),
      needed: 0,
      state: ParserState::Incomplete,
    }
  }

  // Fill the stream with bytes from a `Read` source.
  fn fill(&mut self) -> io::Result<usize> {
    let needed = cmp::max(1, self.needed);

    fill(&mut self.buffer, &mut self.reader, needed).map(|consumed| {
      if self.buffer.len() < needed {
        self.state = ParserState::EndOfInput;
      }

      consumed
    })
  }
}

fn from_iresult<T, E>(buffer: &Buffer, result: IResult<&[u8], T, E>)
                      -> Result<(usize, T), ErrorKind> {
  match result {
    IResult::Done(i, o)    => Ok((buffer.len() - i.len(), o)),
    IResult::Incomplete(n) => {
      let mut needed = buffer.capacity() + 1024;

      if let Needed::Size(size) = n {
        needed = size;
      }

      Err(ErrorKind::Incomplete(needed))
    }
    IResult::Error(_)      => Err(ErrorKind::Unknown),
  }
}

impl<R> StreamProducer for ReadStream<R> where R: Read {
  fn parse<F, T, E>(&mut self, f: F) -> Result<T, ErrorKind>
   where F: FnOnce(&[u8]) -> IResult<&[u8], T, E> {
    if self.state != ParserState::EndOfInput {
      try!(self.fill().map_err(|e| ErrorKind::IO(e.kind())));
    }

    let mut buffer = &mut self.buffer;

    if buffer.is_empty() {
      self.state = ParserState::EndOfInput;

      return Err(ErrorKind::EndOfInput);
    }

    let result = {
      let iresult = f(buffer.as_slice());

      from_iresult(&buffer, iresult)
    };

    match result {
      Ok((consumed, o)) => {
        buffer.consume(consumed);

        Ok(o)
      }
      Err(kind)         => {
        if let ErrorKind::Incomplete(needed) = kind {
          self.needed = needed;

          Err(ErrorKind::Continue)
        } else {
          Err(kind)
        }
      }
    }
  }
}

#[cfg(test)]
mod tests {
  use super::*;
  use utility::StreamProducer;
  use nom::be_u32;

  #[test]
  fn test_buffer() {
    let mut buffer = Buffer::new();
    let bytes      = b"Hello World";
    let mut reader = &bytes[..];

    assert!(buffer.is_empty());
    assert_eq!(buffer.capacity(), 1024);

    let bytes_read = buffer.fill(&mut reader).unwrap_or(0);
    let bytes_len  = bytes.len();

    assert_eq!(bytes_read, bytes_len);
    assert_eq!(buffer.len(), bytes_len);
    assert_eq!(buffer.as_slice(), bytes);

    buffer.resize(512);
    assert_eq!(buffer.capacity(), 1024);
  }

  #[test]
  fn test_byte_stream() {
    let bytes      = b"Hello World";
    let mut stream = ByteStream::new(bytes);

    assert_eq!(stream.len(), bytes.len());

    let result = stream.parse(be_u32).unwrap_or(0);

    assert_eq!(result, 1214606444);
    assert_eq!(stream.len(), 7);
  }

  #[test]
  fn test_read_stream() {
    let bytes      = b"Hello World";
    let mut stream = ReadStream::new(&bytes[..]);

    let result = stream.parse(be_u32).unwrap_or(0);

    assert_eq!(result, 1214606444)
  }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013, David Renshaw (dwrenshaw@gmail.com)
 *
 * See the LICENSE file in the capnproto-rust root directory.
 */

#[feature(macro_rules)];
#[feature(globs)];

#[crate_type = "bin"];

extern mod capnp;

pub mod common;

pub mod carsales_capnp;
pub mod carsales;

pub mod catrank_capnp;
pub mod catrank;

pub mod eval_capnp;
pub mod eval;

mod Uncompressed {
    use capnp;
    use std;

    pub fn write<T : std::io::Writer>(writer: &mut T,
                                      message: &capnp::message::MessageBuilder) {
        capnp::serialize::write_message(writer, message);
    }

    pub fn write_buffered<T : std::io::Writer>(writer: &mut T,
                                               message: &capnp::message::MessageBuilder) {
        capnp::serialize::write_message(writer, message);
    }
/*
    pub fn new_reader<U : std::io::Reader, T>(
        inputStream : &mut U,
        options : capnp::message::ReaderOptions,
        cont : |&mut capnp::message::MessageReader| -> T) -> T {
        capnp::serialize::InputStreamMessageReader::new(inputStream, options, cont)
    }
*/
    pub fn new_buffered_reader<R: capnp::io::BufferedInputStream, T>(
        inputStream : &mut R,
        options : capnp::message::ReaderOptions,
        cont : |&mut capnp::message::MessageReader| -> T) -> T {
        capnp::serialize::InputStreamMessageReader::new(inputStream, options, cont)
    }
}

mod Packed {
    use capnp;
    use std;
    use capnp::serialize_packed::{write_packed_message, write_packed_message_unbuffered};

    pub fn write<T : std::io::Writer>(writer: &mut T,
                                      message: &capnp::message::MessageBuilder) {
        write_packed_message_unbuffered(writer, message);
    }

    pub fn write_buffered<T : capnp::io::BufferedOutputStream>(
        writer: &mut T,
        message: &capnp::message::MessageBuilder) {
        write_packed_message(writer, message);
    }
/*
    pub fn new_reader<U : std::io::Reader, T>(
        inputStream : &mut U,
        options : capnp::message::ReaderOptions,
        cont : |&mut capnp::message::MessageReader| -> T) -> T {
        capnp::serialize::InputStreamMessageReader::new(
            &mut capnp::serialize_packed::PackedInputStream{
                inner : &mut capnp::io::BufferedInputStreamWrapper::new(inputStream)
            },
            options, cont)
    }
*/
    pub fn new_buffered_reader<R:capnp::io::BufferedInputStream, T>(
        inputStream : &mut R,
        options : capnp::message::ReaderOptions,
        cont : |&mut capnp::message::MessageReader| -> T) -> T {
        capnp::serialize::InputStreamMessageReader::new(
            &mut capnp::serialize_packed::PackedInputStream{
                inner : inputStream
            },
            options, cont)
    }

}

macro_rules! pass_by_object(
    ( $testcase:ident, $iters:expr ) => ({
            let mut rng = common::FastRand::new();
            for _ in range(0, $iters) {
                capnp::message::MessageBuilder::new_default(|messageReq| {
                    capnp::message::MessageBuilder::new_default(|messageRes| {

                        let request = messageReq.init_root::<$testcase::RequestBuilder>();
                        let response = messageRes.init_root::<$testcase::ResponseBuilder>();
                        let expected = $testcase::setup_request(&mut rng, request);

                        let requestReader = request.as_reader();
                        $testcase::handle_request(requestReader, response);

                        let responseReader = response.as_reader();
                        if (! $testcase::check_response(responseReader, expected)) {
                            fail!("Incorrect response.");
                        }
                    });
                });
            }
        });
    )

static SCRATCH_SIZE : uint = 128 * 1024;
//static scratchSpace : [u8, .. 6 * SCRATCH_SIZE] = [0, .. 6 * SCRATCH_SIZE];

macro_rules! pass_by_bytes(
    ( $testcase:ident, $compression:ident, $iters:expr ) => ({
            let mut requestBytes : ~[u8] = std::vec::from_elem(SCRATCH_SIZE * 8, 0u8);
            let mut responseBytes : ~[u8] = std::vec::from_elem(SCRATCH_SIZE * 8, 0u8);
            let mut rng = common::FastRand::new();
            for _ in range(0, $iters) {
                capnp::message::MessageBuilder::new_default(|messageReq| {
                    capnp::message::MessageBuilder::new_default(|messageRes| {

                        let request = messageReq.init_root::<$testcase::RequestBuilder>();
                        let response = messageRes.init_root::<$testcase::ResponseBuilder>();
                        let expected = $testcase::setup_request(&mut rng, request);

                        {
                            let mut writer = capnp::io::ArrayOutputStream::new(requestBytes);
                            $compression::write_buffered(&mut writer, messageReq)
                        }

                        $compression::new_buffered_reader(
                            &mut capnp::io::ArrayInputStream::new(requestBytes),
                            capnp::message::DEFAULT_READER_OPTIONS,
                            |requestReader| {
                                let requestReader : $testcase::RequestReader = requestReader.get_root();
                                $testcase::handle_request(requestReader, response);
                            });

                        {
                            let mut writer = capnp::io::ArrayOutputStream::new(responseBytes);
                            $compression::write_buffered(&mut writer, messageRes)
                        }

                        $compression::new_buffered_reader(
                            &mut capnp::io::ArrayInputStream::new(responseBytes),
                            capnp::message::DEFAULT_READER_OPTIONS,
                            |responseReader| {
                                let responseReader : $testcase::ResponseReader = responseReader.get_root();
                                if (! $testcase::check_response(responseReader, expected)) {
                                    fail!("Incorrect response.");
                                }
                        });
                    })
                });
            }
        });
    )

macro_rules! server(
    ( $testcase:ident, $compression:ident, $iters:expr, $input:expr, $output:expr) => ({
            let mut outBuffered = capnp::io::BufferedOutputStreamWrapper::new(&mut $output);
            let mut inBuffered = capnp::io::BufferedInputStreamWrapper::new(&mut $input);
            for _ in range(0, $iters) {
                capnp::message::MessageBuilder::new_default(|messageRes| {
                    let response = messageRes.init_root::<$testcase::ResponseBuilder>();
                    $compression::new_buffered_reader(
                        &mut inBuffered,
                        capnp::message::DEFAULT_READER_OPTIONS,
                        |requestReader| {
                            let requestReader : $testcase::RequestReader = requestReader.get_root();
                            $testcase::handle_request(requestReader, response);
                        });
                    $compression::write_buffered(&mut outBuffered, messageRes);
                    outBuffered.flush();
                });
            }
        });
    )

macro_rules! sync_client(
    ( $testcase:ident, $compression:ident, $iters:expr) => ({
            let mut outStream = std::io::stdout();
            let mut inStream = std::io::stdin();
            let mut inBuffered = capnp::io::BufferedInputStreamWrapper::new(&mut inStream);
            let mut rng = common::FastRand::new();
            for _ in range(0, $iters) {
                capnp::message::MessageBuilder::new_default(|messageReq| {
                    let request = messageReq.init_root::<$testcase::RequestBuilder>();

                    let expected = $testcase::setup_request(&mut rng, request);
                    $compression::write(&mut outStream, messageReq);

                    $compression::new_buffered_reader(
                        &mut inBuffered,
                        capnp::message::DEFAULT_READER_OPTIONS,
                        |responseReader| {
                            let responseReader : $testcase::ResponseReader = responseReader.get_root();
                            assert!($testcase::check_response(responseReader, expected));
                    });
                });
            }
        });
    )

macro_rules! pass_by_pipe(
    ( $testcase:ident, $compression:ident, $iters:expr) => ({
            use std::io::process;

            let mut args = std::os::args();
            args[2] = ~"client";

            let config = process::ProcessConfig {
                program: args[0].as_slice(),
                args: args.slice(1, args.len()),
                env : None,
                cwd: None,
                io : [process::CreatePipe(true, false), // stdin
                      process::CreatePipe(false, true), // stdout
                      process::Ignored]
            };
            match process::Process::new(config) {
                Some(ref mut p) => {
                    p.io.pop();
                    let mut childStdOut = p.io.pop();
                    let mut childStdIn = p.io.pop();

                    server!($testcase, $compression, $iters, childStdOut, childStdIn);
                    println!("{}", p.wait());
                }
                None => {
                    println!("bummer");
                }
            }
        });
    )

macro_rules! do_testcase(
    ( $testcase:ident, $mode:expr, $reuse:expr, $compression:ident, $iters:expr ) => ({
            match $mode {
                ~"object" => pass_by_object!($testcase, $iters),
                ~"bytes" => pass_by_bytes!($testcase, $compression, $iters),
                ~"client" => sync_client!($testcase, $compression, $iters),
                ~"server" => {
                    let mut input = std::io::stdin();
                    let mut output = std::io::stdout();
                    server!($testcase, $compression, $iters, input, output)
                }
                ~"pipe" => pass_by_pipe!($testcase, $compression, $iters),
                s => fail!("unrecognized mode: {}", s)
            }
        });
    )

macro_rules! do_testcase1(
    ( $testcase:expr, $mode:expr, $reuse:expr, $compression:ident, $iters:expr) => ({
            match $testcase {
                ~"carsales" => do_testcase!(carsales, $mode, $reuse, $compression, $iters),
                ~"catrank" => do_testcase!(catrank, $mode, $reuse, $compression, $iters),
                ~"eval" => do_testcase!(eval, $mode, $reuse, $compression, $iters),
                s => fail!("unrecognized test case: {}", s)
            }
        });
    )

pub fn main () {

    let args = std::os::args();

    if (args.len() != 6) {
        println!("USAGE: {} CASE MODE REUSE COMPRESSION ITERATION_COUNT", args[0]);
        std::os::set_exit_status(1);
        return;
    }

    let iters = match from_str::<u64>(args[5]) {
        Some (n) => n,
        None => {
            println!("Could not parse a u64 from: {}", args[5]);
            std::os::set_exit_status(1);
            return;
        }
    };

    // For now, just insist that reuse = none
    match args[3] {
        ~"no-reuse" => {}
        _ => fail!("for now, 'no-reuse' is the only allowed option for REUSE")
    }

    match args[4] {
        ~"none" => do_testcase1!(args[1], args[2],  args[3], Uncompressed, iters),
        ~"packed" => do_testcase1!(args[1], args[2], args[3], Packed, iters),
        s => fail!("unrecognized compression: {}", s)
    }
}
<commit_msg>Use scratch space in benchmark builders<commit_after>/*
 * Copyright (c) 2013, David Renshaw (dwrenshaw@gmail.com)
 *
 * See the LICENSE file in the capnproto-rust root directory.
 */

#[feature(macro_rules)];
#[feature(globs)];

#[crate_type = "bin"];

extern mod capnp;

pub mod common;

pub mod carsales_capnp;
pub mod carsales;

pub mod catrank_capnp;
pub mod catrank;

pub mod eval_capnp;
pub mod eval;

mod Uncompressed {
    use capnp;
    use std;

    pub fn write<T : std::io::Writer>(writer: &mut T,
                                      message: &capnp::message::MessageBuilder) {
        capnp::serialize::write_message(writer, message);
    }

    pub fn write_buffered<T : std::io::Writer>(writer: &mut T,
                                               message: &capnp::message::MessageBuilder) {
        capnp::serialize::write_message(writer, message);
    }
/*
    pub fn new_reader<U : std::io::Reader, T>(
        inputStream : &mut U,
        options : capnp::message::ReaderOptions,
        cont : |&mut capnp::message::MessageReader| -> T) -> T {
        capnp::serialize::InputStreamMessageReader::new(inputStream, options, cont)
    }
*/
    pub fn new_buffered_reader<R: capnp::io::BufferedInputStream, T>(
        inputStream : &mut R,
        options : capnp::message::ReaderOptions,
        cont : |&mut capnp::message::MessageReader| -> T) -> T {
        capnp::serialize::InputStreamMessageReader::new(inputStream, options, cont)
    }
}

mod Packed {
    use capnp;
    use std;
    use capnp::serialize_packed::{write_packed_message, write_packed_message_unbuffered};

    pub fn write<T : std::io::Writer>(writer: &mut T,
                                      message: &capnp::message::MessageBuilder) {
        write_packed_message_unbuffered(writer, message);
    }

    pub fn write_buffered<T : capnp::io::BufferedOutputStream>(
        writer: &mut T,
        message: &capnp::message::MessageBuilder) {
        write_packed_message(writer, message);
    }
/*
    pub fn new_reader<U : std::io::Reader, T>(
        inputStream : &mut U,
        options : capnp::message::ReaderOptions,
        cont : |&mut capnp::message::MessageReader| -> T) -> T {
        capnp::serialize::InputStreamMessageReader::new(
            &mut capnp::serialize_packed::PackedInputStream{
                inner : &mut capnp::io::BufferedInputStreamWrapper::new(inputStream)
            },
            options, cont)
    }
*/
    pub fn new_buffered_reader<R:capnp::io::BufferedInputStream, T>(
        inputStream : &mut R,
        options : capnp::message::ReaderOptions,
        cont : |&mut capnp::message::MessageReader| -> T) -> T {
        capnp::serialize::InputStreamMessageReader::new(
            &mut capnp::serialize_packed::PackedInputStream{
                inner : inputStream
            },
            options, cont)
    }

}

static SCRATCH_SIZE : uint = 128 * 1024;
//static scratchSpace : [u8, .. 6 * SCRATCH_SIZE] = [0, .. 6 * SCRATCH_SIZE];

pub trait ScratchSpace {
    fn get_scratch<'a>(&mut self, idx : uint) -> capnp::message::FirstSegment<'a>;
}

pub struct NoScratch;

impl ScratchSpace for NoScratch {
    fn get_scratch<'a>(&mut self, _idx : uint) -> capnp::message::FirstSegment<'a> {
        capnp::message::NumWords(capnp::message::SUGGESTED_FIRST_SEGMENT_WORDS)
    }
}

pub struct UseScratch {
    scratch_space : ~[capnp::common::Word]
}

impl UseScratch {
    pub fn new() -> UseScratch {
        UseScratch {
            scratch_space : capnp::common::allocate_zeroed_words(SCRATCH_SIZE * 6)
        }
    }
}

impl ScratchSpace for UseScratch {
    fn get_scratch<'a>(&mut self, idx : uint) -> capnp::message::FirstSegment<'a> {
        assert!(idx < 6);
        unsafe {
            capnp::message::ZeroedWords(
                std::cast::transmute(
                    std::unstable::raw::Slice { data : self.scratch_space.unsafe_ref(idx * SCRATCH_SIZE),
                                                len : SCRATCH_SIZE }))
        }
    }
}

macro_rules! pass_by_object(
    ( $testcase:ident, $reuse:ident, $iters:expr ) => ({
            let mut rng = common::FastRand::new();
            for _ in range(0, $iters) {
                capnp::message::MessageBuilder::new($reuse.get_scratch(0),
                                                    capnp::message::SUGGESTED_ALLOCATION_STRATEGY,
                                                    |messageReq| {
                    capnp::message::MessageBuilder::new($reuse.get_scratch(1),
                                                        capnp::message::SUGGESTED_ALLOCATION_STRATEGY,
                                                        |messageRes| {

                        let request = messageReq.init_root::<$testcase::RequestBuilder>();
                        let response = messageRes.init_root::<$testcase::ResponseBuilder>();
                        let expected = $testcase::setup_request(&mut rng, request);

                        let requestReader = request.as_reader();
                        $testcase::handle_request(requestReader, response);

                        let responseReader = response.as_reader();
                        if (! $testcase::check_response(responseReader, expected)) {
                            fail!("Incorrect response.");
                        }
                    });
                });
            }
        });
    )

macro_rules! pass_by_bytes(
    ( $testcase:ident, $reuse:ident, $compression:ident, $iters:expr ) => ({
            let mut requestBytes : ~[u8] = std::vec::from_elem(SCRATCH_SIZE * 8, 0u8);
            let mut responseBytes : ~[u8] = std::vec::from_elem(SCRATCH_SIZE * 8, 0u8);
            let mut rng = common::FastRand::new();
            for _ in range(0, $iters) {
                capnp::message::MessageBuilder::new($reuse.get_scratch(0),
                                                    capnp::message::SUGGESTED_ALLOCATION_STRATEGY,
                                                    |messageReq| {
                    capnp::message::MessageBuilder::new($reuse.get_scratch(1),
                                                        capnp::message::SUGGESTED_ALLOCATION_STRATEGY,
                                                        |messageRes| {

                        let request = messageReq.init_root::<$testcase::RequestBuilder>();
                        let response = messageRes.init_root::<$testcase::ResponseBuilder>();
                        let expected = $testcase::setup_request(&mut rng, request);

                        {
                            let mut writer = capnp::io::ArrayOutputStream::new(requestBytes);
                            $compression::write_buffered(&mut writer, messageReq)
                        }

                        $compression::new_buffered_reader(
                            &mut capnp::io::ArrayInputStream::new(requestBytes),
                            capnp::message::DEFAULT_READER_OPTIONS,
                            |requestReader| {
                                let requestReader : $testcase::RequestReader = requestReader.get_root();
                                $testcase::handle_request(requestReader, response);
                            });

                        {
                            let mut writer = capnp::io::ArrayOutputStream::new(responseBytes);
                            $compression::write_buffered(&mut writer, messageRes)
                        }

                        $compression::new_buffered_reader(
                            &mut capnp::io::ArrayInputStream::new(responseBytes),
                            capnp::message::DEFAULT_READER_OPTIONS,
                            |responseReader| {
                                let responseReader : $testcase::ResponseReader = responseReader.get_root();
                                if (! $testcase::check_response(responseReader, expected)) {
                                    fail!("Incorrect response.");
                                }
                        });
                    })
                });
            }
        });
    )

macro_rules! server(
    ( $testcase:ident, $reuse:ident, $compression:ident, $iters:expr, $input:expr, $output:expr) => ({
            let mut outBuffered = capnp::io::BufferedOutputStreamWrapper::new(&mut $output);
            let mut inBuffered = capnp::io::BufferedInputStreamWrapper::new(&mut $input);
            for _ in range(0, $iters) {
                capnp::message::MessageBuilder::new($reuse.get_scratch(0),
                                                    capnp::message::SUGGESTED_ALLOCATION_STRATEGY,
                                                    |messageRes| {
                    let response = messageRes.init_root::<$testcase::ResponseBuilder>();
                    $compression::new_buffered_reader(
                        &mut inBuffered,
                        capnp::message::DEFAULT_READER_OPTIONS,
                        |requestReader| {
                            let requestReader : $testcase::RequestReader = requestReader.get_root();
                            $testcase::handle_request(requestReader, response);
                        });
                    $compression::write_buffered(&mut outBuffered, messageRes);
                    outBuffered.flush();
                });
            }
        });
    )

macro_rules! sync_client(
    ( $testcase:ident, $reuse:ident, $compression:ident, $iters:expr) => ({
            let mut outStream = std::io::stdout();
            let mut inStream = std::io::stdin();
            let mut inBuffered = capnp::io::BufferedInputStreamWrapper::new(&mut inStream);
            let mut rng = common::FastRand::new();
            for _ in range(0, $iters) {
                capnp::message::MessageBuilder::new($reuse.get_scratch(0),
                                                    capnp::message::SUGGESTED_ALLOCATION_STRATEGY,
                                                    |messageReq| {
                    let request = messageReq.init_root::<$testcase::RequestBuilder>();

                    let expected = $testcase::setup_request(&mut rng, request);
                    $compression::write(&mut outStream, messageReq);

                    $compression::new_buffered_reader(
                        &mut inBuffered,
                        capnp::message::DEFAULT_READER_OPTIONS,
                        |responseReader| {
                            let responseReader : $testcase::ResponseReader = responseReader.get_root();
                            assert!($testcase::check_response(responseReader, expected));
                    });
                });
            }
        });
    )

macro_rules! pass_by_pipe(
    ( $testcase:ident, $reuse:ident, $compression:ident, $iters:expr) => ({
            use std::io::process;

            let mut args = std::os::args();
            args[2] = ~"client";

            let config = process::ProcessConfig {
                program: args[0].as_slice(),
                args: args.slice(1, args.len()),
                env : None,
                cwd: None,
                io : [process::CreatePipe(true, false), // stdin
                      process::CreatePipe(false, true), // stdout
                      process::Ignored]
            };
            match process::Process::new(config) {
                Some(ref mut p) => {
                    p.io.pop();
                    let mut childStdOut = p.io.pop();
                    let mut childStdIn = p.io.pop();

                    server!($testcase, $reuse, $compression, $iters, childStdOut, childStdIn);
                    println!("{}", p.wait());
                }
                None => {
                    println!("bummer");
                }
            }
        });
    )

macro_rules! do_testcase(
    ( $testcase:ident, $mode:expr, $reuse:ident, $compression:ident, $iters:expr ) => ({
            match $mode {
                ~"object" => pass_by_object!($testcase, $reuse, $iters),
                ~"bytes" => pass_by_bytes!($testcase, $reuse, $compression, $iters),
                ~"client" => sync_client!($testcase, $reuse, $compression, $iters),
                ~"server" => {
                    let mut input = std::io::stdin();
                    let mut output = std::io::stdout();
                    server!($testcase, $reuse, $compression, $iters, input, output)
                }
                ~"pipe" => pass_by_pipe!($testcase, $reuse, $compression, $iters),
                s => fail!("unrecognized mode: {}", s)
            }
        });
    )

macro_rules! do_testcase1(
    ( $testcase:expr, $mode:expr, $reuse:ident, $compression:ident, $iters:expr) => ({
            match $testcase {
                ~"carsales" => do_testcase!(carsales, $mode, $reuse, $compression, $iters),
                ~"catrank" => do_testcase!(catrank, $mode, $reuse, $compression, $iters),
                ~"eval" => do_testcase!(eval, $mode, $reuse, $compression, $iters),
                s => fail!("unrecognized test case: {}", s)
            }
        });
    )

macro_rules! do_testcase2(
    ( $testcase:expr, $mode:expr, $reuse:expr, $compression:ident, $iters:expr) => ({
            match $reuse {
                ~"no-reuse" => {
                    let mut scratch = NoScratch;
                    do_testcase1!($testcase, $mode, scratch, $compression, $iters)
                }
                ~"reuse" => {
                    let mut scratch = UseScratch::new();
                    do_testcase1!($testcase, $mode, scratch, $compression, $iters)
                }
                s => fail!("unrecognized reuse option: {}", s)
            }
        });
    )

pub fn main () {

    let args = std::os::args();

    if (args.len() != 6) {
        println!("USAGE: {} CASE MODE REUSE COMPRESSION ITERATION_COUNT", args[0]);
        std::os::set_exit_status(1);
        return;
    }

    let iters = match from_str::<u64>(args[5]) {
        Some (n) => n,
        None => {
            println!("Could not parse a u64 from: {}", args[5]);
            std::os::set_exit_status(1);
            return;
        }
    };

    match args[4] {
        ~"none" => do_testcase2!(args[1], args[2],  args[3], Uncompressed, iters),
        ~"packed" => do_testcase2!(args[1], args[2], args[3], Packed, iters),
        s => fail!("unrecognized compression: {}", s)
    }
}
<|endoftext|>


<commit_before>use mio::*;
use mio::timer::Timer;
use mio_uds::{UnixListener,UnixStream};
use slab::Slab;
use std::fs;
use std::fmt;
use std::path::PathBuf;
use std::io::{self,ErrorKind};
use std::os::unix::fs::PermissionsExt;
use std::collections::HashMap;
use std::time::Duration;
use libc::pid_t;
use serde_json;

use sozu::messages::Order;
use sozu::network::{ProxyOrder,ServerMessage,ServerMessageStatus};
use sozu::channel::Channel;
use sozu_command::state::{HttpProxy,TlsProxy,ConfigState};
use sozu_command::data::{ConfigMessage,ConfigMessageAnswer,ConfigMessageStatus,ProxyType,RunState};
use sozu_command::config::Config;

pub mod orders;
pub mod client;

use self::client::{ConnReadError,CommandClient};

const SERVER: Token = Token(0);

#[derive(Copy,Clone,Debug,PartialEq,Eq,PartialOrd,Ord,Hash)]
pub struct FrontToken(pub usize);

impl From<usize> for FrontToken {
    fn from(val: usize) -> FrontToken {
        FrontToken(val)
    }
}

impl From<FrontToken> for usize {
    fn from(val: FrontToken) -> usize {
        val.0
    }
}

//#[derive(Serialize)]
pub struct Proxy {
  pub tag:           String,
  pub id:            u8,
  pub proxy_type:    ProxyType,
  pub channel:       Channel<ProxyOrder,ServerMessage>,
  pub state:         ConfigState,
  pub token:         Option<Token>,
  pub pid:           pid_t,
  pub run_state:     RunState,
  pub inflight:      HashMap<String,Order>,
}

impl Proxy {
  pub fn new(tag: String, id: u8, pid: pid_t, proxy_type: ProxyType, ip_address: String, port: u16, channel: Channel<ProxyOrder,ServerMessage>) -> Proxy {
    let state = match proxy_type {
      ProxyType::HTTP  => ConfigState::Http(HttpProxy::new(ip_address, port)),
      ProxyType::HTTPS => ConfigState::Tls(TlsProxy::new(ip_address, port)),
      _                => unimplemented!(),
    };

    Proxy {
      tag:        tag,
      id:         id,
      proxy_type: proxy_type,
      channel:    channel,
      state:      state,
      token:      None,
      pid:        pid,
      run_state:  RunState::Running,
      inflight:   HashMap::new(),
    }
  }
}

impl fmt::Debug for Proxy {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "Proxy {{ tag: {}, proxy_type: {:?}, state: {:?} }}", self.tag, self.proxy_type, self.state)
  }
}

#[derive(Deserialize,Serialize,Debug)]
pub struct StoredProxy {
  pub tag:        String,
  pub proxy_type: ProxyType,
  pub state:      ConfigState,
}

impl StoredProxy {
  pub fn from_proxy(proxy: &Proxy) -> StoredProxy {
    StoredProxy {
      tag:        proxy.tag.clone(),
      proxy_type: proxy.proxy_type.clone(),
      state:      proxy.state.clone(),
    }
  }
}

#[derive(Deserialize,Serialize,Debug)]
pub struct ProxyConfiguration {
  id:      String,
  proxies: Vec<StoredProxy>,
}

pub type Tag = String;

struct CommandServer {
  sock:            UnixListener,
  buffer_size:     usize,
  max_buffer_size: usize,
  conns:           Slab<CommandClient,FrontToken>,
  proxies:         HashMap<Token, (Tag, Proxy)>,
  next_ids:        HashMap<Tag,u8>,
  proxy_count:     usize,
  pub poll:        Poll,
  timer:           Timer<Token>,
  config:          Config,
  token_count:     usize,
}

impl CommandServer {
  fn accept(&mut self) -> io::Result<()> {
    debug!("server accepting socket");

    let acc = self.sock.accept();
    if let Ok(Some((sock, addr))) = acc {
      let conn = CommandClient::new(sock, self.buffer_size, self.max_buffer_size);
      let tok = self.conns.insert(conn)
        .ok().expect("could not add connection to slab");

      // Register the connection
      let token = self.from_front(tok);
      self.conns[tok].token = Some(token);
      let mut interest = Ready::hup();
      interest.insert(Ready::readable());
      interest.insert(Ready::writable());
      self.poll.register(&self.conns[tok].channel.sock, token, interest, PollOpt::edge())
        .ok().expect("could not register socket with event loop");

      let accept_interest = Ready::readable();
      self.poll.reregister(&self.sock, SERVER, accept_interest, PollOpt::edge());
      Ok(())
    } else {
      //FIXME: what do other cases mean, like Ok(None)?
      acc.map(|_| ())
    }
  }

  fn dispatch(&mut self, token: FrontToken, v: Vec<ConfigMessage>) {
    for message in &v {
      self.handle_client_message(token, message);
    }
  }

  fn new(srv: UnixListener, config: Config, proxies_map: HashMap<String, Vec<Proxy>>, buffer_size: usize, max_buffer_size: usize, poll: Poll) -> CommandServer {
    //FIXME: verify this
    poll.register(&srv, Token(0), Ready::readable(), PollOpt::edge() | PollOpt::oneshot()).unwrap();

    let mut next_ids: HashMap<String, u8> = HashMap::new();
    for (ref tag, ref value) in &proxies_map {
      next_ids.insert(tag.to_string(), value.len() as u8);
    }

    let mut proxies = HashMap::new();

    let mut token_count = 0;
    for (ref tag, ref mut proxy_list) in proxies_map {
      for proxy in proxy_list.drain(..) {
        token_count += 1;
        poll.register(&proxy.channel.sock, Token(token_count), Ready::all(), PollOpt::edge()).unwrap();
        proxies.insert(Token(token_count), (tag.to_string(), proxy));
      }
    }
    //let mut timer = timer::Builder::default().tick_duration(Duration::from_millis(1000)).build();
    //FIXME: registering the timer makes the timer thread spin too much
    let mut timer = timer::Timer::default();
    //poll.register(&timer, Token(1), Ready::readable(), PollOpt::edge()).unwrap();
    timer.set_timeout(Duration::from_millis(700), Token(0));
    CommandServer {
      sock:            srv,
      buffer_size:     buffer_size,
      max_buffer_size: max_buffer_size,
      conns:           Slab::with_capacity(128),
      proxies:         proxies,
      next_ids:        next_ids,
      proxy_count:     token_count,
      poll:            poll,
      timer:           timer,
      config:          config,
      token_count:     token_count,
    }
  }

  pub fn to_front(&self, token: Token) -> FrontToken {
    FrontToken(token.0 - self.proxy_count - 1)
  }

  pub fn from_front(&self, token: FrontToken) -> Token {
    Token(token.0 + self.proxy_count + 1)
  }

}

type Message = ();

impl CommandServer {
  pub fn run(&mut self) {
    let mut events = Events::with_capacity(1024);
    let poll_timeout = Some(Duration::from_millis(1000));
    loop {
      self.poll.poll(&mut events, poll_timeout).unwrap();
      for event in events.iter() {
        self.ready(event.token(), event.kind());
      }
    }
  }

  fn ready(&mut self, token: Token, events: Ready) {
    //trace!("ready: {:?} -> {:?}", token, events);
    match token {
      Token(0) => {
        if events.is_readable() {
          self.accept().unwrap();
        } else {
          error!("received writable for token 0");
        }
      },
      Token(i) if i < self.proxy_count + 1 => {
        let mut messages = {
          let &mut (ref tag, ref mut proxy) =  self.proxies.get_mut(&Token(i)).unwrap();
          proxy.channel.handle_events(events);
          proxy.channel.run();

          let mut messages = Vec::new();
          loop {
            let msg = proxy.channel.read_message();
            if msg.is_none() {
              break;
            } else {
              messages.push(msg.unwrap());
            }
          }

          messages
        };

        for msg in messages.drain(..) {
          self.proxy_handle_message(Token(i), msg);
        }

        {
          let &mut (ref tag, ref mut proxy) =  self.proxies.get_mut(&Token(i)).unwrap();
          proxy.channel.run();
        }

      },
      _ => {
        let conn_token = self.to_front(token);
        if self.conns.contains(conn_token) {
          self.conns[conn_token].channel.handle_events(events);
          self.conns[conn_token].channel.run();

          //FIXME: handle deconnection
          loop {
            let message = self.conns[conn_token].channel.read_message();

            // if the message was too large, we grow the buffer and retry to read if possible
            if message.is_none() {
              if self.conns[conn_token].channel.readiness.is_hup() {
                break;
              }

              if (self.conns[conn_token].channel.interest & self.conns[conn_token].channel.readiness).is_readable() {
                self.conns[conn_token].channel.run();
                continue;
              } else {
                break;
              }
            }

            let message = message.unwrap();
            self.handle_client_message(conn_token, &message);

          }

          self.conns[conn_token].channel.run();

          if self.conns[conn_token].channel.readiness.is_hup() {
            self.poll.deregister(&self.conns[conn_token].channel.sock);
            self.conns.remove(conn_token);
            trace!("closed client [{}]", token.0);
          }
        }
      }
    }
  }

  fn proxy_handle_message(&mut self, token: Token, msg: ServerMessage) {
    //println!("got answer msg: {:?}", msg);
    if msg.status != ServerMessageStatus::Processing {
      if let Some(&mut (_, ref mut proxy)) = self.proxies.get_mut(&token) {
        if let Some(order) = proxy.inflight.remove(&msg.id) {
          info!("REMOVING INFLIGHT MESSAGE {}: {:?}", msg.id, order);
          // handle message completion here
          // there will probably be other cases to handle in the future
          if order == Order::SoftStop || order == Order::HardStop {
            proxy.run_state = RunState::Stopped
          }
        }
      }
    }

    let answer = ConfigMessageAnswer::new(
      msg.id.clone(),
      match msg.status {
        ServerMessageStatus::Error(_)   => ConfigMessageStatus::Error,
        ServerMessageStatus::Ok         => ConfigMessageStatus::Ok,
        ServerMessageStatus::Processing => ConfigMessageStatus::Processing,
      },
      match msg.status {
        ServerMessageStatus::Error(s) => s.clone(),
        _                             => String::new(),
      },
      None,
    );

    info!("sending: {:?}", answer);
    for client in self.conns.iter_mut() {
      if let Some(index) = client.has_message_id(&msg.id) {
        client.write_message(&answer);
        if answer.status != ConfigMessageStatus::Processing {
          client.remove_message_id(index);
        }
      }
      client.channel.run();
    }
  }

}

pub fn start(config: Config, proxies: HashMap<String, Vec<Proxy>>) {
  let buffer_size     = config.command_buffer_size.unwrap_or(10000);
  let max_buffer_size = config.max_command_buffer_size.unwrap_or(buffer_size * 2);
  let saved_state     = config.saved_state.clone();

  let event_loop = Poll::new().unwrap();
  let addr = PathBuf::from(&config.command_socket);
  if let Err(e) = fs::remove_file(&addr) {
    match e.kind() {
      ErrorKind::NotFound => {},
      _ => {
        error!("could not delete previous socket at {:?}: {:?}", addr, e);
        return;
      }
    }
  }
  match UnixListener::bind(&addr) {
    Ok(srv) => {
      if let Err(e) =  fs::set_permissions(&addr, fs::Permissions::from_mode(0o600)) {
        error!("could not set the unix socket permissions: {:?}", e);
        fs::remove_file(&addr);
        return;
      }

      let mut server = CommandServer::new(srv, config.clone(), proxies, buffer_size, max_buffer_size, event_loop);

      server.load_static_application_configuration();

      saved_state.as_ref().map(|state_path| {
        server.load_state("INITIALIZATION", state_path);
      });

      info!("listen for connections");
      server.run();
      //event_loop.run(&mut CommandServer::new(srv, proxies, buffer_size, max_buffer_size)).unwrap()
    },
      Err(e) => {
        error!("could not create unix socket: {:?}", e);
      }
  }
}
<commit_msg>fix worker indexing<commit_after>use mio::*;
use mio::timer::Timer;
use mio_uds::{UnixListener,UnixStream};
use slab::Slab;
use std::fs;
use std::fmt;
use std::path::PathBuf;
use std::io::{self,ErrorKind};
use std::os::unix::fs::PermissionsExt;
use std::collections::HashMap;
use std::time::Duration;
use libc::pid_t;
use serde_json;

use sozu::messages::Order;
use sozu::network::{ProxyOrder,ServerMessage,ServerMessageStatus};
use sozu::channel::Channel;
use sozu_command::state::{HttpProxy,TlsProxy,ConfigState};
use sozu_command::data::{ConfigMessage,ConfigMessageAnswer,ConfigMessageStatus,ProxyType,RunState};
use sozu_command::config::Config;

pub mod orders;
pub mod client;

use self::client::{ConnReadError,CommandClient};

const SERVER: Token = Token(0);

#[derive(Copy,Clone,Debug,PartialEq,Eq,PartialOrd,Ord,Hash)]
pub struct FrontToken(pub usize);

impl From<usize> for FrontToken {
    fn from(val: usize) -> FrontToken {
        FrontToken(val)
    }
}

impl From<FrontToken> for usize {
    fn from(val: FrontToken) -> usize {
        val.0
    }
}

//#[derive(Serialize)]
pub struct Proxy {
  pub tag:           String,
  pub id:            u8,
  pub proxy_type:    ProxyType,
  pub channel:       Channel<ProxyOrder,ServerMessage>,
  pub state:         ConfigState,
  pub token:         Option<Token>,
  pub pid:           pid_t,
  pub run_state:     RunState,
  pub inflight:      HashMap<String,Order>,
}

impl Proxy {
  pub fn new(tag: String, id: u8, pid: pid_t, proxy_type: ProxyType, ip_address: String, port: u16, channel: Channel<ProxyOrder,ServerMessage>) -> Proxy {
    let state = match proxy_type {
      ProxyType::HTTP  => ConfigState::Http(HttpProxy::new(ip_address, port)),
      ProxyType::HTTPS => ConfigState::Tls(TlsProxy::new(ip_address, port)),
      _                => unimplemented!(),
    };

    Proxy {
      tag:        tag,
      id:         id,
      proxy_type: proxy_type,
      channel:    channel,
      state:      state,
      token:      None,
      pid:        pid,
      run_state:  RunState::Running,
      inflight:   HashMap::new(),
    }
  }
}

impl fmt::Debug for Proxy {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "Proxy {{ tag: {}, proxy_type: {:?}, state: {:?} }}", self.tag, self.proxy_type, self.state)
  }
}

#[derive(Deserialize,Serialize,Debug)]
pub struct StoredProxy {
  pub tag:        String,
  pub proxy_type: ProxyType,
  pub state:      ConfigState,
}

impl StoredProxy {
  pub fn from_proxy(proxy: &Proxy) -> StoredProxy {
    StoredProxy {
      tag:        proxy.tag.clone(),
      proxy_type: proxy.proxy_type.clone(),
      state:      proxy.state.clone(),
    }
  }
}

#[derive(Deserialize,Serialize,Debug)]
pub struct ProxyConfiguration {
  id:      String,
  proxies: Vec<StoredProxy>,
}

pub type Tag = String;

struct CommandServer {
  sock:            UnixListener,
  buffer_size:     usize,
  max_buffer_size: usize,
  conns:           Slab<CommandClient,FrontToken>,
  proxies:         HashMap<Token, (Tag, Proxy)>,
  next_ids:        HashMap<Tag,u8>,
  proxy_count:     usize,
  pub poll:        Poll,
  timer:           Timer<Token>,
  config:          Config,
  token_count:     usize,
}

impl CommandServer {
  fn accept(&mut self) -> io::Result<()> {
    debug!("server accepting socket");

    let acc = self.sock.accept();
    if let Ok(Some((sock, addr))) = acc {
      let conn = CommandClient::new(sock, self.buffer_size, self.max_buffer_size);
      let tok = self.conns.insert(conn)
        .ok().expect("could not add connection to slab");

      // Register the connection
      let token = self.from_front(tok);
      self.conns[tok].token = Some(token);
      let mut interest = Ready::hup();
      interest.insert(Ready::readable());
      interest.insert(Ready::writable());
      self.poll.register(&self.conns[tok].channel.sock, token, interest, PollOpt::edge())
        .ok().expect("could not register socket with event loop");

      let accept_interest = Ready::readable();
      self.poll.reregister(&self.sock, SERVER, accept_interest, PollOpt::edge());
      Ok(())
    } else {
      //FIXME: what do other cases mean, like Ok(None)?
      acc.map(|_| ())
    }
  }

  fn dispatch(&mut self, token: FrontToken, v: Vec<ConfigMessage>) {
    for message in &v {
      self.handle_client_message(token, message);
    }
  }

  fn new(srv: UnixListener, config: Config, proxies_map: HashMap<String, Vec<Proxy>>, buffer_size: usize, max_buffer_size: usize, poll: Poll) -> CommandServer {
    //FIXME: verify this
    poll.register(&srv, Token(0), Ready::readable(), PollOpt::edge() | PollOpt::oneshot()).unwrap();

    let mut next_ids: HashMap<String, u8> = HashMap::new();
    for (ref tag, ref value) in &proxies_map {
      next_ids.insert(tag.to_string(), (value.len() - 1) as u8);
    }

    let mut proxies = HashMap::new();

    let mut token_count = 0;
    for (ref tag, ref mut proxy_list) in proxies_map {
      for proxy in proxy_list.drain(..) {
        token_count += 1;
        poll.register(&proxy.channel.sock, Token(token_count), Ready::all(), PollOpt::edge()).unwrap();
        proxies.insert(Token(token_count), (tag.to_string(), proxy));
      }
    }
    //let mut timer = timer::Builder::default().tick_duration(Duration::from_millis(1000)).build();
    //FIXME: registering the timer makes the timer thread spin too much
    let mut timer = timer::Timer::default();
    //poll.register(&timer, Token(1), Ready::readable(), PollOpt::edge()).unwrap();
    timer.set_timeout(Duration::from_millis(700), Token(0));
    CommandServer {
      sock:            srv,
      buffer_size:     buffer_size,
      max_buffer_size: max_buffer_size,
      conns:           Slab::with_capacity(128),
      proxies:         proxies,
      next_ids:        next_ids,
      proxy_count:     token_count,
      poll:            poll,
      timer:           timer,
      config:          config,
      token_count:     token_count,
    }
  }

  pub fn to_front(&self, token: Token) -> FrontToken {
    FrontToken(token.0 - self.proxy_count - 1)
  }

  pub fn from_front(&self, token: FrontToken) -> Token {
    Token(token.0 + self.proxy_count + 1)
  }

}

type Message = ();

impl CommandServer {
  pub fn run(&mut self) {
    let mut events = Events::with_capacity(1024);
    let poll_timeout = Some(Duration::from_millis(1000));
    loop {
      self.poll.poll(&mut events, poll_timeout).unwrap();
      for event in events.iter() {
        self.ready(event.token(), event.kind());
      }
    }
  }

  fn ready(&mut self, token: Token, events: Ready) {
    //trace!("ready: {:?} -> {:?}", token, events);
    match token {
      Token(0) => {
        if events.is_readable() {
          self.accept().unwrap();
        } else {
          error!("received writable for token 0");
        }
      },
      Token(i) if i < self.proxy_count + 1 => {
        let mut messages = {
          let &mut (ref tag, ref mut proxy) =  self.proxies.get_mut(&Token(i)).unwrap();
          proxy.channel.handle_events(events);
          proxy.channel.run();

          let mut messages = Vec::new();
          loop {
            let msg = proxy.channel.read_message();
            if msg.is_none() {
              break;
            } else {
              messages.push(msg.unwrap());
            }
          }

          messages
        };

        for msg in messages.drain(..) {
          self.proxy_handle_message(Token(i), msg);
        }

        {
          let &mut (ref tag, ref mut proxy) =  self.proxies.get_mut(&Token(i)).unwrap();
          proxy.channel.run();
        }

      },
      _ => {
        let conn_token = self.to_front(token);
        if self.conns.contains(conn_token) {
          self.conns[conn_token].channel.handle_events(events);
          self.conns[conn_token].channel.run();

          //FIXME: handle deconnection
          loop {
            let message = self.conns[conn_token].channel.read_message();

            // if the message was too large, we grow the buffer and retry to read if possible
            if message.is_none() {
              if self.conns[conn_token].channel.readiness.is_hup() {
                break;
              }

              if (self.conns[conn_token].channel.interest & self.conns[conn_token].channel.readiness).is_readable() {
                self.conns[conn_token].channel.run();
                continue;
              } else {
                break;
              }
            }

            let message = message.unwrap();
            self.handle_client_message(conn_token, &message);

          }

          self.conns[conn_token].channel.run();

          if self.conns[conn_token].channel.readiness.is_hup() {
            self.poll.deregister(&self.conns[conn_token].channel.sock);
            self.conns.remove(conn_token);
            trace!("closed client [{}]", token.0);
          }
        }
      }
    }
  }

  fn proxy_handle_message(&mut self, token: Token, msg: ServerMessage) {
    //println!("got answer msg: {:?}", msg);
    if msg.status != ServerMessageStatus::Processing {
      if let Some(&mut (_, ref mut proxy)) = self.proxies.get_mut(&token) {
        if let Some(order) = proxy.inflight.remove(&msg.id) {
          info!("REMOVING INFLIGHT MESSAGE {}: {:?}", msg.id, order);
          // handle message completion here
          // there will probably be other cases to handle in the future
          if order == Order::SoftStop || order == Order::HardStop {
            proxy.run_state = RunState::Stopped
          }
        }
      }
    }

    let answer = ConfigMessageAnswer::new(
      msg.id.clone(),
      match msg.status {
        ServerMessageStatus::Error(_)   => ConfigMessageStatus::Error,
        ServerMessageStatus::Ok         => ConfigMessageStatus::Ok,
        ServerMessageStatus::Processing => ConfigMessageStatus::Processing,
      },
      match msg.status {
        ServerMessageStatus::Error(s) => s.clone(),
        _                             => String::new(),
      },
      None,
    );

    info!("sending: {:?}", answer);
    for client in self.conns.iter_mut() {
      if let Some(index) = client.has_message_id(&msg.id) {
        client.write_message(&answer);
        if answer.status != ConfigMessageStatus::Processing {
          client.remove_message_id(index);
        }
      }
      client.channel.run();
    }
  }

}

pub fn start(config: Config, proxies: HashMap<String, Vec<Proxy>>) {
  let buffer_size     = config.command_buffer_size.unwrap_or(10000);
  let max_buffer_size = config.max_command_buffer_size.unwrap_or(buffer_size * 2);
  let saved_state     = config.saved_state.clone();

  let event_loop = Poll::new().unwrap();
  let addr = PathBuf::from(&config.command_socket);
  if let Err(e) = fs::remove_file(&addr) {
    match e.kind() {
      ErrorKind::NotFound => {},
      _ => {
        error!("could not delete previous socket at {:?}: {:?}", addr, e);
        return;
      }
    }
  }
  match UnixListener::bind(&addr) {
    Ok(srv) => {
      if let Err(e) =  fs::set_permissions(&addr, fs::Permissions::from_mode(0o600)) {
        error!("could not set the unix socket permissions: {:?}", e);
        fs::remove_file(&addr);
        return;
      }

      let mut server = CommandServer::new(srv, config.clone(), proxies, buffer_size, max_buffer_size, event_loop);

      server.load_static_application_configuration();

      saved_state.as_ref().map(|state_path| {
        server.load_state("INITIALIZATION", state_path);
      });

      info!("listen for connections");
      server.run();
      //event_loop.run(&mut CommandServer::new(srv, proxies, buffer_size, max_buffer_size)).unwrap()
    },
      Err(e) => {
        error!("could not create unix socket: {:?}", e);
      }
  }
}
<|endoftext|>


<commit_before>struct Queue<T> {
  older: Vec<T>,
  younger: Vec<T>
}

impl<T> Queue<T> {
  fn new() -> Self {
    Queue { older: Vec::new() , younger: Vec::new() }
  }

  fn is_empty(&self) -> bool {
    self.older.is_empty() && self.younger.is_empty()
  }

  fn push(&mut self, c: T) {
    self.younger.push(c);
  }

  fn pop(&mut self) -> Option<T> {
    if self.older.is_empty() {
      if self.younger.is_empty() {
        return None;
      }
      use std::mem::swap;
      swap(&mut self.older, &mut self.younger);
      self.older.reverse();
    }

    self.older.pop()
  }

  // Here will take ownership for queue
  fn split(self) -> (Vec<T>, Vec<T>) {
    (self.older, self.younger)
  }
}

let mut q = Queue::new();
q.push('0');
q.push('1');
assert_eq!(q.pop(), Some('0'));

q.push('w');
assert_eq!(q.pop(), Some('1'));
assert_eq!(q.pop(), Some('w'));
assert_eq!(q.pop(), None);

assert!(q.is_empty());
q.push('*');
assert!(!q.is_empty());
q.pop();

q.push('P');
q.push('X');
assert_eq!(q.pop(), Some('P'));
q.push('Z');

let(older, younger) = q.split();
assert_eq!(older, vec!['X']);
assert_eq!(younger, vec!['Z']);
<commit_msg>One more trailing spaces kill<commit_after>struct Queue<T> {
  older: Vec<T>,
  younger: Vec<T>
}

impl<T> Queue<T> {
  fn new() -> Self {
    Queue { older: Vec::new() , younger: Vec::new() }
  }

  fn is_empty(&self) -> bool {
    self.older.is_empty() && self.younger.is_empty()
  }

  fn push(&mut self, c: T) {
    self.younger.push(c);
  }

  fn pop(&mut self) -> Option<T> {
    if self.older.is_empty() {
      if self.younger.is_empty() {
        return None;
      }
      use std::mem::swap;
      swap(&mut self.older, &mut self.younger);
      self.older.reverse();
    }

    self.older.pop()
  }

  // Here will take ownership for queue
  fn split(self) -> (Vec<T>, Vec<T>) {
    (self.older, self.younger)
  }
}

let mut q = Queue::new();
q.push('0');
q.push('1');
assert_eq!(q.pop(), Some('0'));

q.push('w');
assert_eq!(q.pop(), Some('1'));
assert_eq!(q.pop(), Some('w'));
assert_eq!(q.pop(), None);

assert!(q.is_empty());
q.push('*');
assert!(!q.is_empty());
q.pop();

q.push('P');
q.push('X');
assert_eq!(q.pop(), Some('P'));
q.push('Z');

let(older, younger) = q.split();
assert_eq!(older, vec!['X']);
assert_eq!(younger, vec!['Z']);
<|endoftext|>