<commit_before>use std::collections::BTreeMap;
use std::io::{self, Cursor};
use std::str;
use std::fmt;
use std::error::Error;

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum BEncode {
    Int(i64),
    String(Vec<u8>),
    List(Vec<BEncode>),
    Dict(BTreeMap<String, BEncode>),
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum BError {
    UTF8Decode,
    InvalidDict,
    InvalidChar(u8),
    ParseInt,
    EOF,
    IO,
}

impl fmt::Display for BError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            BError::UTF8Decode => write!(f, "UTF8 Decoding Error"),
            BError::InvalidDict => write!(f, "Invalid BEncoded dictionary"),
            BError::InvalidChar(c) => write!(f, "Invalid character: {}", char::from(c)),
            BError::ParseInt => write!(f, "Invalid integer value encountered"),
            BError::EOF => write!(f, "Unexpected EOF in data"),
            BError::IO => write!(f, "IO error"),
        }
    }
}

impl Error for BError {
    fn description(&self) -> &str {
        "BEncode processing error"
    }
}

impl BEncode {
    pub fn from_int(i: i64) -> BEncode {
        BEncode::Int(i)
    }

    #[cfg_attr(feature = "cargo-clippy", allow(should_implement_trait))]
    pub fn from_str(s: &str) -> BEncode {
        BEncode::String(Vec::from(s))
    }

    pub fn into_int(self) -> Option<i64> {
        match self {
            BEncode::Int(v) => Some(v),
            _ => None,
        }
    }

    pub fn into_bytes(self) -> Option<Vec<u8>> {
        match self {
            BEncode::String(v) => Some(v),
            _ => None,
        }
    }

    pub fn into_string(self) -> Option<String> {
        match self {
            BEncode::String(v) => String::from_utf8(v).ok(),
            _ => None,
        }
    }

    pub fn into_list(self) -> Option<Vec<BEncode>> {
        match self {
            BEncode::List(v) => Some(v),
            _ => None,
        }
    }

    pub fn into_dict(self) -> Option<BTreeMap<String, BEncode>> {
        match self {
            BEncode::Dict(v) => Some(v),
            _ => None,
        }
    }

    #[allow(dead_code)]
    pub fn as_int(&self) -> Option<&i64> {
        match *self {
            BEncode::Int(ref v) => Some(v),
            _ => None,
        }
    }

    #[allow(dead_code)]
    pub fn as_bytes(&self) -> Option<&Vec<u8>> {
        match *self {
            BEncode::String(ref v) => Some(v),
            _ => None,
        }
    }

    #[allow(dead_code)]
    pub fn as_str(&self) -> Option<&str> {
        match *self {
            BEncode::String(ref v) => str::from_utf8(v).ok(),
            _ => None,
        }
    }

    #[allow(dead_code)]
    pub fn as_list(&self) -> Option<&Vec<BEncode>> {
        match *self {
            BEncode::List(ref v) => Some(v),
            _ => None,
        }
    }

    #[allow(dead_code)]
    pub fn as_dict(&self) -> Option<&BTreeMap<String, BEncode>> {
        match *self {
            BEncode::Dict(ref v) => Some(v),
            _ => None,
        }
    }

    pub fn encode_to_buf(&self) -> Vec<u8> {
        let mut buf = Cursor::new(Vec::new());
        self.encode(&mut buf).unwrap();
        buf.into_inner()
    }

    pub fn encode<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
        enum Token<'a> {
            B(&'a BEncode),
            OS(&'a str),
            E,
        }

        let mut toks = vec![Token::B(self)];
        while !toks.is_empty() {
            match toks.pop().unwrap() {
                Token::B(&BEncode::Int(i)) => {
                    write!(w, "i{}e", i)?;
                }
                Token::B(&BEncode::String(ref s)) => {
                    write!(w, "{}:", s.len())?;
                    w.write_all(s)?;
                }
                Token::B(BEncode::List(ref v)) => {
                    write!(w, "l")?;
                    toks.push(Token::E);
                    toks.extend(v.iter().rev().map(|v| Token::B(v)));
                }
                Token::B(BEncode::Dict(ref d)) => {
                    write!(w, "d")?;
                    toks.push(Token::E);
                    for (k, v) in d.iter().rev() {
                        toks.push(Token::B(v));
                        toks.push(Token::OS(k));
                    }
                }
                Token::OS(s) => {
                    write!(w, "{}:", s.len())?;
                    w.write_all(s.as_bytes())?;
                }
                Token::E => {
                    write!(w, "e")?;
                }
            }
        }
        Ok(())
    }
}

pub fn decode_buf(bytes: &[u8]) -> Result<BEncode, BError> {
    decode(&mut Cursor::new(bytes))
}

pub fn decode<R: io::Read>(bytes: &mut R) -> Result<BEncode, BError> {
    enum Kind {
        Dict(usize),
        List(usize),
    }
    let mut cstack = vec![];
    let mut vstack = vec![];
    loop {
        match next_byte(bytes) {
            Ok(b'i') => {
                // Multiple non complex values are not allowed
                if cstack.is_empty() && !vstack.is_empty() {
                    return Err(BError::EOF);
                }
                let s = read_until(bytes, b'e')?;
                vstack.push(BEncode::Int(decode_int(s)?));
            }
            Ok(b'l') => {
                if cstack.is_empty() && !vstack.is_empty() {
                    return Err(BError::EOF);
                }
                cstack.push(Kind::List(vstack.len()));
            }
            Ok(b'd') => {
                if cstack.is_empty() && !vstack.is_empty() {
                    return Err(BError::EOF);
                }
                cstack.push(Kind::Dict(vstack.len()));
            }
            Err(BError::EOF) => break,
            Ok(b'e') => match cstack.pop() {
                Some(Kind::List(i)) => {
                    let mut l = Vec::with_capacity(vstack.len() - i);
                    while vstack.len() > i {
                        l.push(vstack.pop().unwrap());
                    }
                    l.reverse();
                    vstack.push(BEncode::List(l));
                }
                Some(Kind::Dict(i)) => {
                    let mut d = BTreeMap::new();
                    if (vstack.len() - i) % 2 != 0 {
                        return Err(BError::InvalidDict);
                    }
                    while vstack.len() > i {
                        let val = vstack.pop().unwrap();
                        match vstack.pop().and_then(BEncode::into_string) {
                            Some(key) => {
                                d.insert(key, val);
                            }
                            None => return Err(BError::InvalidDict),
                        }
                    }
                    vstack.push(BEncode::Dict(d))
                }
                None => return Err(BError::InvalidChar(b'e')),
            },
            Ok(d @ b'0'...b'9') => {
                if cstack.is_empty() && !vstack.is_empty() {
                    return Err(BError::EOF);
                }
                let mut slen = read_until(bytes, b':')?;
                slen.insert(0, d);
                let len = decode_int(slen)?;
                let mut v = vec![0u8; len as usize];
                bytes.read_exact(&mut v).map_err(|_| BError::EOF)?;
                vstack.push(BEncode::String(v));
            }
            Err(e) => return Err(e),
            Ok(c) => return Err(BError::InvalidChar(c)),
        }
    }

    if cstack.is_empty() && vstack.len() == 1 {
        Ok(vstack.into_iter().next().unwrap())
    } else {
        Err(BError::EOF)
    }
}

fn next_byte<R: io::Read>(r: &mut R) -> Result<u8, BError> {
    let mut v = [0];
    let amnt = r.read(&mut v).map_err(|_| BError::IO)?;
    if amnt == 0 {
        Err(BError::EOF)
    } else {
        Ok(v[0])
    }
}

fn read_until<R: io::Read>(r: &mut R, b: u8) -> Result<Vec<u8>, BError> {
    let mut v = vec![];
    loop {
        let n = next_byte(r)?;
        if b == n {
            return Ok(v);
        }
        v.push(n);
    }
}

fn decode_int(v: Vec<u8>) -> Result<i64, BError> {
    String::from_utf8(v)
        .map_err(|_| BError::UTF8Decode)
        .and_then(|i| i.parse().map_err(|_| BError::ParseInt))
}

#[cfg(test)]
mod tests {
    use super::{decode_buf, BEncode};
    use std::collections::BTreeMap;

    #[test]
    fn test_encode_decode() {
        let i = BEncode::Int(-10);
        let mut v = Vec::new();
        i.encode(&mut v).unwrap();
        assert_eq!(v, b"i-10e");

        let s = BEncode::String(Vec::from(&b"asdf"[..]));
        v = Vec::new();
        s.encode(&mut v).unwrap();
        assert_eq!(v, b"4:asdf");

        let s2r = [1u8, 2, 3, 4];
        let s2e = [52u8, 58, 1, 2, 3, 4];
        let s2 = BEncode::String(Vec::from(&s2r[..]));
        v = Vec::new();
        s2.encode(&mut v).unwrap();
        assert_eq!(v, &s2e);

        let l = BEncode::List(vec![i.clone(), s.clone()]);
        v = Vec::new();
        l.encode(&mut v).unwrap();
        assert_eq!(v, b"li-10e4:asdfe");

        let mut map = BTreeMap::new();
        map.insert(String::from("asdf"), i.clone());
        map.insert(String::from("qwerty"), i.clone());
        let d = BEncode::Dict(map);
        v = Vec::new();
        d.encode(&mut v).unwrap();
        println!("{:?}", ::std::str::from_utf8(&v));
        assert_eq!(v, b"d4:asdfi-10e6:qwertyi-10ee");

        decode_encode(b"d4:asdfi-10e6:qwertyi-10ee");

        decode_encode(b"d1:rd2:id20:mnopqrstuvwxyz123456e1:t2:aa1:y1:re");

        encode_decode(&i);
        encode_decode(&s);
        encode_decode(&s2);
        encode_decode(&l);
        encode_decode(&d);
    }

    #[test]
    fn test_invalid() {
        let badint = b"i-123.4e";
        let twoint = b"i123ei123e";
        let badstr = b"5:eeeeeeeeeeee";
        let badstr2 = b"5:e";
        let badstr3 = b"-1:e";
        let badstr4 = b"1:a2:ab";
        let badlist = b"l123e";
        let badlist2 = b"li123e";
        let badlist3 = b"lllllllllllllllllllllllllllllllllllllleeeeeeeeeeee";
        let badlist4 = b"lele";
        let baddict = b"d1:ae";
        let baddict2 = b"di123ei123ee";
        assert!(decode_buf(badint).is_err());
        assert!(decode_buf(twoint).is_err());
        assert!(decode_buf(badstr).is_err());
        assert!(decode_buf(badstr2).is_err());
        assert!(decode_buf(badstr3).is_err());
        assert!(decode_buf(badstr4).is_err());
        assert!(decode_buf(badlist).is_err());
        assert!(decode_buf(badlist2).is_err());
        assert!(decode_buf(badlist3).is_err());
        assert!(decode_buf(badlist4).is_err());
        assert!(decode_buf(baddict).is_err());
        assert!(decode_buf(baddict2).is_err());
    }

    fn encode_decode(b: &BEncode) {
        let mut v = Vec::new();
        b.encode(&mut v).unwrap();
        assert_eq!(b, &decode_buf(&v).unwrap());
    }

    fn decode_encode(d: &[u8]) {
        let mut v = Vec::new();
        let dec = decode_buf(d).unwrap();
        println!("{:?}", dec);
        dec.encode(&mut v).unwrap();
        assert_eq!(d, &v[..]);
    }
}
<commit_msg>Ensure matches work on stable<commit_after>use std::collections::BTreeMap;
use std::io::{self, Cursor};
use std::str;
use std::fmt;
use std::error::Error;

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum BEncode {
    Int(i64),
    String(Vec<u8>),
    List(Vec<BEncode>),
    Dict(BTreeMap<String, BEncode>),
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum BError {
    UTF8Decode,
    InvalidDict,
    InvalidChar(u8),
    ParseInt,
    EOF,
    IO,
}

impl fmt::Display for BError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            BError::UTF8Decode => write!(f, "UTF8 Decoding Error"),
            BError::InvalidDict => write!(f, "Invalid BEncoded dictionary"),
            BError::InvalidChar(c) => write!(f, "Invalid character: {}", char::from(c)),
            BError::ParseInt => write!(f, "Invalid integer value encountered"),
            BError::EOF => write!(f, "Unexpected EOF in data"),
            BError::IO => write!(f, "IO error"),
        }
    }
}

impl Error for BError {
    fn description(&self) -> &str {
        "BEncode processing error"
    }
}

impl BEncode {
    pub fn from_int(i: i64) -> BEncode {
        BEncode::Int(i)
    }

    #[cfg_attr(feature = "cargo-clippy", allow(should_implement_trait))]
    pub fn from_str(s: &str) -> BEncode {
        BEncode::String(Vec::from(s))
    }

    pub fn into_int(self) -> Option<i64> {
        match self {
            BEncode::Int(v) => Some(v),
            _ => None,
        }
    }

    pub fn into_bytes(self) -> Option<Vec<u8>> {
        match self {
            BEncode::String(v) => Some(v),
            _ => None,
        }
    }

    pub fn into_string(self) -> Option<String> {
        match self {
            BEncode::String(v) => String::from_utf8(v).ok(),
            _ => None,
        }
    }

    pub fn into_list(self) -> Option<Vec<BEncode>> {
        match self {
            BEncode::List(v) => Some(v),
            _ => None,
        }
    }

    pub fn into_dict(self) -> Option<BTreeMap<String, BEncode>> {
        match self {
            BEncode::Dict(v) => Some(v),
            _ => None,
        }
    }

    #[allow(dead_code)]
    pub fn as_int(&self) -> Option<&i64> {
        match *self {
            BEncode::Int(ref v) => Some(v),
            _ => None,
        }
    }

    #[allow(dead_code)]
    pub fn as_bytes(&self) -> Option<&Vec<u8>> {
        match *self {
            BEncode::String(ref v) => Some(v),
            _ => None,
        }
    }

    #[allow(dead_code)]
    pub fn as_str(&self) -> Option<&str> {
        match *self {
            BEncode::String(ref v) => str::from_utf8(v).ok(),
            _ => None,
        }
    }

    #[allow(dead_code)]
    pub fn as_list(&self) -> Option<&Vec<BEncode>> {
        match *self {
            BEncode::List(ref v) => Some(v),
            _ => None,
        }
    }

    #[allow(dead_code)]
    pub fn as_dict(&self) -> Option<&BTreeMap<String, BEncode>> {
        match *self {
            BEncode::Dict(ref v) => Some(v),
            _ => None,
        }
    }

    pub fn encode_to_buf(&self) -> Vec<u8> {
        let mut buf = Cursor::new(Vec::new());
        self.encode(&mut buf).unwrap();
        buf.into_inner()
    }

    pub fn encode<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
        enum Token<'a> {
            B(&'a BEncode),
            OS(&'a str),
            E,
        }

        let mut toks = vec![Token::B(self)];
        while !toks.is_empty() {
            match toks.pop().unwrap() {
                Token::B(&BEncode::Int(i)) => {
                    write!(w, "i{}e", i)?;
                }
                Token::B(&BEncode::String(ref s)) => {
                    write!(w, "{}:", s.len())?;
                    w.write_all(s)?;
                }
                Token::B(&BEncode::List(ref v)) => {
                    write!(w, "l")?;
                    toks.push(Token::E);
                    toks.extend(v.iter().rev().map(|v| Token::B(v)));
                }
                Token::B(&BEncode::Dict(ref d)) => {
                    write!(w, "d")?;
                    toks.push(Token::E);
                    for (k, v) in d.iter().rev() {
                        toks.push(Token::B(v));
                        toks.push(Token::OS(k));
                    }
                }
                Token::OS(s) => {
                    write!(w, "{}:", s.len())?;
                    w.write_all(s.as_bytes())?;
                }
                Token::E => {
                    write!(w, "e")?;
                }
            }
        }
        Ok(())
    }
}

pub fn decode_buf(bytes: &[u8]) -> Result<BEncode, BError> {
    decode(&mut Cursor::new(bytes))
}

pub fn decode<R: io::Read>(bytes: &mut R) -> Result<BEncode, BError> {
    enum Kind {
        Dict(usize),
        List(usize),
    }
    let mut cstack = vec![];
    let mut vstack = vec![];
    loop {
        match next_byte(bytes) {
            Ok(b'i') => {
                // Multiple non complex values are not allowed
                if cstack.is_empty() && !vstack.is_empty() {
                    return Err(BError::EOF);
                }
                let s = read_until(bytes, b'e')?;
                vstack.push(BEncode::Int(decode_int(s)?));
            }
            Ok(b'l') => {
                if cstack.is_empty() && !vstack.is_empty() {
                    return Err(BError::EOF);
                }
                cstack.push(Kind::List(vstack.len()));
            }
            Ok(b'd') => {
                if cstack.is_empty() && !vstack.is_empty() {
                    return Err(BError::EOF);
                }
                cstack.push(Kind::Dict(vstack.len()));
            }
            Err(BError::EOF) => break,
            Ok(b'e') => match cstack.pop() {
                Some(Kind::List(i)) => {
                    let mut l = Vec::with_capacity(vstack.len() - i);
                    while vstack.len() > i {
                        l.push(vstack.pop().unwrap());
                    }
                    l.reverse();
                    vstack.push(BEncode::List(l));
                }
                Some(Kind::Dict(i)) => {
                    let mut d = BTreeMap::new();
                    if (vstack.len() - i) % 2 != 0 {
                        return Err(BError::InvalidDict);
                    }
                    while vstack.len() > i {
                        let val = vstack.pop().unwrap();
                        match vstack.pop().and_then(BEncode::into_string) {
                            Some(key) => {
                                d.insert(key, val);
                            }
                            None => return Err(BError::InvalidDict),
                        }
                    }
                    vstack.push(BEncode::Dict(d))
                }
                None => return Err(BError::InvalidChar(b'e')),
            },
            Ok(d @ b'0'...b'9') => {
                if cstack.is_empty() && !vstack.is_empty() {
                    return Err(BError::EOF);
                }
                let mut slen = read_until(bytes, b':')?;
                slen.insert(0, d);
                let len = decode_int(slen)?;
                let mut v = vec![0u8; len as usize];
                bytes.read_exact(&mut v).map_err(|_| BError::EOF)?;
                vstack.push(BEncode::String(v));
            }
            Err(e) => return Err(e),
            Ok(c) => return Err(BError::InvalidChar(c)),
        }
    }

    if cstack.is_empty() && vstack.len() == 1 {
        Ok(vstack.into_iter().next().unwrap())
    } else {
        Err(BError::EOF)
    }
}

fn next_byte<R: io::Read>(r: &mut R) -> Result<u8, BError> {
    let mut v = [0];
    let amnt = r.read(&mut v).map_err(|_| BError::IO)?;
    if amnt == 0 {
        Err(BError::EOF)
    } else {
        Ok(v[0])
    }
}

fn read_until<R: io::Read>(r: &mut R, b: u8) -> Result<Vec<u8>, BError> {
    let mut v = vec![];
    loop {
        let n = next_byte(r)?;
        if b == n {
            return Ok(v);
        }
        v.push(n);
    }
}

fn decode_int(v: Vec<u8>) -> Result<i64, BError> {
    String::from_utf8(v)
        .map_err(|_| BError::UTF8Decode)
        .and_then(|i| i.parse().map_err(|_| BError::ParseInt))
}

#[cfg(test)]
mod tests {
    use super::{decode_buf, BEncode};
    use std::collections::BTreeMap;

    #[test]
    fn test_encode_decode() {
        let i = BEncode::Int(-10);
        let mut v = Vec::new();
        i.encode(&mut v).unwrap();
        assert_eq!(v, b"i-10e");

        let s = BEncode::String(Vec::from(&b"asdf"[..]));
        v = Vec::new();
        s.encode(&mut v).unwrap();
        assert_eq!(v, b"4:asdf");

        let s2r = [1u8, 2, 3, 4];
        let s2e = [52u8, 58, 1, 2, 3, 4];
        let s2 = BEncode::String(Vec::from(&s2r[..]));
        v = Vec::new();
        s2.encode(&mut v).unwrap();
        assert_eq!(v, &s2e);

        let l = BEncode::List(vec![i.clone(), s.clone()]);
        v = Vec::new();
        l.encode(&mut v).unwrap();
        assert_eq!(v, b"li-10e4:asdfe");

        let mut map = BTreeMap::new();
        map.insert(String::from("asdf"), i.clone());
        map.insert(String::from("qwerty"), i.clone());
        let d = BEncode::Dict(map);
        v = Vec::new();
        d.encode(&mut v).unwrap();
        println!("{:?}", ::std::str::from_utf8(&v));
        assert_eq!(v, b"d4:asdfi-10e6:qwertyi-10ee");

        decode_encode(b"d4:asdfi-10e6:qwertyi-10ee");

        decode_encode(b"d1:rd2:id20:mnopqrstuvwxyz123456e1:t2:aa1:y1:re");

        encode_decode(&i);
        encode_decode(&s);
        encode_decode(&s2);
        encode_decode(&l);
        encode_decode(&d);
    }

    #[test]
    fn test_invalid() {
        let badint = b"i-123.4e";
        let twoint = b"i123ei123e";
        let badstr = b"5:eeeeeeeeeeee";
        let badstr2 = b"5:e";
        let badstr3 = b"-1:e";
        let badstr4 = b"1:a2:ab";
        let badlist = b"l123e";
        let badlist2 = b"li123e";
        let badlist3 = b"lllllllllllllllllllllllllllllllllllllleeeeeeeeeeee";
        let badlist4 = b"lele";
        let baddict = b"d1:ae";
        let baddict2 = b"di123ei123ee";
        assert!(decode_buf(badint).is_err());
        assert!(decode_buf(twoint).is_err());
        assert!(decode_buf(badstr).is_err());
        assert!(decode_buf(badstr2).is_err());
        assert!(decode_buf(badstr3).is_err());
        assert!(decode_buf(badstr4).is_err());
        assert!(decode_buf(badlist).is_err());
        assert!(decode_buf(badlist2).is_err());
        assert!(decode_buf(badlist3).is_err());
        assert!(decode_buf(badlist4).is_err());
        assert!(decode_buf(baddict).is_err());
        assert!(decode_buf(baddict2).is_err());
    }

    fn encode_decode(b: &BEncode) {
        let mut v = Vec::new();
        b.encode(&mut v).unwrap();
        assert_eq!(b, &decode_buf(&v).unwrap());
    }

    fn decode_encode(d: &[u8]) {
        let mut v = Vec::new();
        let dec = decode_buf(d).unwrap();
        println!("{:?}", dec);
        dec.encode(&mut v).unwrap();
        assert_eq!(d, &v[..]);
    }
}
<|endoftext|>


<commit_before>//
// FlightVars
// Copyright (c) 2015, 2016 Alvaro Polo
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::ffi::OsString;
use std::fmt;
use std::io;
use std::sync::mpsc;
use std::thread;
use std::time::Duration;

use serial;
use serial::SerialPort;

use comm::{Interrupt, Listen};

#[derive(Debug, Eq, PartialEq)]
enum PortStatus {
    Available, InUse,
}

struct PortInfo {
    name: SerialAddr,
    status: PortStatus,
}

pub struct PortScanner {
    ports: Vec<PortInfo>,
    tx: PortScannerSender,
    rx: PortScannerReceiver,
}

impl PortScanner {
    pub fn with_ports<S, I>(port_names: I) -> io::Result<PortScanner>
    where S: Into<OsString>, I: IntoIterator<Item=S> {
        let mut ports = Vec::with_capacity(64);
        for port_name in port_names {
            let port_info = PortInfo {
                name: SerialAddr(port_name.into()),
                status: PortStatus::Available,
            };
            ports.push(port_info);
        }
        let (tx, rx) = mpsc::channel();
        Ok(PortScanner { ports: ports,  tx: tx, rx: rx })
    }
}

impl Listen for PortScanner {
    type ConnAddr = SerialAddr;
    type Input = serial::SystemPort;
    type Output = serial::SystemPort;
    type Int = PortScannerSender;

    fn listen(&mut self) -> io::Result<(serial::SystemPort, serial::SystemPort, SerialAddr)> {
        loop {
            if let Ok(PortScannerMsg::Shutdown) = self.rx.try_recv() {
            	return Err(io::Error::new(
            	        io::ErrorKind::ConnectionAborted,
            	        "scanner received a shutdown message"));
            }
            for p in self.ports.iter_mut() {
                if p.status == PortStatus::Available {
                    debug!("trying to open serial port {}", p.name);
                    match serial::open(&p.name.0) {
                        Ok(mut open_port) => {
                            info!("serial port {} successfully open", p.name);

                            let mut settings = serial::PortSettings::default();
                            settings.baud_rate = serial::BaudRate::Baud9600;
                            try!(open_port.configure(&settings));
                            try!(open_port.set_rts(true));
                            try!(open_port.set_dtr(true));

                            p.status = PortStatus::InUse;
                            let read_port = try!(open_port.try_clone());
                            let write_port = open_port;
                            return Ok((read_port, write_port, p.name.clone()));
                        },
                        Err(e) => {
                        	debug!("cannot open serial port {}: {:?}", p.name, e);
                        },
                    }
                }
            }
            thread::sleep(Duration::from_millis(1000));
        };
    }

    fn shutdown_interruption(&mut self) -> PortScannerSender {
        self.tx.clone()
    }
}

#[derive(Clone)]
pub struct SerialAddr(OsString);

impl fmt::Display for SerialAddr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self.0)
    }
}

pub enum PortScannerMsg {
    Shutdown
}

pub type PortScannerSender = mpsc::Sender<PortScannerMsg>;
pub type PortScannerReceiver = mpsc::Receiver<PortScannerMsg>;

pub type SerialInterruptor = PortScannerSender;

impl Interrupt for PortScannerSender {
    fn interrupt(self) {
        if let Err(e) = self.send(PortScannerMsg::Shutdown) {
            error!("cannot send shutdown message to serial port scanner: {:?}", e);
        }
    }
}<commit_msg>Move default baudrate into a constant<commit_after>//
// FlightVars
// Copyright (c) 2015, 2016 Alvaro Polo
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::ffi::OsString;
use std::fmt;
use std::io;
use std::sync::mpsc;
use std::thread;
use std::time::Duration;

use serial;
use serial::SerialPort;

use comm::{Interrupt, Listen};

const DEFAULT_BAUDRATE: serial::BaudRate = serial::BaudRate::Baud9600;

#[derive(Debug, Eq, PartialEq)]
enum PortStatus {
    Available, InUse,
}

struct PortInfo {
    name: SerialAddr,
    status: PortStatus,
}

pub struct PortScanner {
    ports: Vec<PortInfo>,
    tx: PortScannerSender,
    rx: PortScannerReceiver,
}

impl PortScanner {
    pub fn with_ports<S, I>(port_names: I) -> io::Result<PortScanner>
    where S: Into<OsString>, I: IntoIterator<Item=S> {
        let mut ports = Vec::with_capacity(64);
        for port_name in port_names {
            let port_info = PortInfo {
                name: SerialAddr(port_name.into()),
                status: PortStatus::Available,
            };
            ports.push(port_info);
        }
        let (tx, rx) = mpsc::channel();
        Ok(PortScanner { ports: ports,  tx: tx, rx: rx })
    }
}

impl Listen for PortScanner {
    type ConnAddr = SerialAddr;
    type Input = serial::SystemPort;
    type Output = serial::SystemPort;
    type Int = PortScannerSender;

    fn listen(&mut self) -> io::Result<(serial::SystemPort, serial::SystemPort, SerialAddr)> {
        loop {
            if let Ok(PortScannerMsg::Shutdown) = self.rx.try_recv() {
            	return Err(io::Error::new(
            	        io::ErrorKind::ConnectionAborted,
            	        "scanner received a shutdown message"));
            }
            for p in self.ports.iter_mut() {
                if p.status == PortStatus::Available {
                    debug!("trying to open serial port {}", p.name);
                    match serial::open(&p.name.0) {
                        Ok(mut open_port) => {
                            info!("serial port {} successfully open", p.name);

                            let mut settings = serial::PortSettings::default();
                            settings.baud_rate = DEFAULT_BAUDRATE;
                            try!(open_port.configure(&settings));
                            try!(open_port.set_rts(true));
                            try!(open_port.set_dtr(true));

                            p.status = PortStatus::InUse;
                            let read_port = try!(open_port.try_clone());
                            let write_port = open_port;
                            return Ok((read_port, write_port, p.name.clone()));
                        },
                        Err(e) => {
                        	debug!("cannot open serial port {}: {:?}", p.name, e);
                        },
                    }
                }
            }
            thread::sleep(Duration::from_millis(1000));
        };
    }

    fn shutdown_interruption(&mut self) -> PortScannerSender {
        self.tx.clone()
    }
}

#[derive(Clone)]
pub struct SerialAddr(OsString);

impl fmt::Display for SerialAddr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self.0)
    }
}

pub enum PortScannerMsg {
    Shutdown
}

pub type PortScannerSender = mpsc::Sender<PortScannerMsg>;
pub type PortScannerReceiver = mpsc::Receiver<PortScannerMsg>;

pub type SerialInterruptor = PortScannerSender;

impl Interrupt for PortScannerSender {
    fn interrupt(self) {
        if let Err(e) = self.send(PortScannerMsg::Shutdown) {
            error!("cannot send shutdown message to serial port scanner: {:?}", e);
        }
    }
}<|endoftext|>


<commit_before>//! API to invoke `protoc` command.
//!
//! `protoc` command must be in `$PATH`, along with `protoc-gen-LANG` command.
//!
//! Note that to generate `rust` code from `.proto` files, `protoc-rust` crate
//! can be used, which does not require `protoc-gen-rust` present in `$PATH`.

#![deny(missing_docs)]

use std::ffi::{OsStr, OsString};
use std::fmt;
use std::path::{Path, PathBuf};
use std::process;
use std::io;

#[macro_use]
extern crate log;
extern crate which;

/// Alias for io::Error
pub type Error = io::Error;
/// Alias for io::Result
pub type Result<T> = io::Result<T>;

fn err_other(s: impl AsRef<str>) -> Error {
    Error::new(io::ErrorKind::Other, s.as_ref().to_owned())
}

/// `Protoc --lang_out...` args
#[derive(Default)]
pub struct Args {
    protoc: Option<Protoc>,
    /// `LANG` part in `--LANG_out=...`
    lang: Option<String>,
    /// `--LANG_out=...` param
    out_dir: Option<PathBuf>,
    /// `--plugin` param. Not needed if plugin is in `$PATH`
    plugin: Option<OsString>,
    /// `-I` args
    includes: Vec<PathBuf>,
    /// List of `.proto` files to compile
    inputs: Vec<PathBuf>,
}

impl Args {
    /// Arguments to the `protoc` found in `$PATH`
    pub fn new() -> Self {
        Self::default()
    }

    /// Set `LANG` part in `--LANG_out=...`
    pub fn lang(&mut self, lang: &str) -> &mut Self {
        self.lang = Some(lang.to_owned());
        self
    }

    /// Set `--LANG_out=...` param
    pub fn out_dir(&mut self, out_dir: impl AsRef<Path>) -> &mut Self {
        self.out_dir = Some(out_dir.as_ref().to_owned());
        self
    }

    /// Set `--plugin` param. Not needed if plugin is in `$PATH`
    pub fn plugin(&mut self, plugin: impl AsRef<OsStr>) -> &mut Self {
        self.plugin = Some(plugin.as_ref().to_owned());
        self
    }

    /// Append a path to `-I` args
    pub fn include(&mut self, include: impl AsRef<Path>) -> &mut Self {
        self.includes.push(include.as_ref().to_owned());
        self
    }

    /// Append multiple paths to `-I` args
    pub fn includes(&mut self, includes: impl IntoIterator<Item = impl AsRef<Path>>) -> &mut Self {
        for include in includes {
            self.include(include);
        }
        self
    }

    /// Append a `.proto` file path to compile
    pub fn input(&mut self, input: impl AsRef<Path>) -> &mut Self {
        self.inputs.push(input.as_ref().to_owned());
        self
    }

    /// Append multiple `.proto` file paths to compile
    pub fn inputs(&mut self, inputs: impl IntoIterator<Item = impl AsRef<Path>>) -> &mut Self {
        for input in inputs {
            self.input(input);
        }
        self
    }

    /// Execute `protoc` with given args
    pub fn run(&self) -> Result<()> {
        let protoc = match &self.protoc {
            Some(protoc) => protoc.clone(),
            None => {
                let protoc = Protoc::from_env_path();
                // Check with have good `protoc`
                protoc.check()?;
                protoc
            }
        };

        if self.inputs.is_empty() {
            return Err(err_other("input is empty"));
        }

        let out_dir = self
            .out_dir
            .as_ref()
            .ok_or_else(|| err_other("out_dir is empty"))?;
        let lang = self
            .lang
            .as_ref()
            .ok_or_else(|| err_other("lang is empty"))?;

        // --{lang}_out={out_dir}
        let mut lang_out_flag = OsString::from("--");
        lang_out_flag.push(lang);
        lang_out_flag.push("_out=");
        lang_out_flag.push(out_dir);

        // --plugin={plugin}
        let plugin_flag = self.plugin.as_ref().map(|plugin| {
            let mut flag = OsString::from("--plugin=");
            flag.push(plugin);
            flag
        });

        // -I{include}
        let include_flags = self.includes.iter().map(|include| {
            let mut flag = OsString::from("-I");
            flag.push(include);
            flag
        });

        let mut cmd_args = Vec::new();
        cmd_args.push(lang_out_flag);
        cmd_args.extend(self.inputs.iter().map(|path| path.as_os_str().to_owned()));
        cmd_args.extend(plugin_flag);
        cmd_args.extend(include_flags);
        protoc.run_with_args(cmd_args)
    }
}

/// `Protoc --descriptor_set_out...` args
#[derive(Debug)]
pub struct DescriptorSetOutArgs {
    protoc: Protoc,
    /// `--file_descriptor_out=...` param
    out: Option<PathBuf>,
    /// `-I` args
    includes: Vec<PathBuf>,
    /// List of `.proto` files to compile
    inputs: Vec<PathBuf>,
    /// `--include_imports`
    include_imports: bool,
}

impl DescriptorSetOutArgs {
    /// Set `--file_descriptor_out=...` param
    pub fn out(&mut self, out: impl AsRef<Path>) -> &mut Self {
        self.out = Some(out.as_ref().to_owned());
        self
    }

    /// Append a path to `-I` args
    pub fn include(&mut self, include: impl AsRef<Path>) -> &mut Self {
        self.includes.push(include.as_ref().to_owned());
        self
    }

    /// Append multiple paths to `-I` args
    pub fn includes(&mut self, includes: impl IntoIterator<Item = impl AsRef<Path>>) -> &mut Self {
        for include in includes {
            self.include(include);
        }
        self
    }

    /// Append a `.proto` file path to compile
    pub fn input(&mut self, input: impl AsRef<Path>) -> &mut Self {
        self.inputs.push(input.as_ref().to_owned());
        self
    }

    /// Append multiple `.proto` file paths to compile
    pub fn inputs(&mut self, inputs: impl IntoIterator<Item = impl AsRef<Path>>) -> &mut Self {
        for input in inputs {
            self.input(input);
        }
        self
    }

    /// Set `--include_imports`
    pub fn include_imports(&mut self, include_imports: bool) -> &mut Self {
        self.include_imports = include_imports;
        self
    }

    /// Execute `protoc --descriptor_set_out=`
    pub fn write_descriptor_set(&self) -> Result<()> {
        if self.inputs.is_empty() {
            return Err(err_other("input is empty"));
        }

        let out = self.out.as_ref().ok_or_else(|| err_other("out is empty"))?;

        // -I{include}
        let include_flags = self.includes.iter().map(|include| {
            let mut flag = OsString::from("-I");
            flag.push(include);
            flag
        });

        // --descriptor_set_out={out}
        let mut descriptor_set_out_flag = OsString::from("--descriptor_set_out=");
        descriptor_set_out_flag.push(out);

        // --include_imports
        let include_imports_flag = match self.include_imports {
            false => None,
            true => Some("--include_imports".into()),
        };

        let mut cmd_args = Vec::new();
        cmd_args.extend(include_flags);
        cmd_args.push(descriptor_set_out_flag);
        cmd_args.extend(include_imports_flag);
        cmd_args.extend(self.inputs.iter().map(|path| path.as_os_str().to_owned()));
        self.protoc.run_with_args(cmd_args)
    }
}

/// Protoc command.
#[derive(Clone, Debug)]
pub struct Protoc {
    exec: OsString,
}

impl Protoc {
    /// New `protoc` command from `$PATH`
    pub fn from_env_path() -> Protoc {
        if let Ok(path) = which::which("protoc") {
            Protoc {
                exec: path.into_os_string(),
            }
        } else {
            panic!("protoc binary not found");
        }
    }

    /// New `protoc` command from specified path
    ///
    /// # Examples
    ///
    /// ```no_run
    /// # mod protoc_bin_vendored {
    /// #   pub fn protoc_bin_path() -> Result<std::path::PathBuf, std::io::Error> {
    /// #       unimplemented!()
    /// #   }
    /// # }
    ///
    /// // Use a binary from `protoc-bin-vendored` crate
    /// let protoc = protoc::Protoc::from_path(
    ///     protoc_bin_vendored::protoc_bin_path().unwrap());
    /// ```
    pub fn from_path(path: impl AsRef<OsStr>) -> Protoc {
        Protoc {
            exec: path.as_ref().to_owned(),
        }
    }

    /// Check `protoc` command found and valid
    pub fn check(&self) -> Result<()> {
        self.version().map(|_| ())
    }

    fn spawn(&self, cmd: &mut process::Command) -> io::Result<process::Child> {
        info!("spawning command {:?}", cmd);

        cmd.spawn()
            .map_err(|e| Error::new(e.kind(), format!("failed to spawn `{:?}`: {}", cmd, e)))
    }

    /// Obtain `protoc` version
    pub fn version(&self) -> Result<Version> {
        let child = self.spawn(
            process::Command::new(&self.exec)
                .stdin(process::Stdio::null())
                .stdout(process::Stdio::piped())
                .stderr(process::Stdio::piped())
                .args(&["--version"]),
        )?;

        let output = child.wait_with_output()?;
        if !output.status.success() {
            return Err(err_other("protoc failed with error"));
        }
        let output =
            String::from_utf8(output.stdout).map_err(|e| Error::new(io::ErrorKind::Other, e))?;
        let output = match output.lines().next() {
            None => return Err(err_other("output is empty")),
            Some(line) => line,
        };
        let prefix = "libprotoc ";
        if !output.starts_with(prefix) {
            return Err(err_other("output does not start with prefix"));
        }
        let output = &output[prefix.len()..];
        if output.is_empty() {
            return Err(err_other("version is empty"));
        }
        let first = output.chars().next().unwrap();
        if !first.is_digit(10) {
            return Err(err_other("version does not start with digit"));
        }
        Ok(Version {
            version: output.to_owned(),
        })
    }

    /// Execute `protoc` command with given args, check it completed correctly.
    fn run_with_args(&self, args: Vec<OsString>) -> Result<()> {
        let mut cmd = process::Command::new(&self.exec);
        cmd.stdin(process::Stdio::null());
        cmd.args(args);

        let mut child = self.spawn(&mut cmd)?;

        if !child.wait()?.success() {
            return Err(err_other(format!(
                "protoc ({:?}) exited with non-zero exit code",
                cmd
            )));
        }

        Ok(())
    }

    /// Get default Args for this command.
    pub fn args(&self) -> Args {
        Args {
            protoc: Some(self.clone()),
            ..Args::new()
        }
    }

    /// Get default DescriptorSetOutArgs for this command.
    pub fn descriptor_set_out_args(&self) -> DescriptorSetOutArgs {
        DescriptorSetOutArgs {
            protoc: self.clone(),
            out: None,
            includes: Vec::new(),
            inputs: Vec::new(),
            include_imports: false,
        }
    }
}

/// Protobuf (protoc) version.
pub struct Version {
    version: String,
}

impl Version {
    /// `true` if the protoc major version is 3.
    pub fn is_3(&self) -> bool {
        self.version.starts_with("3")
    }
}

impl fmt::Display for Version {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.version, f)
    }
}

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

    #[test]
    fn version() {
        Protoc::from_env_path().version().expect("version");
    }
}
<commit_msg>Rename protoc::Args to protoc::ProtocCommand<commit_after>//! API to invoke `protoc` command.
//!
//! `protoc` command must be in `$PATH`, along with `protoc-gen-LANG` command.
//!
//! Note that to generate `rust` code from `.proto` files, `protoc-rust` crate
//! can be used, which does not require `protoc-gen-rust` present in `$PATH`.

#![deny(missing_docs)]

use std::ffi::{OsStr, OsString};
use std::fmt;
use std::io;
use std::path::{Path, PathBuf};
use std::process;

#[macro_use]
extern crate log;
extern crate which;

/// Alias for io::Error
pub type Error = io::Error;
/// Alias for io::Result
pub type Result<T> = io::Result<T>;

fn err_other(s: impl AsRef<str>) -> Error {
    Error::new(io::ErrorKind::Other, s.as_ref().to_owned())
}

/// `protoc --lang_out=... ...` command builder and spawner.
///
/// # Examples
///
/// ```no_run
/// use protoc::ProtocLangOut;
/// ProtocLangOut::new()
///     .lang("go")
///     .include("protos")
///     .include("more-protos")
///     .out_dir("generated-protos")
///     .run()
///     .unwrap();
/// ```
#[derive(Default)]
pub struct ProtocLangOut {
    protoc: Option<Protoc>,
    /// `LANG` part in `--LANG_out=...`
    lang: Option<String>,
    /// `--LANG_out=...` param
    out_dir: Option<PathBuf>,
    /// `--plugin` param. Not needed if plugin is in `$PATH`
    plugin: Option<OsString>,
    /// `-I` args
    includes: Vec<PathBuf>,
    /// List of `.proto` files to compile
    inputs: Vec<PathBuf>,
}

impl ProtocLangOut {
    /// Arguments to the `protoc` found in `$PATH`
    pub fn new() -> Self {
        Self::default()
    }

    /// Set `LANG` part in `--LANG_out=...`
    pub fn lang(&mut self, lang: &str) -> &mut Self {
        self.lang = Some(lang.to_owned());
        self
    }

    /// Set `--LANG_out=...` param
    pub fn out_dir(&mut self, out_dir: impl AsRef<Path>) -> &mut Self {
        self.out_dir = Some(out_dir.as_ref().to_owned());
        self
    }

    /// Set `--plugin` param. Not needed if plugin is in `$PATH`
    pub fn plugin(&mut self, plugin: impl AsRef<OsStr>) -> &mut Self {
        self.plugin = Some(plugin.as_ref().to_owned());
        self
    }

    /// Append a path to `-I` args
    pub fn include(&mut self, include: impl AsRef<Path>) -> &mut Self {
        self.includes.push(include.as_ref().to_owned());
        self
    }

    /// Append multiple paths to `-I` args
    pub fn includes(&mut self, includes: impl IntoIterator<Item = impl AsRef<Path>>) -> &mut Self {
        for include in includes {
            self.include(include);
        }
        self
    }

    /// Append a `.proto` file path to compile
    pub fn input(&mut self, input: impl AsRef<Path>) -> &mut Self {
        self.inputs.push(input.as_ref().to_owned());
        self
    }

    /// Append multiple `.proto` file paths to compile
    pub fn inputs(&mut self, inputs: impl IntoIterator<Item = impl AsRef<Path>>) -> &mut Self {
        for input in inputs {
            self.input(input);
        }
        self
    }

    /// Execute `protoc` with given args
    pub fn run(&self) -> Result<()> {
        let protoc = match &self.protoc {
            Some(protoc) => protoc.clone(),
            None => {
                let protoc = Protoc::from_env_path();
                // Check with have good `protoc`
                protoc.check()?;
                protoc
            }
        };

        if self.inputs.is_empty() {
            return Err(err_other("input is empty"));
        }

        let out_dir = self
            .out_dir
            .as_ref()
            .ok_or_else(|| err_other("out_dir is empty"))?;
        let lang = self
            .lang
            .as_ref()
            .ok_or_else(|| err_other("lang is empty"))?;

        // --{lang}_out={out_dir}
        let mut lang_out_flag = OsString::from("--");
        lang_out_flag.push(lang);
        lang_out_flag.push("_out=");
        lang_out_flag.push(out_dir);

        // --plugin={plugin}
        let plugin_flag = self.plugin.as_ref().map(|plugin| {
            let mut flag = OsString::from("--plugin=");
            flag.push(plugin);
            flag
        });

        // -I{include}
        let include_flags = self.includes.iter().map(|include| {
            let mut flag = OsString::from("-I");
            flag.push(include);
            flag
        });

        let mut cmd_args = Vec::new();
        cmd_args.push(lang_out_flag);
        cmd_args.extend(self.inputs.iter().map(|path| path.as_os_str().to_owned()));
        cmd_args.extend(plugin_flag);
        cmd_args.extend(include_flags);
        protoc.run_with_args(cmd_args)
    }
}

/// `Protoc --descriptor_set_out...` args
#[derive(Debug)]
pub struct DescriptorSetOutArgs {
    protoc: Protoc,
    /// `--file_descriptor_out=...` param
    out: Option<PathBuf>,
    /// `-I` args
    includes: Vec<PathBuf>,
    /// List of `.proto` files to compile
    inputs: Vec<PathBuf>,
    /// `--include_imports`
    include_imports: bool,
}

impl DescriptorSetOutArgs {
    /// Set `--file_descriptor_out=...` param
    pub fn out(&mut self, out: impl AsRef<Path>) -> &mut Self {
        self.out = Some(out.as_ref().to_owned());
        self
    }

    /// Append a path to `-I` args
    pub fn include(&mut self, include: impl AsRef<Path>) -> &mut Self {
        self.includes.push(include.as_ref().to_owned());
        self
    }

    /// Append multiple paths to `-I` args
    pub fn includes(&mut self, includes: impl IntoIterator<Item = impl AsRef<Path>>) -> &mut Self {
        for include in includes {
            self.include(include);
        }
        self
    }

    /// Append a `.proto` file path to compile
    pub fn input(&mut self, input: impl AsRef<Path>) -> &mut Self {
        self.inputs.push(input.as_ref().to_owned());
        self
    }

    /// Append multiple `.proto` file paths to compile
    pub fn inputs(&mut self, inputs: impl IntoIterator<Item = impl AsRef<Path>>) -> &mut Self {
        for input in inputs {
            self.input(input);
        }
        self
    }

    /// Set `--include_imports`
    pub fn include_imports(&mut self, include_imports: bool) -> &mut Self {
        self.include_imports = include_imports;
        self
    }

    /// Execute `protoc --descriptor_set_out=`
    pub fn write_descriptor_set(&self) -> Result<()> {
        if self.inputs.is_empty() {
            return Err(err_other("input is empty"));
        }

        let out = self.out.as_ref().ok_or_else(|| err_other("out is empty"))?;

        // -I{include}
        let include_flags = self.includes.iter().map(|include| {
            let mut flag = OsString::from("-I");
            flag.push(include);
            flag
        });

        // --descriptor_set_out={out}
        let mut descriptor_set_out_flag = OsString::from("--descriptor_set_out=");
        descriptor_set_out_flag.push(out);

        // --include_imports
        let include_imports_flag = match self.include_imports {
            false => None,
            true => Some("--include_imports".into()),
        };

        let mut cmd_args = Vec::new();
        cmd_args.extend(include_flags);
        cmd_args.push(descriptor_set_out_flag);
        cmd_args.extend(include_imports_flag);
        cmd_args.extend(self.inputs.iter().map(|path| path.as_os_str().to_owned()));
        self.protoc.run_with_args(cmd_args)
    }
}

/// Protoc command.
#[derive(Clone, Debug)]
pub struct Protoc {
    exec: OsString,
}

impl Protoc {
    /// New `protoc` command from `$PATH`
    pub fn from_env_path() -> Protoc {
        if let Ok(path) = which::which("protoc") {
            Protoc {
                exec: path.into_os_string(),
            }
        } else {
            panic!("protoc binary not found");
        }
    }

    /// New `protoc` command from specified path
    ///
    /// # Examples
    ///
    /// ```no_run
    /// # mod protoc_bin_vendored {
    /// #   pub fn protoc_bin_path() -> Result<std::path::PathBuf, std::io::Error> {
    /// #       unimplemented!()
    /// #   }
    /// # }
    ///
    /// // Use a binary from `protoc-bin-vendored` crate
    /// let protoc = protoc::Protoc::from_path(
    ///     protoc_bin_vendored::protoc_bin_path().unwrap());
    /// ```
    pub fn from_path(path: impl AsRef<OsStr>) -> Protoc {
        Protoc {
            exec: path.as_ref().to_owned(),
        }
    }

    /// Check `protoc` command found and valid
    pub fn check(&self) -> Result<()> {
        self.version().map(|_| ())
    }

    fn spawn(&self, cmd: &mut process::Command) -> io::Result<process::Child> {
        info!("spawning command {:?}", cmd);

        cmd.spawn()
            .map_err(|e| Error::new(e.kind(), format!("failed to spawn `{:?}`: {}", cmd, e)))
    }

    /// Obtain `protoc` version
    pub fn version(&self) -> Result<Version> {
        let child = self.spawn(
            process::Command::new(&self.exec)
                .stdin(process::Stdio::null())
                .stdout(process::Stdio::piped())
                .stderr(process::Stdio::piped())
                .args(&["--version"]),
        )?;

        let output = child.wait_with_output()?;
        if !output.status.success() {
            return Err(err_other("protoc failed with error"));
        }
        let output =
            String::from_utf8(output.stdout).map_err(|e| Error::new(io::ErrorKind::Other, e))?;
        let output = match output.lines().next() {
            None => return Err(err_other("output is empty")),
            Some(line) => line,
        };
        let prefix = "libprotoc ";
        if !output.starts_with(prefix) {
            return Err(err_other("output does not start with prefix"));
        }
        let output = &output[prefix.len()..];
        if output.is_empty() {
            return Err(err_other("version is empty"));
        }
        let first = output.chars().next().unwrap();
        if !first.is_digit(10) {
            return Err(err_other("version does not start with digit"));
        }
        Ok(Version {
            version: output.to_owned(),
        })
    }

    /// Execute `protoc` command with given args, check it completed correctly.
    fn run_with_args(&self, args: Vec<OsString>) -> Result<()> {
        let mut cmd = process::Command::new(&self.exec);
        cmd.stdin(process::Stdio::null());
        cmd.args(args);

        let mut child = self.spawn(&mut cmd)?;

        if !child.wait()?.success() {
            return Err(err_other(format!(
                "protoc ({:?}) exited with non-zero exit code",
                cmd
            )));
        }

        Ok(())
    }

    /// Get default Args for this command.
    pub fn args(&self) -> ProtocLangOut {
        ProtocLangOut {
            protoc: Some(self.clone()),
            ..ProtocLangOut::new()
        }
    }

    /// Get default DescriptorSetOutArgs for this command.
    pub fn descriptor_set_out_args(&self) -> DescriptorSetOutArgs {
        DescriptorSetOutArgs {
            protoc: self.clone(),
            out: None,
            includes: Vec::new(),
            inputs: Vec::new(),
            include_imports: false,
        }
    }
}

/// Protobuf (protoc) version.
pub struct Version {
    version: String,
}

impl Version {
    /// `true` if the protoc major version is 3.
    pub fn is_3(&self) -> bool {
        self.version.starts_with("3")
    }
}

impl fmt::Display for Version {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.version, f)
    }
}

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

    #[test]
    fn version() {
        Protoc::from_env_path().version().expect("version");
    }
}
<|endoftext|>


<commit_before>use core::cell::Cell;
use hotel::crypto::dcrypto::{Dcrypto, DcryptoClient, ProgramFault};
use kernel::{AppId, Callback, Driver, ReturnCode, Shared, AppSlice};
use kernel::common::take_cell::{MapCell};

pub const DRIVER_NUM: usize = 0x40004;

pub struct App {
    program: Option<AppSlice<Shared, u8>>,
    data_buffer: Option<AppSlice<Shared, u8>>,
    callback: Option<Callback>,
}

impl Default for App {
    fn default() -> App {
        App {
            program: None,
            data_buffer: None,
            callback: None
        }
    }
}

pub struct DcryptoDriver<'a> {
    device: &'a Dcrypto<'a>,
    app: MapCell<App>,
    current_user: Cell<Option<AppId>>,
    busy: Cell<bool>,
}

impl<'a> DcryptoDriver<'a> {
    pub fn new(device: &'a mut Dcrypto<'a>) -> DcryptoDriver<'a> {
        DcryptoDriver {
            device: device,
            current_user: Cell::new(None),
            app: MapCell::new(App::default()),
            busy: Cell::new(false),
       }
    }

    fn run_program(&self, app: &mut App) -> ReturnCode {
        if app.data_buffer.is_none() || app.program.is_none() {
            return ReturnCode::ENOMEM;
        }

        let mut rval = ReturnCode::SUCCESS;
        let data_slice = app.data_buffer.take().unwrap();
        let program_slice = app.program.take().unwrap();
        {
            // In user space, len is in bytes. For the device, however,
            // len is in terms of words, with partial words being truncated.
            // So divide by 4.
            let data = data_slice.as_ref();
            let data_len = data.len() / 4;
            let program = program_slice.as_ref();
            let program_len = program.len() / 4;

            rval = self.device.write_data(data, 0, data_len as u32);

            if rval == ReturnCode::SUCCESS {
                rval = self.device.write_instructions(program, 0, program_len as u32);
            }
        };
        app.data_buffer = Some(data_slice);
        app.program = Some(program_slice);

        if rval != ReturnCode::SUCCESS {
            return rval;
        }
        rval = self.device.call_imem(0);
        if rval != ReturnCode::SUCCESS {
            return rval;
        }
        ReturnCode::SUCCESS
    }
}

impl<'a> Driver for DcryptoDriver<'a> {
    fn subscribe(&self, subscribe_num: usize, callback: Callback) -> ReturnCode {
        match subscribe_num {
            0 => {
                self.app.map(|app| {
                    app.callback = Some(callback);
                });
                ReturnCode::SUCCESS
            },
            _ => ReturnCode::ENOSUPPORT
        }
    }

    fn command(&self, command_num: usize, arg1: usize, _: usize, caller_id: AppId) -> ReturnCode {
        match command_num {
            0 /* Check if present */ => ReturnCode::SUCCESS,
            1 /* run program */ => {
                if self.busy.get() {
                    ReturnCode::EBUSY
                } else {
                    self.app.map_or(ReturnCode::EBUSY, |app| {
                        self.busy.set(true);
                        self.run_program(app)
                    })
                }
            }
            _ => ReturnCode::ENOSUPPORT,
        }
    }

    fn allow(&self, app_id: AppId, minor_num: usize, slice: AppSlice<Shared, u8>) -> ReturnCode {
        match minor_num {
            0 => {
                // Data memory
                self.app
                    .map(|app_data| {
                        app_data.data_buffer = Some(slice);
                        ReturnCode::SUCCESS
                    })
                    .unwrap_or(ReturnCode::FAIL)
            }
            1 => {
                // Input Buffer
                self.app
                    .map(|app_data| {
                        app_data.program = Some(slice);
                        ReturnCode::SUCCESS
                    })
                    .unwrap_or(ReturnCode::FAIL)
            }
            _ => ReturnCode::ENOSUPPORT,
        }
    }
}

impl<'a> DcryptoClient<'a> for DcryptoDriver<'a> {
    fn execution_complete(&self, error: ReturnCode, fault: ProgramFault) {
        self.busy.set(false);
        self.app.map(move |app| {
            app.callback.map(|mut callback| {
                let mut data_slice = app.data_buffer.take().unwrap();
                {
                    let data = data_slice.as_mut();
                    // In user space, len is in bytes. For the device,
                    // however, len is in terms of words, with partial
                    // words being truncated.  So divide by 4.
                    let len = (data.len() / 4) as u32;
                    self.device.read_data(data, 0, len);
                    callback.schedule(usize::from(error), usize::from(fault), 0);
                }
                app.data_buffer = Some(data_slice);
            });
        });
    }

    fn reset_complete(&self, _error: ReturnCode) {
        panic!("ERROR: Dcrypto driver reset_complete invoked, but should never be called.");
    }

    fn secret_wipe_complete(&self, _error: ReturnCode) {
        panic!("ERROR: Dcrypto driver secret_wipe_complete invoked, but should never be called.");
    }

}
<commit_msg>Fix warnings in dcrypto.<commit_after>use core::cell::Cell;
use hotel::crypto::dcrypto::{Dcrypto, DcryptoClient, ProgramFault};
use kernel::{AppId, Callback, Driver, ReturnCode, Shared, AppSlice};
use kernel::common::take_cell::{MapCell};

pub const DRIVER_NUM: usize = 0x40004;

pub struct App {
    program: Option<AppSlice<Shared, u8>>,
    data_buffer: Option<AppSlice<Shared, u8>>,
    callback: Option<Callback>,
}

impl Default for App {
    fn default() -> App {
        App {
            program: None,
            data_buffer: None,
            callback: None
        }
    }
}

pub struct DcryptoDriver<'a> {
    device: &'a Dcrypto<'a>,
    app: MapCell<App>,
    busy: Cell<bool>,
}

impl<'a> DcryptoDriver<'a> {
    pub fn new(device: &'a mut Dcrypto<'a>) -> DcryptoDriver<'a> {
        DcryptoDriver {
            device: device,
            app: MapCell::new(App::default()),
            busy: Cell::new(false),
       }
    }

    fn run_program(&self, app: &mut App) -> ReturnCode {
        if app.data_buffer.is_none() || app.program.is_none() {
            return ReturnCode::ENOMEM;
        }

        let mut rval: ReturnCode;
        let data_slice = app.data_buffer.take().unwrap();
        let program_slice = app.program.take().unwrap();
        {
            // In user space, len is in bytes. For the device, however,
            // len is in terms of words, with partial words being truncated.
            // So divide by 4.
            let data = data_slice.as_ref();
            let data_len = data.len() / 4;
            let program = program_slice.as_ref();
            let program_len = program.len() / 4;

            rval = self.device.write_data(data, 0, data_len as u32);

            if rval == ReturnCode::SUCCESS {
                rval = self.device.write_instructions(program, 0, program_len as u32);
            }
        };
        app.data_buffer = Some(data_slice);
        app.program = Some(program_slice);

        if rval != ReturnCode::SUCCESS {
            return rval;
        }
        rval = self.device.call_imem(0);
        if rval != ReturnCode::SUCCESS {
            return rval;
        }
        ReturnCode::SUCCESS
    }
}

impl<'a> Driver for DcryptoDriver<'a> {
    fn subscribe(&self, subscribe_num: usize, callback: Callback) -> ReturnCode {
        match subscribe_num {
            0 => {
                self.app.map(|app| {
                    app.callback = Some(callback);
                });
                ReturnCode::SUCCESS
            },
            _ => ReturnCode::ENOSUPPORT
        }
    }

    fn command(&self, command_num: usize, _: usize, _: usize, _: AppId) -> ReturnCode {
        match command_num {
            0 /* Check if present */ => ReturnCode::SUCCESS,
            1 /* run program */ => {
                if self.busy.get() {
                    ReturnCode::EBUSY
                } else {
                    self.app.map_or(ReturnCode::EBUSY, |app| {
                        self.busy.set(true);
                        self.run_program(app)
                    })
                }
            }
            _ => ReturnCode::ENOSUPPORT,
        }
    }

    fn allow(&self, _: AppId, minor_num: usize, slice: AppSlice<Shared, u8>) -> ReturnCode {
        match minor_num {
            0 => {
                // Data memory
                self.app
                    .map(|app_data| {
                        app_data.data_buffer = Some(slice);
                        ReturnCode::SUCCESS
                    })
                    .unwrap_or(ReturnCode::FAIL)
            }
            1 => {
                // Input Buffer
                self.app
                    .map(|app_data| {
                        app_data.program = Some(slice);
                        ReturnCode::SUCCESS
                    })
                    .unwrap_or(ReturnCode::FAIL)
            }
            _ => ReturnCode::ENOSUPPORT,
        }
    }
}

impl<'a> DcryptoClient<'a> for DcryptoDriver<'a> {
    fn execution_complete(&self, error: ReturnCode, fault: ProgramFault) {
        self.busy.set(false);
        self.app.map(move |app| {
            app.callback.map(|mut callback| {
                let mut data_slice = app.data_buffer.take().unwrap();
                {
                    let data = data_slice.as_mut();
                    // In user space, len is in bytes. For the device,
                    // however, len is in terms of words, with partial
                    // words being truncated.  So divide by 4.
                    let len = (data.len() / 4) as u32;
                    self.device.read_data(data, 0, len);
                    callback.schedule(usize::from(error), usize::from(fault), 0);
                }
                app.data_buffer = Some(data_slice);
            });
        });
    }

    fn reset_complete(&self, _error: ReturnCode) {
        panic!("ERROR: Dcrypto driver reset_complete invoked, but should never be called.");
    }

    fn secret_wipe_complete(&self, _error: ReturnCode) {
        panic!("ERROR: Dcrypto driver secret_wipe_complete invoked, but should never be called.");
    }

}
<|endoftext|>


<commit_before>mod http;
mod udp;
mod errors;
mod dns;
mod dht;

use std::collections::VecDeque;
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
use std::{io, result, thread};
use std::sync::Arc;

use byteorder::{BigEndian, ReadBytesExt};
use url::Url;
use amy;

pub use self::errors::{Error, ErrorKind, Result, ResultExt};
use torrent::Torrent;
use bencode::BEncode;
use control::cio;
use handle;
use disk;
use CONFIG;

pub struct Tracker {
    poll: amy::Poller,
    ch: handle::Handle<Request, Response>,
    dns_res: amy::Receiver<dns::QueryResponse>,
    http: http::Handler,
    queue: VecDeque<Announce>,
    udp: udp::Handler,
    dht: dht::Manager,
    dns: dns::Resolver,
    timer: usize,
    shutting_down: bool,
}

#[derive(Debug)]
pub enum Request {
    Announce(Announce),
    GetPeers(GetPeers),
    AddNode(SocketAddr),
    DHTAnnounce([u8; 20]),
    Ping,
    Shutdown,
}

#[derive(Debug)]
pub struct Announce {
    id: usize,
    url: Arc<Url>,
    hash: [u8; 20],
    port: u16,
    uploaded: u64,
    downloaded: u64,
    left: u64,
    num_want: Option<u16>,
    event: Option<Event>,
}

#[derive(Debug)]
pub struct GetPeers {
    pub id: usize,
    pub hash: [u8; 20],
}

#[derive(Debug)]
pub enum Event {
    Started,
    Stopped,
    Completed,
}

#[derive(Debug)]
pub enum Response {
    Tracker {
        tid: usize,
        url: Arc<Url>,
        resp: Result<TrackerResponse>,
    },
    DHT {
        tid: usize,
        peers: Vec<SocketAddr>,
    },
}

#[derive(Debug)]
pub struct TrackerResponse {
    pub peers: Vec<SocketAddr>,
    pub interval: u32,
    pub leechers: u32,
    pub seeders: u32,
}

const POLL_INT_MS: usize = 1000;

impl Tracker {
    pub fn start(
        creg: &mut amy::Registrar,
        db: amy::Sender<disk::Request>,
    ) -> io::Result<(handle::Handle<Response, Request>, thread::JoinHandle<()>)> {
        let poll = amy::Poller::new()?;
        let mut reg = poll.get_registrar();
        let (ch, dh) = handle::Handle::new(creg, &mut reg)?;
        let timer = reg.set_interval(150)?;
        let (dtx, drx) = reg.channel()?;
        let udp = udp::Handler::new(&reg)?;
        let dht = dht::Manager::new(&reg, db)?;
        let http = http::Handler::new(&reg)?;
        let dns = dns::Resolver::new(dtx);
        let th = dh.run("trk", move |h| {
            Tracker {
                poll,
                ch: h,
                udp,
                dht,
                http,
                dns,
                dns_res: drx,
                timer,
                queue: VecDeque::new(),
                shutting_down: false,
            }.run()
        })?;
        Ok((ch, th))
    }

    pub fn run(&mut self) {
        self.dht.init();

        debug!("Initialized!");
        'outer: loop {
            match self.poll.wait(POLL_INT_MS) {
                Ok(events) => for event in events {
                    if self.handle_event(event).is_err() {
                        break 'outer;
                    }
                },
                Err(e) => {
                    error!("Failed to poll for events: {}", e);
                }
            }
        }

        self.shutting_down = true;

        // Shutdown loop - wait for all requests to complete
        loop {
            for event in self.poll.wait(POLL_INT_MS).unwrap() {
                if self.handle_event(event).is_err() {}
                if self.http.complete() && self.udp.complete() {
                    return;
                }
            }
        }
    }

    fn handle_event(&mut self, event: amy::Notification) -> result::Result<(), ()> {
        if event.id == self.ch.rx.get_id() {
            return self.handle_request();
        } else if event.id == self.dns_res.get_id() {
            self.handle_dns_res();
        } else if event.id == self.timer {
            self.handle_timer();
        } else {
            self.handle_socket(event);
        }
        Ok(())
    }

    fn handle_request(&mut self) -> result::Result<(), ()> {
        while let Ok(r) = self.ch.recv() {
            match r {
                Request::Announce(req) => self.handle_announce(req),
                Request::GetPeers(gp) => {
                    trace!("Handling dht peer find req!");
                    self.dht.get_peers(gp.id, gp.hash);
                }
                Request::AddNode(addr) => {
                    trace!("Handling dht node addition req!");
                    self.dht.add_addr(addr);
                }
                Request::DHTAnnounce(hash) => {
                    trace!("Handling dht announce req!");
                    self.dht.announce(hash);
                }
                Request::Ping => {}
                Request::Shutdown => {
                    return Err(());
                }
            }
        }
        Ok(())
    }

    fn handle_announce(&mut self, req: Announce) {
        debug!("Handling announce request!");
        if self.udp.active_requests() + self.http.active_requests() > CONFIG.net.max_open_announces
        {
            self.queue.push_back(req);
        } else {
            let id = req.id;
            let url = req.url.clone();
            let response = match url.scheme() {
                "http" | "https" => self.http.new_announce(req, &mut self.dns),
                "udp" => self.udp.new_announce(req, &mut self.dns),
                s => Err(
                    ErrorKind::InvalidRequest(format!("Unknown tracker url scheme: {}", s)).into(),
                ),
            };
            if let Err(e) = response {
                self.send_response(Response::Tracker {
                    tid: id,
                    url,
                    resp: Err(e),
                });
            }
        }
    }

    fn dequeue_req(&mut self) {
        // Attempt to dequeue next request if we can
        if let Some(a) = self.queue.pop_front() {
            self.handle_announce(a);
        }
    }

    fn handle_dns_res(&mut self) {
        while let Ok(r) = self.dns_res.try_recv() {
            let resp = if self.http.contains(r.id) {
                self.http.dns_resolved(r)
            } else if self.udp.contains(r.id) {
                self.udp.dns_resolved(r)
            } else {
                None
            };
            if let Some(r) = resp {
                self.send_response(r);
            }
        }
    }

    fn handle_timer(&mut self) {
        for r in self.http
            .tick()
            .into_iter()
            .chain(self.udp.tick().into_iter())
        {
            self.send_response(r);
        }

        self.dns.tick();
        self.dht.tick();
    }

    fn handle_socket(&mut self, event: amy::Notification) {
        if self.http.contains(event.id) {
            let resp = if event.event.readable() {
                self.http.readable(event.id, &mut self.dns)
            } else {
                self.http.writable(event.id)
            };
            if let Some(r) = resp {
                self.send_response(r);
            }
        } else if self.udp.id() == event.id {
            for resp in self.udp.readable() {
                self.send_response(resp);
            }
        } else if self.dht.id() == event.id {
            for resp in self.dht.readable() {
                self.send_response(resp);
            }
        } else {
            unreachable!();
        };
    }

    fn send_response(&mut self, r: Response) {
        if !self.shutting_down {
            trace!("Sending trk response to control!");
            self.ch.send(r).ok();
        }
        // TODO: The active announce queue could grow with DHT usage,
        // since DHT stuff doesn't go into the announce queue, but still triggers send_response.
        // Not a big deal, but worth thinking about for later.
        self.dequeue_req();
    }
}

impl Request {
    pub fn new_announce<T: cio::CIO>(
        torrent: &Torrent<T>,
        event: Option<Event>,
    ) -> Option<Request> {
        let url = if let Some(trk) = torrent.trackers().front() {
            trk.url.clone()
        } else {
            return None;
        };
        Some(Request::Announce(Announce {
            id: torrent.id(),
            url,
            hash: torrent.info().hash,
            port: CONFIG.port,
            uploaded: torrent.uploaded(),
            downloaded: torrent.downloaded(),
            // This should be fine because the true len is usually slightly less than
            // piece_len * pieces_dld (due to shorter last piece), so we always get
            // either the correct amount left or 0.
            left: torrent.info().total_len.saturating_sub(
                torrent.pieces().iter().count() as u64 * torrent.info().piece_len as u64,
            ),
            // TODO: Develop better heuristics here.
            // For now, only request peers if we're leeching,
            // let existing peers connect otherwise
            num_want: if torrent.complete() { None } else { Some(50) },
            event,
        }))
    }

    pub fn started<T: cio::CIO>(torrent: &Torrent<T>) -> Option<Request> {
        Request::new_announce(torrent, Some(Event::Started))
    }

    pub fn stopped<T: cio::CIO>(torrent: &Torrent<T>) -> Option<Request> {
        Request::new_announce(torrent, Some(Event::Stopped))
    }

    pub fn completed<T: cio::CIO>(torrent: &Torrent<T>) -> Option<Request> {
        Request::new_announce(torrent, Some(Event::Completed))
    }

    pub fn interval<T: cio::CIO>(torrent: &Torrent<T>) -> Option<Request> {
        Request::new_announce(torrent, None)
    }

    pub fn custom<T: cio::CIO>(torrent: &Torrent<T>, url: Arc<Url>) -> Option<Request> {
        Request::new_announce(torrent, None).map(|mut r| {
            match r {
                Request::Announce(ref mut a) => a.url = url,
                _ => {}
            }
            r
        })
    }
}

impl TrackerResponse {
    pub fn empty() -> TrackerResponse {
        TrackerResponse {
            peers: vec![],
            interval: 900,
            leechers: 0,
            seeders: 0,
        }
    }

    pub fn from_bencode(data: BEncode) -> Result<TrackerResponse> {
        let mut d = data.into_dict().ok_or(ErrorKind::InvalidResponse(
            "Tracker response must be a dictionary type!",
        ))?;
        if let Some(BEncode::String(data)) = d.remove("failure reason") {
            let reason = String::from_utf8(data)
                .chain_err(|| ErrorKind::InvalidResponse("Failure reason must be UTF8!"))?;
            return Err(ErrorKind::TrackerError(reason).into());
        }
        let mut resp = TrackerResponse::empty();
        match d.remove("peers") {
            Some(BEncode::String(ref data)) => for p in data.chunks(6) {
                let ip = Ipv4Addr::new(p[0], p[1], p[2], p[3]);
                let socket = SocketAddrV4::new(ip, (&p[4..]).read_u16::<BigEndian>().unwrap());
                resp.peers.push(SocketAddr::V4(socket));
            },
            _ => {}
        };
        match d.remove("interval") {
            Some(BEncode::Int(ref i)) => {
                resp.interval = *i as u32;
            }
            _ => {
                return Err(ErrorKind::InvalidResponse("Response must have interval!").into());
            }
        };
        Ok(resp)
    }
}
<commit_msg>Stop tracker thread from crashing in exceptional situations<commit_after>mod http;
mod udp;
mod errors;
mod dns;
mod dht;

use std::collections::VecDeque;
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
use std::{io, result, thread};
use std::sync::Arc;

use byteorder::{BigEndian, ReadBytesExt};
use url::Url;
use amy;

pub use self::errors::{Error, ErrorKind, Result, ResultExt};
use torrent::Torrent;
use bencode::BEncode;
use control::cio;
use handle;
use disk;
use CONFIG;

pub struct Tracker {
    poll: amy::Poller,
    ch: handle::Handle<Request, Response>,
    dns_res: amy::Receiver<dns::QueryResponse>,
    http: http::Handler,
    queue: VecDeque<Announce>,
    udp: udp::Handler,
    dht: dht::Manager,
    dns: dns::Resolver,
    timer: usize,
    shutting_down: bool,
}

#[derive(Debug)]
pub enum Request {
    Announce(Announce),
    GetPeers(GetPeers),
    AddNode(SocketAddr),
    DHTAnnounce([u8; 20]),
    Ping,
    Shutdown,
}

#[derive(Debug)]
pub struct Announce {
    id: usize,
    url: Arc<Url>,
    hash: [u8; 20],
    port: u16,
    uploaded: u64,
    downloaded: u64,
    left: u64,
    num_want: Option<u16>,
    event: Option<Event>,
}

#[derive(Debug)]
pub struct GetPeers {
    pub id: usize,
    pub hash: [u8; 20],
}

#[derive(Debug)]
pub enum Event {
    Started,
    Stopped,
    Completed,
}

#[derive(Debug)]
pub enum Response {
    Tracker {
        tid: usize,
        url: Arc<Url>,
        resp: Result<TrackerResponse>,
    },
    DHT {
        tid: usize,
        peers: Vec<SocketAddr>,
    },
}

#[derive(Debug)]
pub struct TrackerResponse {
    pub peers: Vec<SocketAddr>,
    pub interval: u32,
    pub leechers: u32,
    pub seeders: u32,
}

const POLL_INT_MS: usize = 1000;

impl Tracker {
    pub fn start(
        creg: &mut amy::Registrar,
        db: amy::Sender<disk::Request>,
    ) -> io::Result<(handle::Handle<Response, Request>, thread::JoinHandle<()>)> {
        let poll = amy::Poller::new()?;
        let mut reg = poll.get_registrar();
        let (ch, dh) = handle::Handle::new(creg, &mut reg)?;
        let timer = reg.set_interval(150)?;
        let (dtx, drx) = reg.channel()?;
        let udp = udp::Handler::new(&reg)?;
        let dht = dht::Manager::new(&reg, db)?;
        let http = http::Handler::new(&reg)?;
        let dns = dns::Resolver::new(dtx);
        let th = dh.run("trk", move |h| {
            Tracker {
                poll,
                ch: h,
                udp,
                dht,
                http,
                dns,
                dns_res: drx,
                timer,
                queue: VecDeque::new(),
                shutting_down: false,
            }.run()
        })?;
        Ok((ch, th))
    }

    pub fn run(&mut self) {
        self.dht.init();

        debug!("Initialized!");
        'outer: loop {
            match self.poll.wait(POLL_INT_MS) {
                Ok(events) => for event in events {
                    if self.handle_event(event).is_err() {
                        break 'outer;
                    }
                },
                Err(e) => {
                    error!("Failed to poll for events: {}", e);
                }
            }
        }

        self.shutting_down = true;

        // Shutdown loop - wait for all requests to complete
        loop {
            for event in self.poll.wait(POLL_INT_MS).unwrap() {
                if self.handle_event(event).is_err() {}
                if self.http.complete() && self.udp.complete() {
                    return;
                }
            }
        }
    }

    fn handle_event(&mut self, event: amy::Notification) -> result::Result<(), ()> {
        if event.id == self.ch.rx.get_id() {
            return self.handle_request();
        } else if event.id == self.dns_res.get_id() {
            self.handle_dns_res();
        } else if event.id == self.timer {
            self.handle_timer();
        } else {
            self.handle_socket(event);
        }
        Ok(())
    }

    fn handle_request(&mut self) -> result::Result<(), ()> {
        while let Ok(r) = self.ch.recv() {
            match r {
                Request::Announce(req) => self.handle_announce(req),
                Request::GetPeers(gp) => {
                    trace!("Handling dht peer find req!");
                    self.dht.get_peers(gp.id, gp.hash);
                }
                Request::AddNode(addr) => {
                    trace!("Handling dht node addition req!");
                    self.dht.add_addr(addr);
                }
                Request::DHTAnnounce(hash) => {
                    trace!("Handling dht announce req!");
                    self.dht.announce(hash);
                }
                Request::Ping => {}
                Request::Shutdown => {
                    return Err(());
                }
            }
        }
        Ok(())
    }

    fn handle_announce(&mut self, req: Announce) {
        debug!("Handling announce request!");
        if self.udp.active_requests() + self.http.active_requests() > CONFIG.net.max_open_announces
        {
            self.queue.push_back(req);
        } else {
            let id = req.id;
            let url = req.url.clone();
            let response = match url.scheme() {
                "http" | "https" => self.http.new_announce(req, &mut self.dns),
                "udp" => self.udp.new_announce(req, &mut self.dns),
                s => Err(
                    ErrorKind::InvalidRequest(format!("Unknown tracker url scheme: {}", s)).into(),
                ),
            };
            if let Err(e) = response {
                self.send_response(Response::Tracker {
                    tid: id,
                    url,
                    resp: Err(e),
                });
            }
        }
    }

    fn dequeue_req(&mut self) {
        // Attempt to dequeue next request if we can
        if let Some(a) = self.queue.pop_front() {
            self.handle_announce(a);
        }
    }

    fn handle_dns_res(&mut self) {
        while let Ok(r) = self.dns_res.try_recv() {
            let resp = if self.http.contains(r.id) {
                self.http.dns_resolved(r)
            } else if self.udp.contains(r.id) {
                self.udp.dns_resolved(r)
            } else {
                None
            };
            if let Some(r) = resp {
                self.send_response(r);
            }
        }
    }

    fn handle_timer(&mut self) {
        for r in self.http
            .tick()
            .into_iter()
            .chain(self.udp.tick().into_iter())
        {
            self.send_response(r);
        }

        self.dns.tick();
        self.dht.tick();
    }

    fn handle_socket(&mut self, event: amy::Notification) {
        if self.http.contains(event.id) {
            let resp = if event.event.readable() {
                self.http.readable(event.id, &mut self.dns)
            } else {
                self.http.writable(event.id)
            };
            if let Some(r) = resp {
                self.send_response(r);
            }
        } else if self.udp.id() == event.id {
            for resp in self.udp.readable() {
                self.send_response(resp);
            }
        } else if self.dht.id() == event.id {
            for resp in self.dht.readable() {
                self.send_response(resp);
            }
        } else {
            error!("Unknown event occured for tracker: {:?}", event);
        };
    }

    fn send_response(&mut self, r: Response) {
        if !self.shutting_down {
            trace!("Sending trk response to control!");
            self.ch.send(r).ok();
        }
        // TODO: The active announce queue could grow with DHT usage,
        // since DHT stuff doesn't go into the announce queue, but still triggers send_response.
        // Not a big deal, but worth thinking about for later.
        self.dequeue_req();
    }
}

impl Request {
    pub fn new_announce<T: cio::CIO>(
        torrent: &Torrent<T>,
        event: Option<Event>,
    ) -> Option<Request> {
        let url = if let Some(trk) = torrent.trackers().front() {
            trk.url.clone()
        } else {
            return None;
        };
        Some(Request::Announce(Announce {
            id: torrent.id(),
            url,
            hash: torrent.info().hash,
            port: CONFIG.port,
            uploaded: torrent.uploaded(),
            downloaded: torrent.downloaded(),
            // This should be fine because the true len is usually slightly less than
            // piece_len * pieces_dld (due to shorter last piece), so we always get
            // either the correct amount left or 0.
            left: torrent.info().total_len.saturating_sub(
                torrent.pieces().iter().count() as u64 * torrent.info().piece_len as u64,
            ),
            // TODO: Develop better heuristics here.
            // For now, only request peers if we're leeching,
            // let existing peers connect otherwise
            num_want: if torrent.complete() { None } else { Some(50) },
            event,
        }))
    }

    pub fn started<T: cio::CIO>(torrent: &Torrent<T>) -> Option<Request> {
        Request::new_announce(torrent, Some(Event::Started))
    }

    pub fn stopped<T: cio::CIO>(torrent: &Torrent<T>) -> Option<Request> {
        Request::new_announce(torrent, Some(Event::Stopped))
    }

    pub fn completed<T: cio::CIO>(torrent: &Torrent<T>) -> Option<Request> {
        Request::new_announce(torrent, Some(Event::Completed))
    }

    pub fn interval<T: cio::CIO>(torrent: &Torrent<T>) -> Option<Request> {
        Request::new_announce(torrent, None)
    }

    pub fn custom<T: cio::CIO>(torrent: &Torrent<T>, url: Arc<Url>) -> Option<Request> {
        Request::new_announce(torrent, None).map(|mut r| {
            match r {
                Request::Announce(ref mut a) => a.url = url,
                _ => {}
            }
            r
        })
    }
}

impl TrackerResponse {
    pub fn empty() -> TrackerResponse {
        TrackerResponse {
            peers: vec![],
            interval: 900,
            leechers: 0,
            seeders: 0,
        }
    }

    pub fn from_bencode(data: BEncode) -> Result<TrackerResponse> {
        let mut d = data.into_dict().ok_or(ErrorKind::InvalidResponse(
            "Tracker response must be a dictionary type!",
        ))?;
        if let Some(BEncode::String(data)) = d.remove("failure reason") {
            let reason = String::from_utf8(data)
                .chain_err(|| ErrorKind::InvalidResponse("Failure reason must be UTF8!"))?;
            return Err(ErrorKind::TrackerError(reason).into());
        }
        let mut resp = TrackerResponse::empty();
        match d.remove("peers") {
            Some(BEncode::String(ref data)) => for p in data.chunks(6) {
                let ip = Ipv4Addr::new(p[0], p[1], p[2], p[3]);
                let socket = SocketAddrV4::new(ip, (&p[4..]).read_u16::<BigEndian>().unwrap());
                resp.peers.push(SocketAddr::V4(socket));
            },
            _ => {}
        };
        match d.remove("interval") {
            Some(BEncode::Int(ref i)) => {
                resp.interval = *i as u32;
            }
            _ => {
                return Err(ErrorKind::InvalidResponse("Response must have interval!").into());
            }
        };
        Ok(resp)
    }
}
<|endoftext|>


<commit_before>use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, TargetOptions};

pub fn opts() -> TargetOptions {
    let mut pre_link_args = LinkArgs::new();
    pre_link_args.insert(
        LinkerFlavor::Lld(LldFlavor::Ld),
        vec![
            "--build-id".to_string(),
            "--eh-frame-hdr".to_string(),
            "--hash-style=gnu".to_string(),
            "-z".to_string(),
            "rodynamic".to_string(),
        ],
    );

    TargetOptions {
        linker: Some("rust-lld".to_owned()),
        lld_flavor: LldFlavor::Ld,
        dynamic_linking: true,
        executables: true,
        target_family: Some("unix".to_string()),
        is_like_fuchsia: true,
        linker_is_gnu: true,
        has_rpath: false,
        pre_link_args,
        pre_link_objects_exe: vec!["Scrt1.o".to_string()],
        position_independent_executables: true,
        has_elf_tls: true,
        ..Default::default()
    }
}
<commit_msg>Update the Fuchsia linker defaults<commit_after>use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, TargetOptions};

pub fn opts() -> TargetOptions {
    let mut pre_link_args = LinkArgs::new();
    pre_link_args.insert(
        LinkerFlavor::Lld(LldFlavor::Ld),
        vec![
            "--build-id".to_string(),
            "--eh-frame-hdr".to_string(),
            "--hash-style=gnu".to_string(),
            "-z".to_string(),
            "max-page-size=4096".to_string(),
            "-z".to_string(),
            "now".to_string(),
            "-z".to_string(),
            "rodynamic".to_string(),
            "-z".to_string(),
            "separate-loadable-segments".to_string(),
            "--pack-dyn-relocs=relr".to_string(),
        ],
    );

    TargetOptions {
        linker: Some("rust-lld".to_owned()),
        lld_flavor: LldFlavor::Ld,
        dynamic_linking: true,
        executables: true,
        target_family: Some("unix".to_string()),
        is_like_fuchsia: true,
        linker_is_gnu: true,
        has_rpath: false,
        pre_link_args,
        pre_link_objects_exe: vec!["Scrt1.o".to_string()],
        position_independent_executables: true,
        has_elf_tls: true,
        ..Default::default()
    }
}
<|endoftext|>


<commit_before>//! A libray for creating and managing fibers in a cross-platform manner.
//!
//! Fibers are threads that must be manually scheduled by the client application, as opposed to
//! threads which are automatically managed and scheduled by the OS. Each fiber has its own stack
//! space and can be yield its time to another thread at any point during execution. This allows
//! for different forms of concurrency to be implemented in a way that's optimal for the client
//! application.
//!
//! This library is meant to be the base for a fiber-pool system, in which a fixed number of worker
//! fibers are created and used to asynchronously complete units of work.

#![feature(raw)]

use platform::PlatformId;
use std::cell::Cell;

#[cfg(target_os="windows")]
#[path="platform\\windows.rs"]
pub mod platform;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct FiberId(PlatformId);

/// Represents a fiber with its own stack and thread state.
///
/// The fiber's lifetime is associated with any data it borrows when created.
pub struct Fiber(PlatformId);

/// A global cache mapping threads to their currently running fiber.
///
/// This is used by `Fiber::current()` on some platforms to keep track of which fiber is active
/// on which thread.
thread_local! {
    static PREV: Cell<Option<PlatformId>> = Cell::new(None);
    static CURRENT: Cell<Option<PlatformId>> = Cell::new(None);
}

/// Initializes the current thread, making it safe to begin using threads.
///
/// On some platforms initialization is required before using threads (e.g. on Windows versions
/// older than 7 the main thread must be converted to a fiber on startup). This function performs
/// any necessary initialization and returns the active fiber. This function must be called for all
/// spawned threads to ensure that it is safe to use fibers from those threads.
pub fn init() -> Fiber {
    let platform_fiber = platform::init();

    // Initialize our thread-local cache of the current fiber.
    CURRENT.with(|current| current.set(Some(platform_fiber)));

    Fiber(platform_fiber)
}

impl Fiber {
    /// Creates a new fiber with the specified stack size and has it begin executing the specified
    /// function.
    ///
    /// # Panics
    ///
    /// Panics if `init()` has not yet been called on the current thread.
    pub fn new<F>(stack_size: usize, func: F) -> Fiber
        where
        F: Fn(Fiber),
        F: Send,
    {
        Fiber(platform::create_fiber(
            stack_size,
            &func,
        ))
    }

    /// Makes the fiber active, consuming in the process.
    ///
    /// This suspends the current fiber so that the resumed fiber can run in its place. At a later
    /// point another fiber may resume the current one, at which point `resume()` with return,
    /// yielding the fiber that was suspended.
    pub unsafe fn resume(self) -> Fiber {
        // Initialize the current thread for fiber usage if we haven't done so already.
        if let None = CURRENT.with(|current| current.get()) {
            init();
        }

        {
            let prev_handle = CURRENT.with(|current| {
                let prev = current.get();
                current.set(Some(self.0));
                prev
            });
            PREV.with(|prev| prev.set(prev_handle));
        }

        // Switch to `self`.
        platform::resume(self.0);

        // This is explicitly a different scope than before to avoid cross-contamination. We can't
        // make any assumptions about what was true before and after resuming another fiber, so we
        // enforce that we don't accidentally reuse any local variables. Only `PREV` and `CURRENT`
        // are safe to use.
        {
            let prev_fiber = PREV.with(|prev| prev.get().expect("PREV as None after resuming"));
            Fiber(prev_fiber)
        }
    }

    /// Retuns the fiber's unique ID.
    pub fn id(&self) -> FiberId {
        FiberId(self.0)
    }
}

unsafe impl Send for Fiber {}

/// Returns the fiber that is currently executing on this thread.
///
/// Returns `None` if `init()` has not yet been called on this thread.
pub fn current() -> Option<FiberId> {
    CURRENT.with(|current| current.get()).map(|platform_fiber| FiberId(platform_fiber))
}
<commit_msg>Derive Debug for Fiber<commit_after>//! A libray for creating and managing fibers in a cross-platform manner.
//!
//! Fibers are threads that must be manually scheduled by the client application, as opposed to
//! threads which are automatically managed and scheduled by the OS. Each fiber has its own stack
//! space and can be yield its time to another thread at any point during execution. This allows
//! for different forms of concurrency to be implemented in a way that's optimal for the client
//! application.
//!
//! This library is meant to be the base for a fiber-pool system, in which a fixed number of worker
//! fibers are created and used to asynchronously complete units of work.

#![feature(raw)]

use platform::PlatformId;
use std::cell::Cell;

#[cfg(target_os="windows")]
#[path="platform\\windows.rs"]
pub mod platform;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct FiberId(PlatformId);

/// Represents a fiber with its own stack and thread state.
///
/// The fiber's lifetime is associated with any data it borrows when created.
#[derive(Debug)]
pub struct Fiber(PlatformId);

/// A global cache mapping threads to their currently running fiber.
///
/// This is used by `Fiber::current()` on some platforms to keep track of which fiber is active
/// on which thread.
thread_local! {
    static PREV: Cell<Option<PlatformId>> = Cell::new(None);
    static CURRENT: Cell<Option<PlatformId>> = Cell::new(None);
}

/// Initializes the current thread, making it safe to begin using threads.
///
/// On some platforms initialization is required before using threads (e.g. on Windows versions
/// older than 7 the main thread must be converted to a fiber on startup). This function performs
/// any necessary initialization and returns the active fiber. This function must be called for all
/// spawned threads to ensure that it is safe to use fibers from those threads.
pub fn init() -> Fiber {
    let platform_fiber = platform::init();

    // Initialize our thread-local cache of the current fiber.
    CURRENT.with(|current| current.set(Some(platform_fiber)));

    Fiber(platform_fiber)
}

impl Fiber {
    /// Creates a new fiber with the specified stack size and has it begin executing the specified
    /// function.
    ///
    /// # Panics
    ///
    /// Panics if `init()` has not yet been called on the current thread.
    pub fn new<F>(stack_size: usize, func: F) -> Fiber
        where
        F: Fn(Fiber),
        F: Send,
    {
        Fiber(platform::create_fiber(
            stack_size,
            &func,
        ))
    }

    /// Makes the fiber active, consuming in the process.
    ///
    /// This suspends the current fiber so that the resumed fiber can run in its place. At a later
    /// point another fiber may resume the current one, at which point `resume()` with return,
    /// yielding the fiber that was suspended.
    pub unsafe fn resume(self) -> Fiber {
        // Initialize the current thread for fiber usage if we haven't done so already.
        if let None = CURRENT.with(|current| current.get()) {
            init();
        }

        {
            let prev_handle = CURRENT.with(|current| {
                let prev = current.get();
                current.set(Some(self.0));
                prev
            });
            PREV.with(|prev| prev.set(prev_handle));
        }

        // Switch to `self`.
        platform::resume(self.0);

        // This is explicitly a different scope than before to avoid cross-contamination. We can't
        // make any assumptions about what was true before and after resuming another fiber, so we
        // enforce that we don't accidentally reuse any local variables. Only `PREV` and `CURRENT`
        // are safe to use.
        {
            let prev_fiber = PREV.with(|prev| prev.get().expect("PREV as None after resuming"));
            Fiber(prev_fiber)
        }
    }

    /// Retuns the fiber's unique ID.
    pub fn id(&self) -> FiberId {
        FiberId(self.0)
    }
}

unsafe impl Send for Fiber {}

/// Returns the fiber that is currently executing on this thread.
///
/// Returns `None` if `init()` has not yet been called on this thread.
pub fn current() -> Option<FiberId> {
    CURRENT.with(|current| current.get()).map(|platform_fiber| FiberId(platform_fiber))
}
<|endoftext|>


<commit_before>//! Run-time feature detection for the Rust standard library.
//!
//! To detect whether a feature is enabled in the system running the binary
//! use one of the appropriate macro for the target:
//!
//! * `x86` and `x86_64`: [`is_x86_feature_detected`]
//! * `arm`: [`is_arm_feature_detected`]
//! * `aarch64`: [`is_aarch64_feature_detected`]
//! * `riscv`: [`is_riscv_feature_detected`]
//! * `mips`: [`is_mips_feature_detected`]
//! * `mips64`: [`is_mips64_feature_detected`]
//! * `powerpc`: [`is_powerpc_feature_detected`]
//! * `powerpc64`: [`is_powerpc64_feature_detected`]

#![unstable(feature = "stdsimd", issue = "27731")]
#![feature(staged_api, stdsimd, doc_cfg, allow_internal_unstable)]
#![deny(rust_2018_idioms)]
#![allow(clippy::shadow_reuse)]
#![deny(clippy::missing_inline_in_public_items)]
#![cfg_attr(test, allow(unused_imports))]
#![no_std]

#[cfg(test)]
#[macro_use]
extern crate std;

#[doc(hidden)]
#[unstable(feature = "stdsimd", issue = "27731")]
pub mod detect;
<commit_msg>Fix std_detect_file_io<commit_after>//! Run-time feature detection for the Rust standard library.
//!
//! To detect whether a feature is enabled in the system running the binary
//! use one of the appropriate macro for the target:
//!
//! * `x86` and `x86_64`: [`is_x86_feature_detected`]
//! * `arm`: [`is_arm_feature_detected`]
//! * `aarch64`: [`is_aarch64_feature_detected`]
//! * `riscv`: [`is_riscv_feature_detected`]
//! * `mips`: [`is_mips_feature_detected`]
//! * `mips64`: [`is_mips64_feature_detected`]
//! * `powerpc`: [`is_powerpc_feature_detected`]
//! * `powerpc64`: [`is_powerpc64_feature_detected`]

#![unstable(feature = "stdsimd", issue = "27731")]
#![feature(staged_api, stdsimd, doc_cfg, allow_internal_unstable)]
#![deny(rust_2018_idioms)]
#![allow(clippy::shadow_reuse)]
#![deny(clippy::missing_inline_in_public_items)]
#![cfg_attr(test, allow(unused_imports))]
#![no_std]

#[cfg(test)]
#[macro_use]
extern crate std;

// rust-lang/rust#83888: removing `extern crate` gives an error that `vec_spare>
#[cfg_attr(feature = "std_detect_file_io", allow(unused_extern_crates))]
#[cfg(feature = "std_detect_file_io")]
extern crate alloc;

#[doc(hidden)]
#[unstable(feature = "stdsimd", issue = "27731")]
pub mod detect;
<|endoftext|>