<commit_before>// Copyright (c) 2020 rust-mysql-simple contributors
//
// 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. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

use bufstream::BufStream;
use io_enum::*;
#[cfg(windows)]
use named_pipe as np;
use native_tls::{Certificate, Identity, TlsConnector, TlsStream};

#[cfg(unix)]
use std::os::unix;
use std::{
    fmt,
    fs::File,
    io::{self, Read as _},
    net::{self, SocketAddr},
    time::Duration,
};

use crate::{
    error::{
        DriverError::{ConnectTimeout, CouldNotConnect},
        Error::DriverError,
        Result as MyResult,
    },
    SslOpts,
};
use crate::conn::opts::CertificateFormat;

mod tcp;

#[derive(Debug, Read, Write)]
pub enum Stream {
    #[cfg(unix)]
    SocketStream(BufStream<unix::net::UnixStream>),
    #[cfg(windows)]
    SocketStream(BufStream<np::PipeClient>),
    TcpStream(TcpStream),
}

impl Stream {
    #[cfg(unix)]
    pub fn connect_socket(
        socket: &str,
        read_timeout: Option<Duration>,
        write_timeout: Option<Duration>,
    ) -> MyResult<Stream> {
        match unix::net::UnixStream::connect(socket) {
            Ok(stream) => {
                stream.set_read_timeout(read_timeout)?;
                stream.set_write_timeout(write_timeout)?;
                Ok(Stream::SocketStream(BufStream::new(stream)))
            }
            Err(e) => {
                let addr = socket.to_string();
                let desc = e.to_string();
                Err(DriverError(CouldNotConnect(Some((addr, desc, e.kind())))))
            }
        }
    }

    #[cfg(windows)]
    pub fn connect_socket(
        socket: &str,
        read_timeout: Option<Duration>,
        write_timeout: Option<Duration>,
    ) -> MyResult<Stream> {
        let full_name = format!(r"\\.\pipe\{}", socket);
        match np::PipeClient::connect(full_name.clone()) {
            Ok(mut stream) => {
                stream.set_read_timeout(read_timeout);
                stream.set_write_timeout(write_timeout);
                Ok(Stream::SocketStream(BufStream::new(stream)))
            }
            Err(e) => {
                let desc = format!("{}", e);
                Err(DriverError(CouldNotConnect(Some((
                    full_name,
                    desc,
                    e.kind(),
                )))))
            }
        }
    }

    #[cfg(all(not(unix), not(windows)))]
    fn connect_socket(&mut self) -> MyResult<()> {
        unimplemented!("Sockets is not implemented on current platform");
    }

    pub fn connect_tcp(
        ip_or_hostname: &str,
        port: u16,
        read_timeout: Option<Duration>,
        write_timeout: Option<Duration>,
        tcp_keepalive_time: Option<u32>,
        nodelay: bool,
        tcp_connect_timeout: Option<Duration>,
        bind_address: Option<SocketAddr>,
    ) -> MyResult<Stream> {
        let mut builder = tcp::MyTcpBuilder::new((ip_or_hostname, port));
        builder
            .connect_timeout(tcp_connect_timeout)
            .read_timeout(read_timeout)
            .write_timeout(write_timeout)
            .keepalive_time_ms(tcp_keepalive_time)
            .nodelay(nodelay)
            .bind_address(bind_address);
        builder
            .connect()
            .map(|stream| Stream::TcpStream(TcpStream::Insecure(BufStream::new(stream))))
            .map_err(|err| {
                if err.kind() == io::ErrorKind::TimedOut {
                    DriverError(ConnectTimeout)
                } else {
                    let addr = format!("{}:{}", ip_or_hostname, port);
                    let desc = format!("{}", err);
                    DriverError(CouldNotConnect(Some((addr, desc, err.kind()))))
                }
            })
    }

    pub fn is_insecure(&self) -> bool {
        match self {
            Stream::TcpStream(TcpStream::Insecure(_)) => true,
            _ => false,
        }
    }

    pub fn is_socket(&self) -> bool {
        match self {
            Stream::SocketStream(_) => true,
            _ => false,
        }
    }

    pub fn make_secure(self, host: url::Host, ssl_opts: SslOpts) -> MyResult<Stream> {
        if self.is_socket() {
            // won't secure socket connection
            return Ok(self);
        }

        let domain = match host {
            url::Host::Domain(domain) => domain,
            url::Host::Ipv4(ip) => ip.to_string(),
            url::Host::Ipv6(ip) => ip.to_string(),
        };

        let mut builder = TlsConnector::builder();
        match ssl_opts.root_cert_path() {
            Some(root_cert_path) => {
                let mut root_cert_der = vec![];
                let mut root_cert_file = File::open(root_cert_path)?;
                root_cert_file.read_to_end(&mut root_cert_der)?;
                let root_cert = match ssl_opts.root_cert_format().unwrap() {
                    CertificateFormat::Der => Certificate::from_der(&*root_cert_der)?,
                    CertificateFormat::Pem => Certificate::from_pem(&*root_cert_der)?,
                };
                builder.add_root_certificate(root_cert);
            }
            None => (),
        }
        if let Some(pkcs12_path) = ssl_opts.pkcs12_path() {
            let der = std::fs::read(pkcs12_path)?;
            let identity = Identity::from_pkcs12(&*der, ssl_opts.password().unwrap_or(""))?;
            builder.identity(identity);
        }
        builder.danger_accept_invalid_hostnames(ssl_opts.skip_domain_validation());
        builder.danger_accept_invalid_certs(ssl_opts.accept_invalid_certs());
        let tls_connector = builder.build()?;
        match self {
            Stream::TcpStream(tcp_stream) => match tcp_stream {
                TcpStream::Insecure(insecure_stream) => {
                    let inner = insecure_stream.into_inner().map_err(io::Error::from)?;
                    let secure_stream = tls_connector.connect(&domain, inner)?;
                    Ok(Stream::TcpStream(TcpStream::Secure(BufStream::new(
                        secure_stream,
                    ))))
                }
                TcpStream::Secure(_) => Ok(Stream::TcpStream(tcp_stream)),
            },
            _ => unreachable!(),
        }
    }
}

#[derive(Read, Write)]
pub enum TcpStream {
    Secure(BufStream<TlsStream<net::TcpStream>>),
    Insecure(BufStream<net::TcpStream>),
}

impl fmt::Debug for TcpStream {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            TcpStream::Secure(ref s) => write!(f, "Secure stream {:?}", s),
            TcpStream::Insecure(ref s) => write!(f, "Insecure stream {:?}", s),
        }
    }
}
<commit_msg>run fmt<commit_after>// Copyright (c) 2020 rust-mysql-simple contributors
//
// 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. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

use bufstream::BufStream;
use io_enum::*;
#[cfg(windows)]
use named_pipe as np;
use native_tls::{Certificate, Identity, TlsConnector, TlsStream};

#[cfg(unix)]
use std::os::unix;
use std::{
    fmt,
    fs::File,
    io::{self, Read as _},
    net::{self, SocketAddr},
    time::Duration,
};

use crate::conn::opts::CertificateFormat;
use crate::{
    error::{
        DriverError::{ConnectTimeout, CouldNotConnect},
        Error::DriverError,
        Result as MyResult,
    },
    SslOpts,
};

mod tcp;

#[derive(Debug, Read, Write)]
pub enum Stream {
    #[cfg(unix)]
    SocketStream(BufStream<unix::net::UnixStream>),
    #[cfg(windows)]
    SocketStream(BufStream<np::PipeClient>),
    TcpStream(TcpStream),
}

impl Stream {
    #[cfg(unix)]
    pub fn connect_socket(
        socket: &str,
        read_timeout: Option<Duration>,
        write_timeout: Option<Duration>,
    ) -> MyResult<Stream> {
        match unix::net::UnixStream::connect(socket) {
            Ok(stream) => {
                stream.set_read_timeout(read_timeout)?;
                stream.set_write_timeout(write_timeout)?;
                Ok(Stream::SocketStream(BufStream::new(stream)))
            }
            Err(e) => {
                let addr = socket.to_string();
                let desc = e.to_string();
                Err(DriverError(CouldNotConnect(Some((addr, desc, e.kind())))))
            }
        }
    }

    #[cfg(windows)]
    pub fn connect_socket(
        socket: &str,
        read_timeout: Option<Duration>,
        write_timeout: Option<Duration>,
    ) -> MyResult<Stream> {
        let full_name = format!(r"\\.\pipe\{}", socket);
        match np::PipeClient::connect(full_name.clone()) {
            Ok(mut stream) => {
                stream.set_read_timeout(read_timeout);
                stream.set_write_timeout(write_timeout);
                Ok(Stream::SocketStream(BufStream::new(stream)))
            }
            Err(e) => {
                let desc = format!("{}", e);
                Err(DriverError(CouldNotConnect(Some((
                    full_name,
                    desc,
                    e.kind(),
                )))))
            }
        }
    }

    #[cfg(all(not(unix), not(windows)))]
    fn connect_socket(&mut self) -> MyResult<()> {
        unimplemented!("Sockets is not implemented on current platform");
    }

    pub fn connect_tcp(
        ip_or_hostname: &str,
        port: u16,
        read_timeout: Option<Duration>,
        write_timeout: Option<Duration>,
        tcp_keepalive_time: Option<u32>,
        nodelay: bool,
        tcp_connect_timeout: Option<Duration>,
        bind_address: Option<SocketAddr>,
    ) -> MyResult<Stream> {
        let mut builder = tcp::MyTcpBuilder::new((ip_or_hostname, port));
        builder
            .connect_timeout(tcp_connect_timeout)
            .read_timeout(read_timeout)
            .write_timeout(write_timeout)
            .keepalive_time_ms(tcp_keepalive_time)
            .nodelay(nodelay)
            .bind_address(bind_address);
        builder
            .connect()
            .map(|stream| Stream::TcpStream(TcpStream::Insecure(BufStream::new(stream))))
            .map_err(|err| {
                if err.kind() == io::ErrorKind::TimedOut {
                    DriverError(ConnectTimeout)
                } else {
                    let addr = format!("{}:{}", ip_or_hostname, port);
                    let desc = format!("{}", err);
                    DriverError(CouldNotConnect(Some((addr, desc, err.kind()))))
                }
            })
    }

    pub fn is_insecure(&self) -> bool {
        match self {
            Stream::TcpStream(TcpStream::Insecure(_)) => true,
            _ => false,
        }
    }

    pub fn is_socket(&self) -> bool {
        match self {
            Stream::SocketStream(_) => true,
            _ => false,
        }
    }

    pub fn make_secure(self, host: url::Host, ssl_opts: SslOpts) -> MyResult<Stream> {
        if self.is_socket() {
            // won't secure socket connection
            return Ok(self);
        }

        let domain = match host {
            url::Host::Domain(domain) => domain,
            url::Host::Ipv4(ip) => ip.to_string(),
            url::Host::Ipv6(ip) => ip.to_string(),
        };

        let mut builder = TlsConnector::builder();
        match ssl_opts.root_cert_path() {
            Some(root_cert_path) => {
                let mut root_cert_der = vec![];
                let mut root_cert_file = File::open(root_cert_path)?;
                root_cert_file.read_to_end(&mut root_cert_der)?;
                let root_cert = match ssl_opts.root_cert_format().unwrap() {
                    CertificateFormat::Der => Certificate::from_der(&*root_cert_der)?,
                    CertificateFormat::Pem => Certificate::from_pem(&*root_cert_der)?,
                };
                builder.add_root_certificate(root_cert);
            }
            None => (),
        }
        if let Some(pkcs12_path) = ssl_opts.pkcs12_path() {
            let der = std::fs::read(pkcs12_path)?;
            let identity = Identity::from_pkcs12(&*der, ssl_opts.password().unwrap_or(""))?;
            builder.identity(identity);
        }
        builder.danger_accept_invalid_hostnames(ssl_opts.skip_domain_validation());
        builder.danger_accept_invalid_certs(ssl_opts.accept_invalid_certs());
        let tls_connector = builder.build()?;
        match self {
            Stream::TcpStream(tcp_stream) => match tcp_stream {
                TcpStream::Insecure(insecure_stream) => {
                    let inner = insecure_stream.into_inner().map_err(io::Error::from)?;
                    let secure_stream = tls_connector.connect(&domain, inner)?;
                    Ok(Stream::TcpStream(TcpStream::Secure(BufStream::new(
                        secure_stream,
                    ))))
                }
                TcpStream::Secure(_) => Ok(Stream::TcpStream(tcp_stream)),
            },
            _ => unreachable!(),
        }
    }
}

#[derive(Read, Write)]
pub enum TcpStream {
    Secure(BufStream<TlsStream<net::TcpStream>>),
    Insecure(BufStream<net::TcpStream>),
}

impl fmt::Debug for TcpStream {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            TcpStream::Secure(ref s) => write!(f, "Secure stream {:?}", s),
            TcpStream::Insecure(ref s) => write!(f, "Insecure stream {:?}", s),
        }
    }
}
<|endoftext|>


<commit_before>//! # io
//!
//! IO helper functions
//!

#[cfg(test)]
#[path = "io_test.rs"]
mod io_test;

use fsio::file::modify_file;
use fsio::path::from_path::FromPath;
use fsio::path::get_temporary_file_path;
use glob::glob;
use ignore::WalkBuilder;
use std::collections::HashSet;
use std::fs::File;
use std::io;
use std::path::PathBuf;

pub(crate) fn create_text_file(text: &str, extension: &str) -> String {
    let file_path = get_temporary_file_path(extension);

    match fsio::file::write_text_file(&file_path, text) {
        Ok(_) => file_path,
        Err(error) => {
            error!("Unable to create file: {} {:#?}", &file_path, &error);
            panic!("Unable to create file, error: {}", error);
        }
    }
}

pub(crate) fn create_file(
    write_content: &Fn(&mut File) -> io::Result<()>,
    extension: &str,
) -> String {
    let file_path = get_temporary_file_path(extension);

    match modify_file(&file_path, write_content, false) {
        Ok(_) => file_path,
        Err(error) => {
            error!("Unable to write to file: {} {:#?}", &file_path, &error);
            panic!("Unable to write to file, error: {}", error);
        }
    }
}

pub(crate) fn delete_file(file: &str) {
    match fsio::file::delete(file) {
        Ok(_) => debug!("File deleted: {}", &file),
        Err(error) => debug!("Unable to delete file: {} {:#?}", &file, error),
    }
}

pub(crate) fn write_text_file(file_path: &str, text: &str) -> bool {
    match fsio::file::write_text_file(file_path, text) {
        Ok(_) => true,
        Err(_) => false,
    }
}

pub(crate) fn read_text_file(file_path: &PathBuf) -> String {
    debug!("Opening file: {:#?}", &file_path);

    match fsio::file::read_text_file(file_path) {
        Ok(content) => content,
        Err(error) => panic!("Unable to read file: {:?} error: {:#?}", file_path, error),
    }
}

pub(crate) fn get_path_list(
    glob_pattern: &str,
    include_files: bool,
    include_dirs: bool,
    ignore_type: Option<String>,
) -> Vec<String> {
    let mut path_list = vec![];
    match glob(glob_pattern) {
        Ok(paths) => {
            for entry in paths {
                match entry {
                    Ok(path) => {
                        let add =
                            (include_dirs && path.is_dir()) || include_files && path.is_file();

                        if add {
                            let mut value_string: String = FromPath::from_path(&path);
                            value_string = value_string.replace("\\", "/");
                            if !value_string.starts_with("./") {
                                value_string.insert_str(0, "./");
                            }

                            path_list.push(value_string);
                        }
                    }
                    Err(error) => {
                        error!(
                            "Error while iterating over path entries of glob: {}, error: {:#?}",
                            glob_pattern, error
                        );
                        return vec![];
                    }
                }
            }
        }
        Err(error) => {
            error!(
                "Error while running glob: {}, error: {:#?}",
                glob_pattern, error
            );
            return vec![];
        }
    }

    if !path_list.is_empty() {
        if let Some(ignore_type_value) = ignore_type {
            let mut included_paths = HashSet::new();

            match ignore_type_value.as_str() {
                "git" => {
                    for entry in WalkBuilder::new("./")
                        .hidden(true)
                        .parents(true)
                        .git_ignore(true)
                        .git_exclude(true)
                        .build()
                    {
                        match entry {
                            Ok(path) => {
                                let mut value_string: String = FromPath::from_path(&path.path());
                                value_string = value_string.replace("\\", "/");
                                included_paths.insert(value_string);
                            }
                            Err(error) => error!(
                                "Error while running git ignore path checks, error: {:#?}",
                                error
                            ),
                        }
                    }
                }
                _ => error!("Unsupported ignore type: {}", &ignore_type_value),
            };

            println!("path_list: {:#?}", &path_list); //todo re
            println!("included_paths: {:#?}", &included_paths); //todo re
            if included_paths.is_empty() {
                path_list.clear();
            } else {
                let org_path_list = path_list;
                path_list = vec![];
                for path in org_path_list {
                    if included_paths.contains(&path) {
                        path_list.push(path);
                    }
                }
            }
        }
    }

    path_list
}
<commit_msg>Support path glob (with optional gitignore support) environment variables #542<commit_after>//! # io
//!
//! IO helper functions
//!

#[cfg(test)]
#[path = "io_test.rs"]
mod io_test;

use fsio::file::modify_file;
use fsio::path::from_path::FromPath;
use fsio::path::get_temporary_file_path;
use glob::glob;
use ignore::WalkBuilder;
use std::collections::HashSet;
use std::fs::File;
use std::io;
use std::path::PathBuf;

pub(crate) fn create_text_file(text: &str, extension: &str) -> String {
    let file_path = get_temporary_file_path(extension);

    match fsio::file::write_text_file(&file_path, text) {
        Ok(_) => file_path,
        Err(error) => {
            error!("Unable to create file: {} {:#?}", &file_path, &error);
            panic!("Unable to create file, error: {}", error);
        }
    }
}

pub(crate) fn create_file(
    write_content: &Fn(&mut File) -> io::Result<()>,
    extension: &str,
) -> String {
    let file_path = get_temporary_file_path(extension);

    match modify_file(&file_path, write_content, false) {
        Ok(_) => file_path,
        Err(error) => {
            error!("Unable to write to file: {} {:#?}", &file_path, &error);
            panic!("Unable to write to file, error: {}", error);
        }
    }
}

pub(crate) fn delete_file(file: &str) {
    match fsio::file::delete(file) {
        Ok(_) => debug!("File deleted: {}", &file),
        Err(error) => debug!("Unable to delete file: {} {:#?}", &file, error),
    }
}

pub(crate) fn write_text_file(file_path: &str, text: &str) -> bool {
    match fsio::file::write_text_file(file_path, text) {
        Ok(_) => true,
        Err(_) => false,
    }
}

pub(crate) fn read_text_file(file_path: &PathBuf) -> String {
    debug!("Opening file: {:#?}", &file_path);

    match fsio::file::read_text_file(file_path) {
        Ok(content) => content,
        Err(error) => panic!("Unable to read file: {:?} error: {:#?}", file_path, error),
    }
}

pub(crate) fn get_path_list(
    glob_pattern: &str,
    include_files: bool,
    include_dirs: bool,
    ignore_type: Option<String>,
) -> Vec<String> {
    let mut path_list = vec![];
    match glob(glob_pattern) {
        Ok(paths) => {
            for entry in paths {
                match entry {
                    Ok(path) => {
                        let add =
                            (include_dirs && path.is_dir()) || (include_files && path.is_file());

                        if add {
                            let mut value_string: String = FromPath::from_path(&path);
                            value_string = value_string.replace("\\", "/");
                            if !value_string.starts_with("./") {
                                value_string.insert_str(0, "./");
                            }

                            path_list.push(value_string);
                        }
                    }
                    Err(error) => {
                        error!(
                            "Error while iterating over path entries of glob: {}, error: {:#?}",
                            glob_pattern, error
                        );
                        return vec![];
                    }
                }
            }
        }
        Err(error) => {
            error!(
                "Error while running glob: {}, error: {:#?}",
                glob_pattern, error
            );
            return vec![];
        }
    }

    if !path_list.is_empty() {
        if let Some(ignore_type_value) = ignore_type {
            let mut included_paths = HashSet::new();

            match ignore_type_value.as_str() {
                "git" => {
                    for entry in WalkBuilder::new("./")
                        .hidden(true)
                        .parents(true)
                        .git_ignore(true)
                        .git_exclude(true)
                        .build()
                    {
                        match entry {
                            Ok(path) => {
                                let mut value_string: String = FromPath::from_path(&path.path());
                                value_string = value_string.replace("\\", "/");
                                included_paths.insert(value_string);
                            }
                            Err(error) => error!(
                                "Error while running git ignore path checks, error: {:#?}",
                                error
                            ),
                        }
                    }
                }
                _ => error!("Unsupported ignore type: {}", &ignore_type_value),
            };

            println!("path_list: {:#?}", &path_list); //todo re
            println!("included_paths: {:#?}", &included_paths); //todo re
            if included_paths.is_empty() {
                path_list.clear();
            } else {
                let org_path_list = path_list;
                path_list = vec![];
                for path in org_path_list {
                    if included_paths.contains(&path) {
                        path_list.push(path);
                    }
                }
            }
        }
    }

    path_list
}
<|endoftext|>


<commit_before>use super::interface::DBusInterface;

extern crate dbus;
use self::dbus::{Connection, Error};

use std::collections::btree_map::BTreeMap;

pub struct DBusObject<'a> {
    ifaces: BTreeMap<String, Box<DBusInterface>>,

    conn: &'a Connection,
    path: String,
}

impl<'a> DBusObject<'a> {
    pub fn new(conn: &'a Connection, ifaces: BTreeMap<String, Box<DBusInterface>>, path: &str) -> Result<Self, Error> {
        try!(conn.register_object_path(path));

        Ok(DBusObject {
            ifaces: ifaces,

            conn: conn,
            path: path.to_string(),
        })
    }

    pub fn path(&self) -> &str {
        &self.path[..]
    }

    pub fn get_interface(&self, interface: &str) -> Option<&DBusInterface> {
        self.ifaces.get(interface).map(|iface| {
            &**iface
        })
    }
}

impl<'a> Drop for DBusObject<'a> {
    fn drop(&mut self) {
        self.conn.unregister_object_path(self.path())
    }
}
<commit_msg>object: use the Deref trait<commit_after>use super::interface::DBusInterface;

extern crate core;
use self::core::ops::Deref;

extern crate dbus;
use self::dbus::{Connection, Error};

use std::collections::btree_map::BTreeMap;

pub struct DBusObject<'a> {
    ifaces: BTreeMap<String, Box<DBusInterface>>,

    conn: &'a Connection,
    path: String,
}

impl<'a> DBusObject<'a> {
    pub fn new(conn: &'a Connection, ifaces: BTreeMap<String, Box<DBusInterface>>, path: &str) -> Result<Self, Error> {
        try!(conn.register_object_path(path));

        Ok(DBusObject {
            ifaces: ifaces,

            conn: conn,
            path: path.to_string(),
        })
    }

    pub fn path(&self) -> &str {
        &self.path[..]
    }

    pub fn get_interface(&self, interface: &str) -> Option<&DBusInterface> {
        self.ifaces.get(interface).map(|iface| {
            iface.deref()
        })
    }
}

impl<'a> Drop for DBusObject<'a> {
    fn drop(&mut self) {
        self.conn.unregister_object_path(self.path())
    }
}
<|endoftext|>


<commit_before>/// Doc-test test
/// ```rust
/// assert!(cargo_miri_test::make_true());
/// ```
pub fn make_true() -> bool {
    issue_1705::use_the_dependency();
    issue_1691::use_me()
}
<commit_msg>Use the `issue-1567` dependency in the test<commit_after>/// Doc-test test
/// ```rust
/// assert!(cargo_miri_test::make_true());
/// ```
pub fn make_true() -> bool {
    issue_1567::use_the_dependency();
    issue_1705::use_the_dependency();
    issue_1691::use_me()
}
<|endoftext|>


<commit_before>/// TODO: parse and return flags per DSO, add as entry to the struct
/// TODO: fix the high address mapperr for `__libc_start_main`

use std::fs::File;
use std::os::unix::io::AsRawFd;
use std::slice;
use std::os::raw::{c_int};

use utils::mmap;
use utils::page;
use utils;
use image::SharedObject;
use binary::elf::header;
use binary::elf::program_header;
use binary::elf::dyn;
use binary::elf::sym;
use binary::elf::rela;
use binary::elf::strtab::Strtab;
use binary::elf::gnu_hash::GnuHash;

#[inline(always)]
fn compute_load_size (phdrs: &[program_header::ProgramHeader]) -> (usize, u64, u64) {
    let mut max_vaddr = 0;
    let mut min_vaddr = 0;
    for phdr in phdrs {

        if phdr.p_type != program_header::PT_LOAD {
            continue
        }

        if phdr.p_vaddr < min_vaddr {
            min_vaddr = phdr.p_vaddr;
        }

        if phdr.p_vaddr + phdr.p_memsz > max_vaddr {
            max_vaddr = phdr.p_vaddr + phdr.p_memsz;
        }
    }

    min_vaddr = page::page_start(min_vaddr);
    max_vaddr = page::page_end(max_vaddr);

    ((max_vaddr - min_vaddr) as usize, min_vaddr, max_vaddr)
}

#[inline(always)]
fn reserve_address_space (phdrs: &[program_header::ProgramHeader]) -> Result <(u64, u64, u64), String> {

    let (size, min_vaddr, max_vaddr) = compute_load_size(&phdrs);

    let mmap_flags = mmap::MAP_PRIVATE | mmap::MAP_ANONYMOUS;
    let start = unsafe { mmap::mmap(0 as *const u64,
                                    size,
                                    // for now, using PROT_NONE seems to give SEGV_ACCERR on execution of PT_LOAD mmaped segments (i.e., operation not allowed on mapped object)
                                    mmap::PROT_EXEC | mmap::PROT_READ | mmap::PROT_WRITE,
                                    mmap_flags as c_int,  // TODO: I think we should copy glibc's lead here and use their mmap flags
                                    -1,
                                    0) };

    if start == mmap::MAP_FAILED {

        Err (format!("<dryad> Failure: anonymous mmap failed for size {:x} with errno {}", size, utils::get_errno()))

    } else {

        let load_bias = start - min_vaddr;
        let end = start + size as u64;
        Ok ((start, load_bias, end))
    }
}

#[inline(always)]
fn pflags_to_prot (x: u32) -> isize {
    use binary::elf::program_header::{PF_X, PF_R, PF_W};

    // I'm a dick for writing this/copying maniac C programmer implementations: but it checks the flag to see if it's the PF value,
    // and returns the appropriate mmap version, and logical ORs this for use in the mmap prot argument
    (if x & PF_X == PF_X { mmap::PROT_EXEC } else { 0 }) |
    (if x & PF_R == PF_R { mmap::PROT_READ } else { 0 }) |
    (if x & PF_W == PF_W { mmap::PROT_WRITE } else { 0 })
}

/// Loads an ELF binary from the given fd, mmaps its contents, and returns a SharedObject, whose lifetime is tied to the mmap's, i.e., manually managed
pub fn load<'a> (soname: &str, load_path: String, fd: &mut File, debug: bool) -> Result <SharedObject<'a>, String> {

    ///////////////
    // Part I:
    //   wherein we read the binary from disk,
    //   and lovingly mmap it's joyous contents
    ///////////////

    // 1. Suck up the elf header on disk and construct the program headers
    let ehdr = header::Header::from_fd(fd).map_err(|e| format!("<dryad> Error {:?}", e))?;
    let phdrs = program_header::ProgramHeader::from_fd(fd, ehdr.e_phoff, ehdr.e_phnum as usize).map_err(|e| format!("<dryad> Error {:?}", e))?;

    // 2. Reserve address space with anon mmap
    let (start, load_bias, end) = reserve_address_space(&phdrs)?;
    if debug { println!("<loader> reserved {:#x} - {:#x} with load_bias: 0x{:x}", start, end, load_bias); }

    // 3. Now we iterate through the phdrs, and
    // a. mmap the PT_LOAD program headers
    // b. collect the vaddrs of the phdrs and the dynamic array
    // c. TODO: mmap and setup TLS
    let mut phdrs_vaddr = 0;
    let mut dynamic_vaddr = None;
    let mut has_pt_load = false;
    for phdr in &phdrs {

        match phdr.p_type {

            program_header::PT_LOAD => {
                has_pt_load = true;
                // Segment offsets: rounds down the segment start to a value suitable for mmaping, and adjusts the size of the
                // mmap breadth appropriately
                let seg_start: u64 = phdr.p_vaddr + load_bias;
                let seg_end: u64   = seg_start + phdr.p_memsz;

                let seg_page_start: u64 = page::page_start(seg_start);
                let seg_page_end: u64   = page::page_start(seg_end);

                // TODO: unused, I think we need to zero some stuff
                let seg_file_end: u64 = seg_start + phdr.p_filesz;

                // File offsets.
                let file_start: u64 = phdr.p_offset;
                let file_end: u64   = file_start + phdr.p_filesz;

                // "rounds" to an mmap-able value (i.e., file_start % pagesize)
                // file_page_start <= file_start
                // so sometimes the beginning of the page is not the beginning of the PT_LOAD!
                let file_page_start = page::page_start(file_start);
                let file_length: u64 = file_end - file_page_start;

                // TODO: add error checking, if file size <= 0, if file_end greater than file_size, etc.

                if debug { println!("<loader> PT_LOAD:\n\tseg_start: {:x} seg_end: {:x} seg_page_start: {:x} seg_page_end: {:x} seg_file_end: {:x}\n\tfile_start: {:x} file_end: {:x} file_page_start: {:x} file_length: {:x}", seg_start, seg_end, seg_page_start, seg_page_end, seg_file_end, file_start, file_end, file_page_start, file_length); }

                if file_length != 0 {
                    let mmap_flags = mmap::MAP_FIXED | mmap::MAP_PRIVATE;
                    let prot_flags = pflags_to_prot(phdr.p_flags);
                    unsafe {
                        let start = mmap::mmap(seg_page_start as *const u64,
                                               file_length as usize,
                                               prot_flags,
                                               mmap_flags as c_int,
                                               fd.as_raw_fd() as c_int,
                                               file_page_start as usize);

                        if start == mmap::MAP_FAILED {

                            return Err(format!("<loader> loading phdrs for {} failed with errno {}, aborting execution", &soname, utils::get_errno()))
                        }
                    }

                    // TODO: other more boring shit to do with zero'd out extra pages if too big, etc.
                    //seg_file_end = page::page_end(seg_file_end);

                }
            } // end match PT_LOAD

            program_header::PT_PHDR => {
                phdrs_vaddr = phdr.p_vaddr;
            },
            program_header::PT_DYNAMIC => {
                dynamic_vaddr = Some(phdr.p_vaddr);
            },
            _ => () // do nothing, i.e., continue
        }
    }

    if !has_pt_load {
        return Err(format!("<loader> {} has no PT_LOAD sections", soname));
    }

    ///////////////
    // Part Deux:
    //   wherein we construct our components for this SharedObject
    //   from the newly mmap'd memory
    ///////////////

    // use the now mmap'd program headers
    let phdrs = unsafe { program_header::ProgramHeader::from_raw_parts((phdrs_vaddr + load_bias) as *const program_header::ProgramHeader, phdrs.len()) };

    // construct the dynamic slice in whatever mmap'd PT_LOAD it's in
    let dynamic_vaddr = dynamic_vaddr.ok_or(format!("<loader> {} has no dynamic array", soname))?;
    let dynamic = unsafe { dyn::from_raw(load_bias, dynamic_vaddr) };

    // build the link info with the bias and the dynamic array
    let link_info = dyn::LinkInfo::new(&dynamic, load_bias as usize);

    // now get the strtab from the dynamic array
    let strtab = unsafe { Strtab::from_raw(link_info.strtab as *const u8, link_info.strsz as usize) };

    // now get the libs we will need
    let libs = dyn::get_needed(dynamic, &strtab, link_info.needed_count);

    // caveat about rdr doing this for hundres of binaries and it being "ok"
    let num_syms = (link_info.strtab - link_info.symtab) / sym::SIZEOF_SYM;

    // now construct the symtab
    let symtab = unsafe { sym::from_raw(link_info.symtab as *const sym::Sym, num_syms) };

    // now grab relatab, and pltreltab which we'll use for relocating this shared object later
    let relatab = unsafe { rela::from_raw(link_info.rela as *const rela::Rela, link_info.relasz) };
    let pltrelatab = unsafe { rela::from_raw(link_info.jmprel as *const rela::Rela, link_info.pltrelsz) };

    // the pltgot we need for doing lazy dynamic linking
    let pltgot = if let Some(addr) = link_info.pltgot { addr } else { 0 }; // musl doesn't have a PLTGOT, for example

    // and finally grab the gnu_hash (if it has one)
    let gnu_hash = if let Some(addr) = link_info.gnu_hash { Some (GnuHash::new(addr as *const u32, symtab.len())) } else { None };

    let shared_object = SharedObject {
        name: strtab.get(link_info.soname),
        load_bias: load_bias,
        libs: libs,
        map_begin: start,
        map_end: end,
        phdrs: phdrs,
        dynamic: dynamic,
        symtab: symtab,
        strtab: strtab,
        relatab: relatab,
        pltrelatab: pltrelatab,
        pltgot: pltgot as *const u64,
        gnu_hash: gnu_hash,
        load_path: Some (load_path),
    };

    Ok (shared_object)
}
<commit_msg>loader: remove unused slice import<commit_after>/// TODO: parse and return flags per DSO, add as entry to the struct
/// TODO: fix the high address mapperr for `__libc_start_main`

use std::fs::File;
use std::os::unix::io::AsRawFd;
use std::os::raw::{c_int};

use utils::mmap;
use utils::page;
use utils;
use image::SharedObject;
use binary::elf::header;
use binary::elf::program_header;
use binary::elf::dyn;
use binary::elf::sym;
use binary::elf::rela;
use binary::elf::strtab::Strtab;
use binary::elf::gnu_hash::GnuHash;

#[inline(always)]
fn compute_load_size (phdrs: &[program_header::ProgramHeader]) -> (usize, u64, u64) {
    let mut max_vaddr = 0;
    let mut min_vaddr = 0;
    for phdr in phdrs {

        if phdr.p_type != program_header::PT_LOAD {
            continue
        }

        if phdr.p_vaddr < min_vaddr {
            min_vaddr = phdr.p_vaddr;
        }

        if phdr.p_vaddr + phdr.p_memsz > max_vaddr {
            max_vaddr = phdr.p_vaddr + phdr.p_memsz;
        }
    }

    min_vaddr = page::page_start(min_vaddr);
    max_vaddr = page::page_end(max_vaddr);

    ((max_vaddr - min_vaddr) as usize, min_vaddr, max_vaddr)
}

#[inline(always)]
fn reserve_address_space (phdrs: &[program_header::ProgramHeader]) -> Result <(u64, u64, u64), String> {

    let (size, min_vaddr, max_vaddr) = compute_load_size(&phdrs);

    let mmap_flags = mmap::MAP_PRIVATE | mmap::MAP_ANONYMOUS;
    let start = unsafe { mmap::mmap(0 as *const u64,
                                    size,
                                    // for now, using PROT_NONE seems to give SEGV_ACCERR on execution of PT_LOAD mmaped segments (i.e., operation not allowed on mapped object)
                                    mmap::PROT_EXEC | mmap::PROT_READ | mmap::PROT_WRITE,
                                    mmap_flags as c_int,  // TODO: I think we should copy glibc's lead here and use their mmap flags
                                    -1,
                                    0) };

    if start == mmap::MAP_FAILED {

        Err (format!("<dryad> Failure: anonymous mmap failed for size {:x} with errno {}", size, utils::get_errno()))

    } else {

        let load_bias = start - min_vaddr;
        let end = start + size as u64;
        Ok ((start, load_bias, end))
    }
}

#[inline(always)]
fn pflags_to_prot (x: u32) -> isize {
    use binary::elf::program_header::{PF_X, PF_R, PF_W};

    // I'm a dick for writing this/copying maniac C programmer implementations: but it checks the flag to see if it's the PF value,
    // and returns the appropriate mmap version, and logical ORs this for use in the mmap prot argument
    (if x & PF_X == PF_X { mmap::PROT_EXEC } else { 0 }) |
    (if x & PF_R == PF_R { mmap::PROT_READ } else { 0 }) |
    (if x & PF_W == PF_W { mmap::PROT_WRITE } else { 0 })
}

/// Loads an ELF binary from the given fd, mmaps its contents, and returns a SharedObject, whose lifetime is tied to the mmap's, i.e., manually managed
pub fn load<'a> (soname: &str, load_path: String, fd: &mut File, debug: bool) -> Result <SharedObject<'a>, String> {

    ///////////////
    // Part I:
    //   wherein we read the binary from disk,
    //   and lovingly mmap it's joyous contents
    ///////////////

    // 1. Suck up the elf header on disk and construct the program headers
    let ehdr = header::Header::from_fd(fd).map_err(|e| format!("<dryad> Error {:?}", e))?;
    let phdrs = program_header::ProgramHeader::from_fd(fd, ehdr.e_phoff, ehdr.e_phnum as usize).map_err(|e| format!("<dryad> Error {:?}", e))?;

    // 2. Reserve address space with anon mmap
    let (start, load_bias, end) = reserve_address_space(&phdrs)?;
    if debug { println!("<loader> reserved {:#x} - {:#x} with load_bias: 0x{:x}", start, end, load_bias); }

    // 3. Now we iterate through the phdrs, and
    // a. mmap the PT_LOAD program headers
    // b. collect the vaddrs of the phdrs and the dynamic array
    // c. TODO: mmap and setup TLS
    let mut phdrs_vaddr = 0;
    let mut dynamic_vaddr = None;
    let mut has_pt_load = false;
    for phdr in &phdrs {

        match phdr.p_type {

            program_header::PT_LOAD => {
                has_pt_load = true;
                // Segment offsets: rounds down the segment start to a value suitable for mmaping, and adjusts the size of the
                // mmap breadth appropriately
                let seg_start: u64 = phdr.p_vaddr + load_bias;
                let seg_end: u64   = seg_start + phdr.p_memsz;

                let seg_page_start: u64 = page::page_start(seg_start);
                let seg_page_end: u64   = page::page_start(seg_end);

                // TODO: unused, I think we need to zero some stuff
                let seg_file_end: u64 = seg_start + phdr.p_filesz;

                // File offsets.
                let file_start: u64 = phdr.p_offset;
                let file_end: u64   = file_start + phdr.p_filesz;

                // "rounds" to an mmap-able value (i.e., file_start % pagesize)
                // file_page_start <= file_start
                // so sometimes the beginning of the page is not the beginning of the PT_LOAD!
                let file_page_start = page::page_start(file_start);
                let file_length: u64 = file_end - file_page_start;

                // TODO: add error checking, if file size <= 0, if file_end greater than file_size, etc.

                if debug { println!("<loader> PT_LOAD:\n\tseg_start: {:x} seg_end: {:x} seg_page_start: {:x} seg_page_end: {:x} seg_file_end: {:x}\n\tfile_start: {:x} file_end: {:x} file_page_start: {:x} file_length: {:x}", seg_start, seg_end, seg_page_start, seg_page_end, seg_file_end, file_start, file_end, file_page_start, file_length); }

                if file_length != 0 {
                    let mmap_flags = mmap::MAP_FIXED | mmap::MAP_PRIVATE;
                    let prot_flags = pflags_to_prot(phdr.p_flags);
                    unsafe {
                        let start = mmap::mmap(seg_page_start as *const u64,
                                               file_length as usize,
                                               prot_flags,
                                               mmap_flags as c_int,
                                               fd.as_raw_fd() as c_int,
                                               file_page_start as usize);

                        if start == mmap::MAP_FAILED {

                            return Err(format!("<loader> loading phdrs for {} failed with errno {}, aborting execution", &soname, utils::get_errno()))
                        }
                    }

                    // TODO: other more boring shit to do with zero'd out extra pages if too big, etc.
                    //seg_file_end = page::page_end(seg_file_end);

                }
            } // end match PT_LOAD

            program_header::PT_PHDR => {
                phdrs_vaddr = phdr.p_vaddr;
            },
            program_header::PT_DYNAMIC => {
                dynamic_vaddr = Some(phdr.p_vaddr);
            },
            _ => () // do nothing, i.e., continue
        }
    }

    if !has_pt_load {
        return Err(format!("<loader> {} has no PT_LOAD sections", soname));
    }

    ///////////////
    // Part Deux:
    //   wherein we construct our components for this SharedObject
    //   from the newly mmap'd memory
    ///////////////

    // use the now mmap'd program headers
    let phdrs = unsafe { program_header::ProgramHeader::from_raw_parts((phdrs_vaddr + load_bias) as *const program_header::ProgramHeader, phdrs.len()) };

    // construct the dynamic slice in whatever mmap'd PT_LOAD it's in
    let dynamic_vaddr = dynamic_vaddr.ok_or(format!("<loader> {} has no dynamic array", soname))?;
    let dynamic = unsafe { dyn::from_raw(load_bias, dynamic_vaddr) };

    // build the link info with the bias and the dynamic array
    let link_info = dyn::LinkInfo::new(&dynamic, load_bias as usize);

    // now get the strtab from the dynamic array
    let strtab = unsafe { Strtab::from_raw(link_info.strtab as *const u8, link_info.strsz as usize) };

    // now get the libs we will need
    let libs = dyn::get_needed(dynamic, &strtab, link_info.needed_count);

    // caveat about rdr doing this for hundres of binaries and it being "ok"
    let num_syms = (link_info.strtab - link_info.symtab) / sym::SIZEOF_SYM;

    // now construct the symtab
    let symtab = unsafe { sym::from_raw(link_info.symtab as *const sym::Sym, num_syms) };

    // now grab relatab, and pltreltab which we'll use for relocating this shared object later
    let relatab = unsafe { rela::from_raw(link_info.rela as *const rela::Rela, link_info.relasz) };
    let pltrelatab = unsafe { rela::from_raw(link_info.jmprel as *const rela::Rela, link_info.pltrelsz) };

    // the pltgot we need for doing lazy dynamic linking
    let pltgot = if let Some(addr) = link_info.pltgot { addr } else { 0 }; // musl doesn't have a PLTGOT, for example

    // and finally grab the gnu_hash (if it has one)
    let gnu_hash = if let Some(addr) = link_info.gnu_hash { Some (GnuHash::new(addr as *const u32, symtab.len())) } else { None };

    let shared_object = SharedObject {
        name: strtab.get(link_info.soname),
        load_bias: load_bias,
        libs: libs,
        map_begin: start,
        map_end: end,
        phdrs: phdrs,
        dynamic: dynamic,
        symtab: symtab,
        strtab: strtab,
        relatab: relatab,
        pltrelatab: pltrelatab,
        pltgot: pltgot as *const u64,
        gnu_hash: gnu_hash,
        load_path: Some (load_path),
    };

    Ok (shared_object)
}
<|endoftext|>


<commit_before>extern crate iron;
extern crate time;

use iron::prelude::*;
use iron::{BeforeMiddleware, AfterMiddleware, typemap};
use time::precise_time_ns;

pub struct RequestLogger;

impl typemap::Key for RequestLogger { type Value = u64; }

impl BeforeMiddleware for RequestLogger {
    fn before(&self, request: &mut Request) -> IronResult<()> {
        request.extensions.insert::<RequestLogger>(precise_time_ns());
        println!(
            "Started {} \"{}\" for {}",
            request.method,
            format!("/{}", request.url.path().join("/")),
            request.remote_addr
        );

        Ok(())
    }
}

impl AfterMiddleware for RequestLogger {
    fn after(&self, request: &mut Request, response: Response) -> IronResult<Response> {
        let delta = precise_time_ns() - *request.extensions.get::<RequestLogger>().unwrap();
        println!("Request took {} ms", (delta as f64) / 1000000.0);

        Ok(response)
    }
}
<commit_msg>Add current time in RequestLogger<commit_after>extern crate iron;
extern crate time;

use iron::prelude::*;
use iron::{BeforeMiddleware, AfterMiddleware, typemap};
use time::precise_time_ns;

pub struct RequestLogger;

impl typemap::Key for RequestLogger { type Value = u64; }

impl BeforeMiddleware for RequestLogger {
    fn before(&self, request: &mut Request) -> IronResult<()> {
        request.extensions.insert::<RequestLogger>(precise_time_ns());
        println!(
            "Started {} \"{}\" for {} at {}",
            request.method,
            format!("/{}", request.url.path().join("/")),
            request.remote_addr,
            time::now().strftime("%+").unwrap()
        );

        Ok(())
    }
}

impl AfterMiddleware for RequestLogger {
    fn after(&self, request: &mut Request, response: Response) -> IronResult<Response> {
        let delta = precise_time_ns() - *request.extensions.get::<RequestLogger>().unwrap();
        println!("Request took {} ms", (delta as f64) / 1000000.0);

        Ok(response)
    }
}
<|endoftext|>


<commit_before>use std::fs::{File, OpenOptions};

pub struct Logger {
    logfile: Option<File>,
}

impl Logger {
    pub fn new() -> Logger {
        Logger {
            logfile: None,
        }
    }

    pub fn set_logfile(&mut self, filename: &str) {
        let file = OpenOptions::new()
            .create(true)
            .append(true)
            .open(filename);

        match file {
            Ok(file) => self.logfile = Some(file),
            Err(error) => eprintln!("Couldn't open `{}' as a logfile: {}", filename, error),
        }
    }
}

#[cfg(test)]
mod tests {
    extern crate tempfile;

    use super::*;

    use std::io;
    use self::tempfile::TempDir;

    #[test]
    fn t_set_logfile() -> io::Result<()> {
        let tmp = TempDir::new()?;
        let filename = {
            let mut filename = tmp.path().to_owned();
            filename.push("example.log");
            filename
        };

        assert!(!filename.exists());

        let mut logger = Logger::new();
        logger.set_logfile(filename.to_str().unwrap());

        assert!(filename.exists());

        Ok(())
    }
}
<commit_msg>Logger::log writes a line to the file<commit_after>use std::fs::{File, OpenOptions};
use std::io::{self, Write};

pub struct Logger {
    logfile: Option<File>,
}

impl Logger {
    pub fn new() -> Logger {
        Logger {
            logfile: None,
        }
    }

    pub fn set_logfile(&mut self, filename: &str) {
        let file = OpenOptions::new()
            .create(true)
            .append(true)
            .open(filename);

        match file {
            Ok(file) => self.logfile = Some(file),
            Err(error) => eprintln!("Couldn't open `{}' as a logfile: {}", filename, error),
        }
    }

    pub fn log(&mut self, message: &str) -> io::Result<()> {
        if let Some(ref mut logfile) = self.logfile {
            logfile.write_all(message.as_bytes())?;
        }

        Ok(())
    }
}

#[cfg(test)]
mod tests {
    extern crate tempfile;

    use super::*;

    use self::tempfile::TempDir;
    use std::io::{self, Read};
    use std::path;

    fn setup_logger() -> io::Result<(TempDir, path::PathBuf, Logger)> {
        let tmp = TempDir::new()?;
        let logfile = {
            let mut logfile = tmp.path().to_owned();
            logfile.push("example.log");
            logfile
        };
        assert!(!logfile.exists());

        let mut logger = Logger::new();
        logger.set_logfile(logfile.to_str().unwrap());

        Ok((tmp, logfile, logger))
    }

    #[test]
    fn t_set_logfile() -> io::Result<()> {
        let (_tmp, logfile, _logger) = setup_logger()?;

        assert!(logfile.exists());

        Ok(())
    }

    #[test]
    fn t_log_writes_message_to_the_file() -> io::Result<()> {
        let (_tmp, logfile, mut logger) = setup_logger()?;

        let message = "Hello, world!";
        logger.log(message)?;

        // Dropping logger to force it to flush the log and close the file
        drop(logger);

        let mut file = File::open(logfile)?;
        let mut contents = String::new();
        file.read_to_string(&mut contents)?;

        assert_eq!(contents, message);

        Ok(())
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2020 Jason Ish
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

// Export the standard log style marcros under the log module. To use:
//    use crate::logger::log;
//    log::info("Something info...");
pub mod log {
    pub use tracing::debug;
    pub use tracing::error;
    pub use tracing::info;
    pub use tracing::trace;
    pub use tracing::warn;
}

use tracing::Level;

pub fn init_logger(level: Level) {
    let level = match level {
        Level::TRACE => "trace",
        Level::DEBUG => "debug",
        Level::INFO => "info",
        Level::WARN => "warn",
        Level::ERROR => "error",
    };
    let timer =
        tracing_subscriber::fmt::time::ChronoLocal::with_format("%Y-%m-%d %H:%M:%S".to_string());
    let subscriber = tracing_subscriber::FmtSubscriber::builder()
        .with_env_filter(format!("{},hyper=off", level))
        .with_writer(std::io::stderr)
        .with_timer(timer)
        .finish();
    tracing::subscriber::set_global_default(subscriber).expect("setting default subscriber failed");
}

pub fn init_stdlog() {
    tracing_log::LogTracer::builder()
        .with_max_level(stdlog::LevelFilter::Info)
        .init()
        .unwrap();
}
<commit_msg>logging: suppress warp logs<commit_after>// Copyright (C) 2020 Jason Ish
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

// Export the standard log style marcros under the log module. To use:
//    use crate::logger::log;
//    log::info("Something info...");
pub mod log {
    pub use tracing::debug;
    pub use tracing::error;
    pub use tracing::info;
    pub use tracing::trace;
    pub use tracing::warn;
}

use tracing::Level;

pub fn init_logger(level: Level) {
    let level = match level {
        Level::TRACE => "trace",
        Level::DEBUG => "debug",
        Level::INFO => "info",
        Level::WARN => "warn",
        Level::ERROR => "error",
    };
    let timer =
        tracing_subscriber::fmt::time::ChronoLocal::with_format("%Y-%m-%d %H:%M:%S".to_string());
    let subscriber = tracing_subscriber::FmtSubscriber::builder()
        .with_env_filter(format!("{},hyper=off,warp=off", level))
        .with_writer(std::io::stderr)
        .with_timer(timer)
        .finish();
    tracing::subscriber::set_global_default(subscriber).expect("setting default subscriber failed");
}

pub fn init_stdlog() {
    tracing_log::LogTracer::builder()
        .with_max_level(stdlog::LevelFilter::Info)
        .init()
        .unwrap();
}
<|endoftext|>


<commit_before>#[macro_export]
macro_rules! routes {
    {$(resource $resource:ty => $methods:tt { $(related $rel:ty : $count:tt; )* } )*} => {
        pub fn attach_routes<T: ::cargonauts::router::Router>(router: &mut T) {
            let mut router = ::cargonauts::_internal::Router::new(router);
            $({ resource!(router, $resource => $methods { $($rel: $count;)* }); })*
        }
    }
}

#[macro_export]
macro_rules! resource {
    ($router:expr, $resource:ty => $methods:tt { }) => {
        impl ::cargonauts::_internal::Wrapper<$resource> for ::cargonauts::_internal::Resource<$resource> {
            type Relationships = ();

            fn related(&self) -> Option<()> {
                None
            }

            fn include(&self, params: &[String]) -> Vec<::cargonauts::Value> {
                vec![]
            }
        }
    };
    ($router:expr, $resource:ty => $methods:tt { $($rel:ty : $count:tt;)+ }) => {
        impl ::cargonauts::_internal::Wrapper<$resource> for ::cargonauts::_internal::Resource<$resource> {
            type Relationships = Relationships;

            fn related(&self) -> Option<Relationships> {
                Some(Relationships {
                    id: self.id(),
                })
            }

            fn include(&self, params: &[String]) -> Vec<::cargonauts::Value> {
                let id = self.id();
                params.iter().flat_map(|param| {
                    $(
                        if param == <$rel as ::cargonauts::api::Resource>::resource() {
                            include_relation!(&id, $resource, $rel, $count);
                        }
                    )*
                    return vec![]
                }).collect()
            }
        }

        struct Relationships {
            id: <$resource as ::cargonauts::api::Resource>::Id,
        }

        impl ::cargonauts::Serialize for Relationships {
            fn serialize<S: ::cargonauts::Serializer>(&self, serializer: &mut S) -> Result<(), S::Error> {
                let mut state = try!(serializer.serialize_map(None));
                let id = &self.id;
                $(
                    { serialize_relation!(serializer, &mut state, id, $resource, $rel, $count); }
                )*
                serializer.serialize_map_end(state)
            }
        }

        methods!($router, $resource, $methods);
    };
}

#[macro_export]
macro_rules! include_relation {
    ($id:expr, $resource:ty, $rel:ty, "has-one") => {
        if let Some(resource) = <$resource as ::cargonauts::api::HasOne<$rel>>::has_one($id) {
            let resource = ::cargonauts::_internal::Resource::wrap(resource);
            return vec![::cargonauts::to_value(resource)]
        } else { return vec![] }
    };
    ($id:expr, $resource:ty, $rel:ty, "has-many") => {
        let mut values = vec![];
        for resource in <$resource as ::cargonauts::api::HasMany<$rel>>::has_many($id) {
            let resource = ::cargonauts::_internal::Resource::wrap(resource);
            values.push(::cargonauts::to_value(resource))
        }
        return values
    };
    ($id:expr, $resource:ty, $rel:ty, $ignore:tt) => {
        // TODO handle errors more betterer
    };
}

#[macro_export]
macro_rules! serialize_relation {
    ($serializer:expr, $state:expr, $id:expr, $resource:ty, $rel:ty, "has-one") => {
        try!($serializer.serialize_map_key($state, <$rel as ::cargonauts::api::Resource>::resource()));
        try!($serializer.serialize_map_value($state, ::cargonauts::_internal::HasOne::<$resource, $rel>::new($id)));
    };
    ($serializer:expr, $state:expr, $id:expr, $resource:ty, $rel:ty, "has-many") => {
        try!($serializer.serialize_map_key($state, <$rel as ::cargonauts::api::Resource>::resource()));
        try!($serializer.serialize_map_value($state, ::cargonauts::_internal::HasMany::<$resource, $rel>::new($id)));

    };
    ($serializer:expr, $state:expr, $id:expr, $resource:ty, $rel:ty, $ignore:tt) => {
        // TODO handle errors more betterer
    };
}

#[macro_export]
macro_rules! methods {
    ($router:expr, $resource:ty,  ["get", $($method:tt),*]) => {
        $router.attach_get::<$resource>();
        methods!($router, $resource,  [$($method),*])
    };
    ($router:expr, $resource:ty,  ["get"]) => {
        $router.attach_get::<$resource>();
    };
    ($router:expr, $resource:ty,  ["index", $($method:tt),*]) => {
        $router.attach_index::<$resource>();
        methods!($router, $rels, $resource,  [$($method),*])
    };
    ($router:expr, $resource:ty,  ["index"]) => {
        $router.attach_index::<$resource>();
    };
    ($router:expr, $resource:ty,  [$ignore:tt, $($method:tt),*]) => {
        // TODO handle errors more betterer
        methods!($router, $rels, $resource,  [$($method),*])
    };
    ($router:expr, $resource:ty,  $ignore:tt) => {
        // TODO handle errors more betterer
    };
}
<commit_msg>Small oversight in macro definition.<commit_after>#[macro_export]
macro_rules! routes {
    {$(resource $resource:ty => $methods:tt { $(related $rel:ty : $count:tt; )* } )*} => {
        pub fn attach_routes<T: ::cargonauts::router::Router>(router: &mut T) {
            let mut router = ::cargonauts::_internal::Router::new(router);
            $({ resource!(router, $resource => $methods { $($rel: $count;)* }); })*
        }
    }
}

#[macro_export]
macro_rules! resource {
    ($router:expr, $resource:ty => $methods:tt { }) => {
        impl ::cargonauts::_internal::Wrapper<$resource> for ::cargonauts::_internal::Resource<$resource> {
            type Relationships = ();

            fn related(&self) -> Option<()> {
                None
            }

            fn include(&self, params: &[String]) -> Vec<::cargonauts::Value> {
                vec![]
            }
        }

        methods!($router, $resource, $methods);
    };
    ($router:expr, $resource:ty => $methods:tt { $($rel:ty : $count:tt;)+ }) => {
        impl ::cargonauts::_internal::Wrapper<$resource> for ::cargonauts::_internal::Resource<$resource> {
            type Relationships = Relationships;

            fn related(&self) -> Option<Relationships> {
                Some(Relationships {
                    id: self.id(),
                })
            }

            fn include(&self, params: &[String]) -> Vec<::cargonauts::Value> {
                let id = self.id();
                params.iter().flat_map(|param| {
                    $(
                        if param == <$rel as ::cargonauts::api::Resource>::resource() {
                            include_relation!(&id, $resource, $rel, $count);
                        }
                    )*
                    return vec![]
                }).collect()
            }
        }

        struct Relationships {
            id: <$resource as ::cargonauts::api::Resource>::Id,
        }

        impl ::cargonauts::Serialize for Relationships {
            fn serialize<S: ::cargonauts::Serializer>(&self, serializer: &mut S) -> Result<(), S::Error> {
                let mut state = try!(serializer.serialize_map(None));
                let id = &self.id;
                $(
                    { serialize_relation!(serializer, &mut state, id, $resource, $rel, $count); }
                )*
                serializer.serialize_map_end(state)
            }
        }

        methods!($router, $resource, $methods);
    };
}

#[macro_export]
macro_rules! include_relation {
    ($id:expr, $resource:ty, $rel:ty, "has-one") => {
        if let Some(resource) = <$resource as ::cargonauts::api::HasOne<$rel>>::has_one($id) {
            let resource = ::cargonauts::_internal::Resource::wrap(resource);
            return vec![::cargonauts::to_value(resource)]
        } else { return vec![] }
    };
    ($id:expr, $resource:ty, $rel:ty, "has-many") => {
        let mut values = vec![];
        for resource in <$resource as ::cargonauts::api::HasMany<$rel>>::has_many($id) {
            let resource = ::cargonauts::_internal::Resource::wrap(resource);
            values.push(::cargonauts::to_value(resource))
        }
        return values
    };
    ($id:expr, $resource:ty, $rel:ty, $ignore:tt) => {
        // TODO handle errors more betterer
    };
}

#[macro_export]
macro_rules! serialize_relation {
    ($serializer:expr, $state:expr, $id:expr, $resource:ty, $rel:ty, "has-one") => {
        try!($serializer.serialize_map_key($state, <$rel as ::cargonauts::api::Resource>::resource()));
        try!($serializer.serialize_map_value($state, ::cargonauts::_internal::HasOne::<$resource, $rel>::new($id)));
    };
    ($serializer:expr, $state:expr, $id:expr, $resource:ty, $rel:ty, "has-many") => {
        try!($serializer.serialize_map_key($state, <$rel as ::cargonauts::api::Resource>::resource()));
        try!($serializer.serialize_map_value($state, ::cargonauts::_internal::HasMany::<$resource, $rel>::new($id)));

    };
    ($serializer:expr, $state:expr, $id:expr, $resource:ty, $rel:ty, $ignore:tt) => {
        // TODO handle errors more betterer
    };
}

#[macro_export]
macro_rules! methods {
    ($router:expr, $resource:ty,  ["get", $($method:tt),*]) => {
        $router.attach_get::<$resource>();
        methods!($router, $resource,  [$($method),*])
    };
    ($router:expr, $resource:ty,  ["get"]) => {
        $router.attach_get::<$resource>();
    };
    ($router:expr, $resource:ty,  ["index", $($method:tt),*]) => {
        $router.attach_index::<$resource>();
        methods!($router, $rels, $resource,  [$($method),*])
    };
    ($router:expr, $resource:ty,  ["index"]) => {
        $router.attach_index::<$resource>();
    };
    ($router:expr, $resource:ty,  [$ignore:tt, $($method:tt),*]) => {
        // TODO handle errors more betterer
        methods!($router, $rels, $resource,  [$($method),*])
    };
    ($router:expr, $resource:ty,  $ignore:tt) => {
        // TODO handle errors more betterer
    };
}
<|endoftext|>


<commit_before>pub struct Memory {
  addr:[u8; 0xffff]
}

impl Memory {
  pub fn new() -> Memory {
    Memory {
      addr: [0; 0xffff]
    }
  }

  pub fn store(&mut self, addr: usize, data: u8) -> Result<(), &'static str> {
    if addr > 0xffff {
      Err("memory address out of bounds")
    } else {
      self.addr[addr] = data;
      Ok(()) // TODO: There must be a cleaner way of doing this
    }
  }

  pub fn load(&mut self, addr: usize) -> Result<u8, &'static str> {
    if addr > 0xffff {
      Err("memory address out of bounds")
    } else {
      Ok(self.addr[addr])
    }
  }
}

<commit_msg>Get rid of old comment<commit_after>pub struct Memory {
  addr:[u8; 0xffff]
}

impl Memory {
  pub fn new() -> Memory {
    Memory {
      addr: [0; 0xffff]
    }
  }

  pub fn store(&mut self, addr: usize, data: u8) -> Result<(), &'static str> {
    if addr > 0xffff {
      Err("memory address out of bounds")
    } else {
      self.addr[addr] = data;
      Ok(())
    }
  }

  pub fn load(&mut self, addr: usize) -> Result<u8, &'static str> {
    if addr > 0xffff {
      Err("memory address out of bounds")
    } else {
      Ok(self.addr[addr])
    }
  }
}

<|endoftext|>


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

use std::collections::BTreeMap;

#[cfg(feature = "amqp0-build-specs")]
include!(concat!(env!("OUT_DIR"), "/amqp0.rs"));
#[cfg(not(feature = "amqp0-build-specs"))]
include!(concat!("lib.pregen.rs"));

#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct Version {
    minor: u16,
    revision: u16,
}

#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct Spec {
    name: &'static str,
    classes: BTreeMap<&'static str, Class>,
    constants: BTreeMap<&'static str, Constant>,
    domains: BTreeMap<&'static str, &'static str>,
    frame_types: BTreeMap<&'static str, Constant>,
    response_codes: BTreeMap<&'static str, Constant>,
    version: Version,
}

#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct Class {
    name: &'static str,
    fields: Vec<ClassField>,
    index: u16,
    methods: Vec<ClassMethod>,
}

#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct ClassMethod {
    name: &'static str,
    index: u16,
    response: Option<&'static str>,
    fields: Vec<ClassMethodField>,
    is_synchronous: bool,

    chassis_server: Option<&'static str>,
    chassis_client: Option<&'static str>,
}

#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct ClassField {
    name: &'static str,
    domain: &'static str,
}

#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct ClassMethodField {
    name: &'static str,
    domain: &'static str,
    assertions: Vec<ClassMethodFieldAssertion>,
    is_reserved: bool,
}

#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub enum ClassMethodFieldAssertion {
    Null,
    NotNull,
    ChannelMax,
    NotZero,
    Enum(Vec<&'static str>),
    Length(usize),
    Regexp(&'static str),
    Syntax(&'static str),
}

#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct Constant {
    name: &'static str,
    value: u32,
    class: Option<&'static str>,
}

impl Spec {
    pub fn name(&self) -> &'static str {
        self.name
    }
    pub fn classes(&self) -> &BTreeMap<&'static str, Class> {
        &self.classes
    }
    pub fn domains(&self) -> &BTreeMap<&'static str, &'static str> {
        &self.domains
    }
    pub fn frame_types(&self) -> &BTreeMap<&'static str, Constant> {
        &self.frame_types
    }
    pub fn response_codes(&self) -> &BTreeMap<&'static str, Constant> {
        &self.response_codes
    }
    pub fn version(&self) -> &Version {
        &self.version
    }
}

impl Class {
    pub fn name(&self) -> &'static str {
        self.name
    }

    pub fn fields(&self) -> &[ClassField] {
        &self.fields
    }

    pub fn index(&self) -> u16 {
        self.index
    }

    pub fn methods(&self) -> &[ClassMethod] {
        &self.methods
    }
}

impl ClassField {
    pub fn name(&self) -> &'static str {
        &self.name
    }

    pub fn domain(&self) -> &'static str {
        self.domain
    }
}

impl ClassMethod {
    pub fn index(&self) -> u16 {
        self.index
    }
    pub fn name(&self) -> &str {
        &self.name
    }
    pub fn fields(&self) -> &[ClassMethodField] {
        &self.fields
    }
}

impl ClassMethodField {
    pub fn name(&self) -> &'static str {
        &self.name
    }

    pub fn domain(&self) -> &'static str {
        self.domain
    }

    pub fn assertions(&self) -> &[ClassMethodFieldAssertion] {
        &self.assertions
    }

    pub fn is_reserved(&self) -> bool {
        self.is_reserved
    }
}

impl Constant {
    pub fn name(&self) -> &'static str {
        self.name
    }

    pub fn value(&self) -> u32 {
        self.value
    }

    pub fn class(&self) -> Option<&'static str> {
        self.class
    }
}

impl Version {
    pub fn minor(&self) -> u16 {
        self.minor
    }

    pub fn revision(&self) -> u16 {
        self.revision
    }
}<commit_msg>[specs] Enable clippy lints<commit_after>// Copyright 2016 Alexander Reece
//
// 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.

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

use std::collections::BTreeMap;

#[cfg(feature = "amqp0-build-specs")]
include!(concat!(env!("OUT_DIR"), "/amqp0.rs"));
#[cfg(not(feature = "amqp0-build-specs"))]
include!(concat!("lib.pregen.rs"));

#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct Version {
    minor: u16,
    revision: u16,
}

#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct Spec {
    name: &'static str,
    classes: BTreeMap<&'static str, Class>,
    constants: BTreeMap<&'static str, Constant>,
    domains: BTreeMap<&'static str, &'static str>,
    frame_types: BTreeMap<&'static str, Constant>,
    response_codes: BTreeMap<&'static str, Constant>,
    version: Version,
}

#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct Class {
    name: &'static str,
    fields: Vec<ClassField>,
    index: u16,
    methods: Vec<ClassMethod>,
}

#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct ClassMethod {
    name: &'static str,
    index: u16,
    response: Option<&'static str>,
    fields: Vec<ClassMethodField>,
    is_synchronous: bool,

    chassis_server: Option<&'static str>,
    chassis_client: Option<&'static str>,
}

#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct ClassField {
    name: &'static str,
    domain: &'static str,
}

#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct ClassMethodField {
    name: &'static str,
    domain: &'static str,
    assertions: Vec<ClassMethodFieldAssertion>,
    is_reserved: bool,
}

#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub enum ClassMethodFieldAssertion {
    Null,
    NotNull,
    ChannelMax,
    NotZero,
    Enum(Vec<&'static str>),
    Length(usize),
    Regexp(&'static str),
    Syntax(&'static str),
}

#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct Constant {
    name: &'static str,
    value: u32,
    class: Option<&'static str>,
}

impl Spec {
    pub fn name(&self) -> &'static str {
        self.name
    }
    pub fn classes(&self) -> &BTreeMap<&'static str, Class> {
        &self.classes
    }
    pub fn domains(&self) -> &BTreeMap<&'static str, &'static str> {
        &self.domains
    }
    pub fn frame_types(&self) -> &BTreeMap<&'static str, Constant> {
        &self.frame_types
    }
    pub fn response_codes(&self) -> &BTreeMap<&'static str, Constant> {
        &self.response_codes
    }
    pub fn version(&self) -> &Version {
        &self.version
    }
}

impl Class {
    pub fn name(&self) -> &'static str {
        self.name
    }

    pub fn fields(&self) -> &[ClassField] {
        &self.fields
    }

    pub fn index(&self) -> u16 {
        self.index
    }

    pub fn methods(&self) -> &[ClassMethod] {
        &self.methods
    }
}

impl ClassField {
    pub fn name(&self) -> &'static str {
        &self.name
    }

    pub fn domain(&self) -> &'static str {
        self.domain
    }
}

impl ClassMethod {
    pub fn index(&self) -> u16 {
        self.index
    }
    pub fn name(&self) -> &str {
        &self.name
    }
    pub fn fields(&self) -> &[ClassMethodField] {
        &self.fields
    }
}

impl ClassMethodField {
    pub fn name(&self) -> &'static str {
        &self.name
    }

    pub fn domain(&self) -> &'static str {
        self.domain
    }

    pub fn assertions(&self) -> &[ClassMethodFieldAssertion] {
        &self.assertions
    }

    pub fn is_reserved(&self) -> bool {
        self.is_reserved
    }
}

impl Constant {
    pub fn name(&self) -> &'static str {
        self.name
    }

    pub fn value(&self) -> u32 {
        self.value
    }

    pub fn class(&self) -> Option<&'static str> {
        self.class
    }
}

impl Version {
    pub fn minor(&self) -> u16 {
        self.minor
    }

    pub fn revision(&self) -> u16 {
        self.revision
    }
}<|endoftext|>