<commit_before>extern crate libc;

use std;
use std::mem;
use libc::c_char;
use std::ffi::CStr;

use nom::*;

use rparser::*;

use tls_parser::tls::{TlsMessage,TlsMessageHandshake,TlsRecordType,TlsRawRecord,parse_tls_raw_record,parse_tls_record_with_header};
use tls_parser::tls_ciphers::*;
use tls_parser::tls_dh::*;
use tls_parser::tls_ec::*;
use tls_parser::tls_extensions::*;
use tls_parser::tls_sign_hash::*;
use tls_parser::tls_states::{TlsState,tls_state_transition};

// --------------------------------------------
// example implementation: TLS parser

#[repr(u32)]
pub enum TlsParserEvents {
    HeartbeatOverflow = 1,
    InvalidState = 2,

    RecordIncomplete = 3,
    RecordWithExtraBytes = 4,
    RecordOverflow = 5,
}

pub struct TlsParserState<'a> {
    pub o: Option<&'a[u8]>,

    events: Vec<u32>,

    compression: Option<u8>,
    cipher: Option<&'a TlsCipherSuite>,
    state: TlsState,

    kx_bits: Option<u32>,

    /// TCP segments defragmentation buffer
    tcp_buffer: Vec<u8>,

    /// Handshake defragmentation buffer
    buffer: Vec<u8>,

    has_signature_algorithms: bool,
}

impl<'a> TlsParserState<'a> {
    pub fn new(i: &'a[u8]) -> TlsParserState<'a> {
        TlsParserState{
            o:Some(i),
            events:Vec::new(),
            compression:None,
            cipher:None,
            state:TlsState::None,
            kx_bits: None,
            // capacity is the amount of space allocated, which means elements can be added
            // without reallocating the vector
            tcp_buffer:Vec::with_capacity(16384),
            buffer:Vec::with_capacity(16384),
            has_signature_algorithms:false,
        }
    }

    /// Message-level TLS parsing
    fn parse_message_level(self: &mut TlsParserState<'a>, msg: &TlsMessage) -> u32 {
        debug!("parse_message_level {:?}",msg);
        let mut status = R_STATUS_OK;
        if self.state == TlsState::ClientChangeCipherSpec {
            // Ignore records from now on, they are encrypted
            return status;
        };
        // update state machine
        match tls_state_transition(self.state, msg) {
            Ok(s)  => self.state = s,
            Err(_) => {
                self.state = TlsState::Invalid;
                self.events.push(TlsParserEvents::InvalidState as u32);
                status |= R_STATUS_EVENTS;
            },
        };
        debug!("TLS new state: {:?}",self.state);
        // extract variables
        match *msg {
            TlsMessage::Handshake(ref m) => {
                match *m {
                    TlsMessageHandshake::ClientHello(ref content) => {
                        let ext = parse_tls_extensions(content.ext.unwrap_or(b""));
                        match &ext {
                            &IResult::Done(_,ref l) => {
                                for extension in l {
                                    match *extension {
                                        TlsExtension::SignatureAlgorithms(_) => self.has_signature_algorithms = true,
                                        _ => (),
                                    }
                                }
                            },
                            e @ _ => error!("Could not parse extentions: {:?}",e),
                        };
                        debug!("ext {:?}", ext);
                    },
                    TlsMessageHandshake::ServerHello(ref content) => {
                        self.compression = Some(content.compression);
                        self.cipher = TlsCipherSuite::from_id(content.cipher);
                        match self.cipher {
                            Some(c) => {
                                debug!("Selected cipher: {:?}", c)
                            },
                            _ => warn!("Unknown cipher 0x{:x}", content.cipher),
                        };
                        let ext = parse_tls_extensions(content.ext.unwrap_or(b""));
                        debug!("extensions: {:?}", ext);
                    },
                    TlsMessageHandshake::Certificate(ref content) => {
                        debug!("cert chain length: {}",content.cert_chain.len());
                        for cert in &content.cert_chain {
                            debug!("cert: {:?}",cert);
                        }
                    },
                    TlsMessageHandshake::ServerKeyExchange(ref content) => {
                        // The SKE contains the chosen algorithm for the ephemeral key
                        match self.cipher {
                            None => (),
                            Some (c) => { self.kx_bits = rusticata_tls_get_kx_bits(c,content.parameters,self.has_signature_algorithms) },
                        }
                    },
                    _ => (),
                }
            },
            TlsMessage::Heartbeat(ref d) => {
                if d.payload_len as usize > d.payload.len() {
                    warn!("Heartbeat message with incorrect length {}. Heartbleed attempt ?",d.payload.len());
                    self.events.push(TlsParserEvents::HeartbeatOverflow as u32);
                    status |= R_STATUS_EVENTS;
                }
            },
            _ => (),
        }

        status
    }

    fn parse_record_level<'b>(self: &mut TlsParserState<'a>, r: &TlsRawRecord<'b>) -> u32 {
        let mut v : Vec<u8>;
        let mut status = R_STATUS_OK;

        debug!("parse_record_level {}",r.data.len());
        // debug!("{:?}",r.data);

        // only parse some message types
        match TlsRecordType::try_from_u8(r.hdr.record_type) {
            Ok(TlsRecordType::ChangeCipherSpec) => (),
            Ok(TlsRecordType::Handshake)        => (),
            _ => return status,
        }

        // Check if a record is being defragmented
        let record_buffer = match self.buffer.len() {
            0 => r.data,
            _ => {
                v = self.buffer.split_off(0);
                // sanity check vector length to avoid memory exhaustion
                // maximum length may be 2^24 (handshake message)
                if self.buffer.len() + r.data.len() > 16777216 {
                    self.events.push(TlsParserEvents::RecordOverflow as u32);
                    return R_STATUS_EVENTS;
                };
                v.extend_from_slice(r.data);
                v.as_slice()
            },
        };
        // do not parse if session is encrypted
        if self.state == TlsState::ClientChangeCipherSpec {
            return status;
        };
        // XXX record may be compressed
        //
        // XXX Parse one message at a time ?
        // Parse record contents as plaintext
        match parse_tls_record_with_header(record_buffer,r.hdr.clone()) {
            IResult::Done(rem2,ref msg_list) => {
                for msg in msg_list {
                    status |= self.parse_message_level(msg);
                };
                if rem2.len() > 0 {
                    warn!("extra bytes in TLS record: {:?}",rem2);
                    self.events.push(TlsParserEvents::RecordWithExtraBytes as u32);
                    status |= R_STATUS_EVENTS;
                };
            }
            IResult::Incomplete(_) => {
                debug!("Defragmentation required (TLS record)");
                // Record is fragmented
                self.buffer.extend_from_slice(r.data);
            },
            IResult::Error(e) => { warn!("parse_tls_record_with_header failed: {:?}",e); status |= R_STATUS_FAIL; },
        };

        status
    }

    pub fn parse_tcp_level<'b>(self: &mut TlsParserState<'a>, i: &'b[u8]) -> u32 {
        let mut v : Vec<u8>;
        let mut status = R_STATUS_OK;
        debug!("parse_tcp_level ({})",i.len());
        // debug!("{:?}",i);
        // Check if TCP data is being defragmented
        let tcp_buffer = match self.tcp_buffer.len() {
            0 => i,
            _ => {
                v = self.tcp_buffer.split_off(0);
                // sanity check vector length to avoid memory exhaustion
                // maximum length may be 2^24 (handshake message)
                if self.tcp_buffer.len() + i.len() > 16777216 {
                    self.events.push(TlsParserEvents::RecordOverflow as u32);
                    return R_STATUS_EVENTS;
                };
                v.extend_from_slice(i);
                v.as_slice()
            },
        };
        // debug!("tcp_buffer ({})",tcp_buffer.len());
        let mut cur_i = tcp_buffer;
        while cur_i.len() > 0 {
            match parse_tls_raw_record(cur_i) {
                IResult::Done(rem, ref r) => {
                    // debug!("rem: {:?}",rem);
                    cur_i = rem;
                    status |= self.parse_record_level(r);
                },
                IResult::Incomplete(_) => {
                    debug!("Fragmentation required (TCP level)");
                    self.tcp_buffer.extend_from_slice(cur_i);
                    break;
                },
                IResult::Error(e) => { warn!("Parsing failed: {:?}",e); break },
            }
        };
        status
    }
}

r_declare_state_new!(r_tls_state_new,TlsParserState,b"TLS parser");
r_declare_state_free!(r_tls_state_free,TlsParserState,{ () });

struct TlsParser;

impl<'a> RParser<TlsParserState<'a>> for TlsParser {
    fn new_state() -> TlsParserState<'a> {
        TlsParserState::new(b"TLS parser")
    }

    fn probe(i: &[u8]) -> bool {
        if i.len() <= 2 { return false; }
        // first byte is record type (between 0x14 and 0x17, 0x16 is handhake)
        // second is TLS version major (0x3)
        // third is TLS version minor (0x0 for SSLv3, 0x1 for TLSv1.0, etc.)
        match (i[0],i[1],i[2]) {
            (0x14...0x17,0x03,0...3) => true,
            _ => false,
        }
    }

    fn parse(parser_state: &mut TlsParserState, i: &[u8], direction: u8) -> u32 {
        debug!("[TLS->parse: direction={}, len={}]",direction,i.len());

        if i.len() == 0 {
            // Connection closed ?
            return R_STATUS_OK;
        };

        parser_state.parse_tcp_level(i)
    }
}

r_implement_probe!(r_tls_probe,TlsParser);
r_implement_parse!(r_tls_parse,TlsParser);

// --------------------------------------------

#[no_mangle]
pub extern fn r_tls_get_next_event(ptr: *mut libc::c_char) -> u32
// pub extern fn r_tls_get_next_event<'a>(this: &mut TlsParserState<'a>) -> u32
{
    assert!(!ptr.is_null());
    let this: &mut TlsParserState = unsafe { mem::transmute(ptr) };
    match this.events.pop() {
        None     => 0xffffffff,
        Some(ev) => ev,
    }
}

#[no_mangle]
// pub extern fn rusticata_tls_get_cipher(ptr: *mut libc::c_char) -> u32
// or
pub extern fn rusticata_tls_get_cipher<'a>(this: &TlsParserState<'a>) -> u32
// but this gives a warning:
// warning: generic functions must be mangled, #[warn(no_mangle_generic_items)] on by default
{
    // let this: &Box<TlsParserState> = unsafe { mem::transmute(ptr) };
    match this.cipher {
        None    => 0,
        Some(c) => c.id.into(),
    }
}

#[no_mangle]
pub extern fn rusticata_tls_get_compression<'a>(this: &TlsParserState<'a>) -> u32
{
    this.compression.unwrap_or(0) as u32
}

#[no_mangle]
pub extern fn rusticata_tls_get_dh_key_bits<'a>(this: &TlsParserState<'a>) -> u32
{
    this.kx_bits.unwrap_or(0) as u32
}

#[no_mangle]
pub extern fn rusticata_tls_cipher_of_string(value: *const c_char) -> u32
{
    let c_str = unsafe { CStr::from_ptr(value) };
    let s = c_str.to_str().unwrap();
    match TlsCipherSuite::from_name(s) {
        Some(c) => c.id as u32,
        None    => 0,
    }
}

fn rusticata_tls_get_kx_bits(cipher: &TlsCipherSuite, parameters: &[u8], extended: bool) -> Option<u32> {
    match cipher.kx {
        TlsCipherKx::Ecdhe |
        TlsCipherKx::Ecdh    => {
            // Signed ECDH params
            match parse_content_and_signature(parameters,parse_ecdh_params,extended) {
                IResult::Done(_,ref parsed) => {
                    debug!("ECDHE Parameters: {:?}",parsed);
                    info!("Temp key: using cipher {:?}",parsed.0.curve_params);
                    match &parsed.0.curve_params.params_content {
                        &ECParametersContent::NamedCurve(curve_id) => {
                            match named_curve_of_u16(curve_id) {
                                None => (),
                                Some(named_curve) => {
                                    let key_bits = named_curve.key_bits().unwrap_or(0);
                                    debug!("NamedCurve: {:?}, key={:?} bits",named_curve,key_bits);
                                    return Some(key_bits as u32);
                                },
                            }
                        },
                        c @ _ => info!("Request for key_bits of unknown curve {:?}",c),
                    }
                },
                e @ _ => error!("Could not parse ECDHE parameters {:?}",e),
            };
            ()
        },
        TlsCipherKx::Dhe => {
            // Signed DH params
            match parse_content_and_signature(parameters,parse_dh_params,extended) {
                IResult::Done(_,ref parsed) => {
                    debug!("DHE Parameters: {:?}",parsed);
                    info!("Temp key: using DHE size_p={:?} bits",parsed.0.dh_p.len() * 8);
                    return Some(parsed.0.dh_p.len() as u32);
                },
                e @ _ => error!("Could not parse DHE parameters {:?}",e),
            };
            ()
        },
        TlsCipherKx::Dh => {
            // Anonymous DH params
            match parse_dh_params(parameters) {
                IResult::Done(_,ref parsed) => {
                    debug!("ADH Parameters: {:?}",parsed);
                    info!("Temp key: using ADH size_p={:?} bits",parsed.dh_p.len() * 8);
                    return Some(parsed.dh_p.len() as u32);
                },
                e @ _ => error!("Could not parse ADH parameters {:?}",e),
            };
            ()
        },
        ref kx @ _ => debug!("unhandled KX algorithm: {:?}",kx),
    };
    None
}
<commit_msg>Export functions to get CipherSuites parameters<commit_after>extern crate libc;

use std;
use std::mem;
use libc::c_char;
use std::ffi::CStr;

use nom::*;

use rparser::*;

use tls_parser::tls::{TlsMessage,TlsMessageHandshake,TlsRecordType,TlsRawRecord,parse_tls_raw_record,parse_tls_record_with_header};
use tls_parser::tls_ciphers::*;
use tls_parser::tls_dh::*;
use tls_parser::tls_ec::*;
use tls_parser::tls_extensions::*;
use tls_parser::tls_sign_hash::*;
use tls_parser::tls_states::{TlsState,tls_state_transition};

// --------------------------------------------
// example implementation: TLS parser

#[repr(u32)]
pub enum TlsParserEvents {
    HeartbeatOverflow = 1,
    InvalidState = 2,

    RecordIncomplete = 3,
    RecordWithExtraBytes = 4,
    RecordOverflow = 5,
}

pub struct TlsParserState<'a> {
    pub o: Option<&'a[u8]>,

    events: Vec<u32>,

    compression: Option<u8>,
    cipher: Option<&'a TlsCipherSuite>,
    state: TlsState,

    kx_bits: Option<u32>,

    /// TCP segments defragmentation buffer
    tcp_buffer: Vec<u8>,

    /// Handshake defragmentation buffer
    buffer: Vec<u8>,

    has_signature_algorithms: bool,
}

impl<'a> TlsParserState<'a> {
    pub fn new(i: &'a[u8]) -> TlsParserState<'a> {
        TlsParserState{
            o:Some(i),
            events:Vec::new(),
            compression:None,
            cipher:None,
            state:TlsState::None,
            kx_bits: None,
            // capacity is the amount of space allocated, which means elements can be added
            // without reallocating the vector
            tcp_buffer:Vec::with_capacity(16384),
            buffer:Vec::with_capacity(16384),
            has_signature_algorithms:false,
        }
    }

    /// Message-level TLS parsing
    fn parse_message_level(self: &mut TlsParserState<'a>, msg: &TlsMessage) -> u32 {
        debug!("parse_message_level {:?}",msg);
        let mut status = R_STATUS_OK;
        if self.state == TlsState::ClientChangeCipherSpec {
            // Ignore records from now on, they are encrypted
            return status;
        };
        // update state machine
        match tls_state_transition(self.state, msg) {
            Ok(s)  => self.state = s,
            Err(_) => {
                self.state = TlsState::Invalid;
                self.events.push(TlsParserEvents::InvalidState as u32);
                status |= R_STATUS_EVENTS;
            },
        };
        debug!("TLS new state: {:?}",self.state);
        // extract variables
        match *msg {
            TlsMessage::Handshake(ref m) => {
                match *m {
                    TlsMessageHandshake::ClientHello(ref content) => {
                        let ext = parse_tls_extensions(content.ext.unwrap_or(b""));
                        match &ext {
                            &IResult::Done(_,ref l) => {
                                for extension in l {
                                    match *extension {
                                        TlsExtension::SignatureAlgorithms(_) => self.has_signature_algorithms = true,
                                        _ => (),
                                    }
                                }
                            },
                            e @ _ => error!("Could not parse extentions: {:?}",e),
                        };
                        debug!("ext {:?}", ext);
                    },
                    TlsMessageHandshake::ServerHello(ref content) => {
                        self.compression = Some(content.compression);
                        self.cipher = TlsCipherSuite::from_id(content.cipher);
                        match self.cipher {
                            Some(c) => {
                                debug!("Selected cipher: {:?}", c)
                            },
                            _ => warn!("Unknown cipher 0x{:x}", content.cipher),
                        };
                        let ext = parse_tls_extensions(content.ext.unwrap_or(b""));
                        debug!("extensions: {:?}", ext);
                    },
                    TlsMessageHandshake::Certificate(ref content) => {
                        debug!("cert chain length: {}",content.cert_chain.len());
                        for cert in &content.cert_chain {
                            debug!("cert: {:?}",cert);
                        }
                    },
                    TlsMessageHandshake::ServerKeyExchange(ref content) => {
                        // The SKE contains the chosen algorithm for the ephemeral key
                        match self.cipher {
                            None => (),
                            Some (c) => { self.kx_bits = rusticata_tls_get_kx_bits(c,content.parameters,self.has_signature_algorithms) },
                        }
                    },
                    _ => (),
                }
            },
            TlsMessage::Heartbeat(ref d) => {
                if d.payload_len as usize > d.payload.len() {
                    warn!("Heartbeat message with incorrect length {}. Heartbleed attempt ?",d.payload.len());
                    self.events.push(TlsParserEvents::HeartbeatOverflow as u32);
                    status |= R_STATUS_EVENTS;
                }
            },
            _ => (),
        }

        status
    }

    fn parse_record_level<'b>(self: &mut TlsParserState<'a>, r: &TlsRawRecord<'b>) -> u32 {
        let mut v : Vec<u8>;
        let mut status = R_STATUS_OK;

        debug!("parse_record_level {}",r.data.len());
        // debug!("{:?}",r.data);

        // only parse some message types
        match TlsRecordType::try_from_u8(r.hdr.record_type) {
            Ok(TlsRecordType::ChangeCipherSpec) => (),
            Ok(TlsRecordType::Handshake)        => (),
            _ => return status,
        }

        // Check if a record is being defragmented
        let record_buffer = match self.buffer.len() {
            0 => r.data,
            _ => {
                v = self.buffer.split_off(0);
                // sanity check vector length to avoid memory exhaustion
                // maximum length may be 2^24 (handshake message)
                if self.buffer.len() + r.data.len() > 16777216 {
                    self.events.push(TlsParserEvents::RecordOverflow as u32);
                    return R_STATUS_EVENTS;
                };
                v.extend_from_slice(r.data);
                v.as_slice()
            },
        };
        // do not parse if session is encrypted
        if self.state == TlsState::ClientChangeCipherSpec {
            return status;
        };
        // XXX record may be compressed
        //
        // XXX Parse one message at a time ?
        // Parse record contents as plaintext
        match parse_tls_record_with_header(record_buffer,r.hdr.clone()) {
            IResult::Done(rem2,ref msg_list) => {
                for msg in msg_list {
                    status |= self.parse_message_level(msg);
                };
                if rem2.len() > 0 {
                    warn!("extra bytes in TLS record: {:?}",rem2);
                    self.events.push(TlsParserEvents::RecordWithExtraBytes as u32);
                    status |= R_STATUS_EVENTS;
                };
            }
            IResult::Incomplete(_) => {
                debug!("Defragmentation required (TLS record)");
                // Record is fragmented
                self.buffer.extend_from_slice(r.data);
            },
            IResult::Error(e) => { warn!("parse_tls_record_with_header failed: {:?}",e); status |= R_STATUS_FAIL; },
        };

        status
    }

    pub fn parse_tcp_level<'b>(self: &mut TlsParserState<'a>, i: &'b[u8]) -> u32 {
        let mut v : Vec<u8>;
        let mut status = R_STATUS_OK;
        debug!("parse_tcp_level ({})",i.len());
        // debug!("{:?}",i);
        // Check if TCP data is being defragmented
        let tcp_buffer = match self.tcp_buffer.len() {
            0 => i,
            _ => {
                v = self.tcp_buffer.split_off(0);
                // sanity check vector length to avoid memory exhaustion
                // maximum length may be 2^24 (handshake message)
                if self.tcp_buffer.len() + i.len() > 16777216 {
                    self.events.push(TlsParserEvents::RecordOverflow as u32);
                    return R_STATUS_EVENTS;
                };
                v.extend_from_slice(i);
                v.as_slice()
            },
        };
        // debug!("tcp_buffer ({})",tcp_buffer.len());
        let mut cur_i = tcp_buffer;
        while cur_i.len() > 0 {
            match parse_tls_raw_record(cur_i) {
                IResult::Done(rem, ref r) => {
                    // debug!("rem: {:?}",rem);
                    cur_i = rem;
                    status |= self.parse_record_level(r);
                },
                IResult::Incomplete(_) => {
                    debug!("Fragmentation required (TCP level)");
                    self.tcp_buffer.extend_from_slice(cur_i);
                    break;
                },
                IResult::Error(e) => { warn!("Parsing failed: {:?}",e); break },
            }
        };
        status
    }
}

r_declare_state_new!(r_tls_state_new,TlsParserState,b"TLS parser");
r_declare_state_free!(r_tls_state_free,TlsParserState,{ () });

struct TlsParser;

impl<'a> RParser<TlsParserState<'a>> for TlsParser {
    fn new_state() -> TlsParserState<'a> {
        TlsParserState::new(b"TLS parser")
    }

    fn probe(i: &[u8]) -> bool {
        if i.len() <= 2 { return false; }
        // first byte is record type (between 0x14 and 0x17, 0x16 is handhake)
        // second is TLS version major (0x3)
        // third is TLS version minor (0x0 for SSLv3, 0x1 for TLSv1.0, etc.)
        match (i[0],i[1],i[2]) {
            (0x14...0x17,0x03,0...3) => true,
            _ => false,
        }
    }

    fn parse(parser_state: &mut TlsParserState, i: &[u8], direction: u8) -> u32 {
        debug!("[TLS->parse: direction={}, len={}]",direction,i.len());

        if i.len() == 0 {
            // Connection closed ?
            return R_STATUS_OK;
        };

        parser_state.parse_tcp_level(i)
    }
}

r_implement_probe!(r_tls_probe,TlsParser);
r_implement_parse!(r_tls_parse,TlsParser);

// --------------------------------------------

#[no_mangle]
pub extern fn r_tls_get_next_event(ptr: *mut libc::c_char) -> u32
// pub extern fn r_tls_get_next_event<'a>(this: &mut TlsParserState<'a>) -> u32
{
    assert!(!ptr.is_null());
    let this: &mut TlsParserState = unsafe { mem::transmute(ptr) };
    match this.events.pop() {
        None     => 0xffffffff,
        Some(ev) => ev,
    }
}

#[no_mangle]
// pub extern fn rusticata_tls_get_cipher(ptr: *mut libc::c_char) -> u32
// or
pub extern fn rusticata_tls_get_cipher<'a>(this: &TlsParserState<'a>) -> u32
// but this gives a warning:
// warning: generic functions must be mangled, #[warn(no_mangle_generic_items)] on by default
{
    // let this: &Box<TlsParserState> = unsafe { mem::transmute(ptr) };
    match this.cipher {
        None    => 0,
        Some(c) => c.id.into(),
    }
}

#[no_mangle]
pub extern fn rusticata_tls_get_compression<'a>(this: &TlsParserState<'a>) -> u32
{
    this.compression.unwrap_or(0) as u32
}

#[no_mangle]
pub extern fn rusticata_tls_get_dh_key_bits<'a>(this: &TlsParserState<'a>) -> u32
{
    this.kx_bits.unwrap_or(0) as u32
}

#[no_mangle]
pub extern fn rusticata_tls_cipher_of_string(value: *const c_char) -> u32
{
    let c_str = unsafe { CStr::from_ptr(value) };
    let s = c_str.to_str().unwrap();
    match TlsCipherSuite::from_name(s) {
        Some(c) => c.id as u32,
        None    => 0,
    }
}

#[no_mangle]
pub extern fn rusticata_tls_kx_of_cipher(id: u16) -> u32
{
    match TlsCipherSuite::from_id(id) {
        Some(c) => c.kx.clone() as u32,
        None    => 0,
    }
}

#[no_mangle]
pub extern fn rusticata_tls_au_of_cipher(id: u16) -> u32
{
    match TlsCipherSuite::from_id(id) {
        Some(c) => c.au.clone() as u32,
        None    => 0,
    }
}

#[no_mangle]
pub extern fn rusticata_tls_enc_of_cipher(id: u16) -> u32
{
    match TlsCipherSuite::from_id(id) {
        Some(c) => c.enc.clone() as u32,
        None    => 0,
    }
}

#[no_mangle]
pub extern fn rusticata_tls_encmode_of_cipher(id: u16) -> u32
{
    match TlsCipherSuite::from_id(id) {
        Some(c) => c.enc_mode.clone() as u32,
        None    => 0,
    }
}

#[no_mangle]
pub extern fn rusticata_tls_mac_of_cipher(id: u16) -> u32
{
    match TlsCipherSuite::from_id(id) {
        Some(c) => c.mac.clone() as u32,
        None    => 0,
    }
}

fn rusticata_tls_get_kx_bits(cipher: &TlsCipherSuite, parameters: &[u8], extended: bool) -> Option<u32> {
    match cipher.kx {
        TlsCipherKx::Ecdhe |
        TlsCipherKx::Ecdh    => {
            // Signed ECDH params
            match parse_content_and_signature(parameters,parse_ecdh_params,extended) {
                IResult::Done(_,ref parsed) => {
                    debug!("ECDHE Parameters: {:?}",parsed);
                    info!("Temp key: using cipher {:?}",parsed.0.curve_params);
                    match &parsed.0.curve_params.params_content {
                        &ECParametersContent::NamedCurve(curve_id) => {
                            match named_curve_of_u16(curve_id) {
                                None => (),
                                Some(named_curve) => {
                                    let key_bits = named_curve.key_bits().unwrap_or(0);
                                    debug!("NamedCurve: {:?}, key={:?} bits",named_curve,key_bits);
                                    return Some(key_bits as u32);
                                },
                            }
                        },
                        c @ _ => info!("Request for key_bits of unknown curve {:?}",c),
                    }
                },
                e @ _ => error!("Could not parse ECDHE parameters {:?}",e),
            };
            ()
        },
        TlsCipherKx::Dhe => {
            // Signed DH params
            match parse_content_and_signature(parameters,parse_dh_params,extended) {
                IResult::Done(_,ref parsed) => {
                    debug!("DHE Parameters: {:?}",parsed);
                    info!("Temp key: using DHE size_p={:?} bits",parsed.0.dh_p.len() * 8);
                    return Some(parsed.0.dh_p.len() as u32);
                },
                e @ _ => error!("Could not parse DHE parameters {:?}",e),
            };
            ()
        },
        TlsCipherKx::Dh => {
            // Anonymous DH params
            match parse_dh_params(parameters) {
                IResult::Done(_,ref parsed) => {
                    debug!("ADH Parameters: {:?}",parsed);
                    info!("Temp key: using ADH size_p={:?} bits",parsed.dh_p.len() * 8);
                    return Some(parsed.dh_p.len() as u32);
                },
                e @ _ => error!("Could not parse ADH parameters {:?}",e),
            };
            ()
        },
        ref kx @ _ => debug!("unhandled KX algorithm: {:?}",kx),
    };
    None
}
<|endoftext|>


<commit_before>import std::cmp::FuzzyEq;
import cmp::Ord;
import num::Num;
import float::sqrt;
import to_str::ToStr;

// TODO: Unittests! I've probably made lots of mistakes...

//
//  N-dimensional Vector
//
trait Vector<T:Num Ord FuzzyEq> {
    pure fn dim() -> uint;

    pure fn index(&&index:uint) -> T;

    pure fn neg() -> self;

    pure fn add_f(&&value:T) -> self;
    pure fn sub_f(&&value:T) -> self;
    pure fn mul_f(&&value:T) -> self;
    pure fn div_f(&&value:T) -> self;

    pure fn add_v(&&other: self) -> self;
    pure fn sub_v(&&other: self) -> self;

    pure fn exact_eq(&&other:self) -> bool;
    pure fn fuzzy_eq(&&other:self) -> bool;
    pure fn eq(&&other:self) -> bool;

    pure fn dot(&&other: self) -> T;

    pure fn magnitude2() -> T;
    pure fn magnitude() -> T;
    pure fn normalize() -> self;

    // pure fn lerp(&&other:self, &&value:T) -> self;
    // pure fn abs(&&other:self) -> self;
    // pure fn min(&&other:self) -> self;
    // pure fn max(&&other:self) -> self;
}

//
//  2-Dimensional Vector
//
trait Vector2<T:Num Ord FuzzyEq> {
    // This is where I wish rust had properties ;)
    pure fn x() -> T;
    pure fn y() -> T;
}

//
//  3-Dimensional Vector
//
trait Vector3<T:Num Ord FuzzyEq> {
    pure fn x() -> T;
    pure fn y() -> T;
    pure fn z() -> T;

    fn cross(&&other:self) -> self;
}

//
//  4-Dimensional Vector
//
trait Vector4<T:Num Ord FuzzyEq> {
    pure fn x() -> T;
    pure fn y() -> T;
    pure fn z() -> T;
    pure fn w() -> T;
}

//
//  Vec2 struct definition
//
struct vec2 { data:[float * 2] }

//
//  Vec2 Constructor
//
#[inline(always)]
pure fn vec2(x:float, y:float) -> vec2 {
    vec2 { data: [ x, y ] }
}

//
//  Constants
//
#[inline(always)] pure fn vec2_zero()     -> vec2 { vec2 (0f, 0f) }
#[inline(always)] pure fn vec2_unit_x()   -> vec2 { vec2 (1f, 0f) }
#[inline(always)] pure fn vec2_unit_y()   -> vec2 { vec2 (0f, 1f) }
#[inline(always)] pure fn vec2_identity() -> vec2 { vec2 (1f, 1f) }

//
//  Vector2 Implementation
//
impl vec2: Vector2<float> {
    #[inline(always)] pure fn x() -> float { self.data[0] }
    #[inline(always)] pure fn y() -> float { self.data[1] }
}

//
//  Vector Implementation
//
impl vec2: Vector<float> {
    #[inline(always)]
    pure fn dim() -> uint { 2 }

    #[inline(always)]
    pure fn index(&&i: uint) -> float {
        self.data[i]
    }

    #[inline(always)]
    pure fn neg() -> vec2 {
        vec2(-self[0], -self[1])
    }

    #[inline(always)]
    pure fn add_f(&&value:float) -> vec2 {
        vec2(self[0] + value,
             self[1] + value)
    }

    #[inline(always)]
    pure fn sub_f(&&value:float) -> vec2 {
        vec2(self[0] - value,
             self[1] - value)
    }

    #[inline(always)]
    pure fn mul_f(&&value:float) -> vec2 {
        vec2(self[0] * value,
             self[1] * value)
    }

    #[inline(always)]
    pure fn div_f(&&value:float) -> vec2 {
        vec2(self[0] / value,
             self[1] / value)
    }

    #[inline(always)]
    pure fn add_v(&&other: vec2) -> vec2{
        vec2(self[0] + other[0],
             self[1] + other[1])
    }

    #[inline(always)]
    pure fn sub_v(&&other: vec2) -> vec2{
        vec2(self[0] - other[0],
             self[1] - other[1])
    }

    #[inline(always)]
    pure fn exact_eq(&&other:vec2) -> bool {
        self[0] == other[0] &&
        self[1] == other[1]
    }

    #[inline(always)]
    pure fn fuzzy_eq(&&other: vec2) -> bool {
        self[0].fuzzy_eq(&other[0]) &&
        self[1].fuzzy_eq(&other[1])
    }

    #[inline(always)]
    pure fn eq(&&other:vec2) -> bool {
        self.fuzzy_eq(other)
    }

    #[inline(always)]
    pure fn dot(&&other: vec2) -> float {
        self[0] * other[0] +
        self[1] * other[1]
    }

    #[inline(always)]
    pure fn magnitude2() -> float {
        self[0] * self[0] +
        self[1] * self[1]
    }

    #[inline(always)]
    pure fn magnitude() -> float {
        sqrt(self.magnitude2())
    }

    #[inline(always)]
    pure fn normalize() -> vec2 {
        let n = 1f / self.magnitude();
        return self.mul_f(n);
    }
}

//
//  Convert To String
//
impl vec2: ToStr {
    fn to_str() -> ~str {
        fmt!("vec2[ %f, %f ]", self[0], self[1])
    }
}

//
//  Vec3 struct definition
//
struct vec3 { data:[float * 3] }

//
//  Constants
//
#[inline(always)] pure fn vec3_zero()     -> vec3 { vec3(0f, 0f, 0f) }
#[inline(always)] pure fn vec3_unit_x()   -> vec3 { vec3(1f, 0f, 0f) }
#[inline(always)] pure fn vec3_unit_y()   -> vec3 { vec3(0f, 1f, 0f) }
#[inline(always)] pure fn vec3_unit_z()   -> vec3 { vec3(0f, 0f, 1f) }
#[inline(always)] pure fn vec3_identity() -> vec3 { vec3(1f, 1f, 1f) }

//
//  Vec3 Constructor
//
#[inline(always)]
pure fn vec3(x:float, y:float, z:float) -> vec3 {
    vec3 { data: [ x, y, z ] }
}

//
//  Vector3 Implementation
//
impl vec3: Vector3<float> {
    #[inline(always)] pure fn x() -> float { self.data[0] }
    #[inline(always)] pure fn y() -> float { self.data[1] }
    #[inline(always)] pure fn z() -> float { self.data[2] }

    #[inline(always)]
    fn cross(&&other:vec3) -> vec3 {
        vec3((self[1] * other[2]) - (self[2] * other[1]),
             (self[2] * other[0]) - (self[0] * other[2]),
             (self[0] * other[1]) - (self[1] * other[0]))
    }
}

//
//  Vector Implementation
//
impl vec3: Vector<float> {
    #[inline(always)]
    pure fn dim() -> uint { 3 }

    #[inline(always)]
    pure fn index(&&i: uint) -> float {
        self.data[i]
    }

    #[inline(always)]
    pure fn neg() -> vec3 {
        vec3(-self[0], -self[1], -self[2])
    }

    #[inline(always)]
    pure fn add_f(&&value:float) -> vec3 {
        vec3(self[0] + value,
             self[1] + value,
             self[2] + value)
    }

    #[inline(always)]
    pure fn sub_f(&&value:float) -> vec3 {
        vec3(self[0] - value,
             self[1] - value,
             self[2] - value)
    }

    #[inline(always)]
    pure fn mul_f(&&value:float) -> vec3 {
        vec3(self[0] * value,
             self[1] * value,
             self[2] * value)
    }

    #[inline(always)]
    pure fn div_f(&&value:float) -> vec3 {
        vec3(self[0] / value,
             self[1] / value,
             self[2] / value)
    }

    #[inline(always)]
    pure fn add_v(&&other: vec3) -> vec3{
        vec3(self[0] + other[0],
             self[1] + other[1],
             self[2] + other[2])
    }

    #[inline(always)]
    pure fn sub_v(&&other: vec3) -> vec3{
        vec3(self[0] - other[0],
             self[1] - other[1],
             self[2] - other[2])
    }

    #[inline(always)]
    pure fn exact_eq(&&other:vec3) -> bool {
        self[0] == other[0] &&
        self[1] == other[1] &&
        self[2] == other[2]
    }

    #[inline(always)]
    pure fn fuzzy_eq(&&other: vec3) -> bool {
        self[0].fuzzy_eq(&other[0]) &&
        self[1].fuzzy_eq(&other[1]) &&
        self[2].fuzzy_eq(&other[2])
    }

    #[inline(always)]
    pure fn eq(&&other:vec3) -> bool {
        self.fuzzy_eq(other)
    }

    #[inline(always)]
    pure fn dot(&&other: vec3) -> float {
        self[0] * other[0] +
        self[1] * other[1] +
        self[2] * other[2]
    }

    #[inline(always)]
    pure fn magnitude2() -> float {
        self[0] * self[0] +
        self[1] * self[1] +
        self[2] * self[2]
    }

    #[inline(always)]
    pure fn magnitude() -> float {
        sqrt(self.magnitude2())
    }

    #[inline(always)]
    pure fn normalize() -> vec3 {
        let n = 1f / self.magnitude();
        return self.mul_f(n);
    }
}

//
//  Convert To String
//
impl vec3: ToStr {
    fn to_str() -> ~str {
        fmt!("vec3[ %f, %f, %f ]", self[0], self[1], self[2])
    }
}

//
//  Vec4 struct definition
//
struct vec4 { data:[float * 4] }

//
//  Constants
//
#[inline(always)] pure fn vec4_zero()     -> vec4 { vec4(0f, 0f, 0f, 0f) }
#[inline(always)] pure fn vec4_unit_x()   -> vec4 { vec4(1f, 0f, 0f, 0f) }
#[inline(always)] pure fn vec4_unit_y()   -> vec4 { vec4(0f, 1f, 0f, 0f) }
#[inline(always)] pure fn vec4_unit_z()   -> vec4 { vec4(0f, 0f, 1f, 0f) }
#[inline(always)] pure fn vec4_unit_w()   -> vec4 { vec4(0f, 0f, 0f, 1f) }
#[inline(always)] pure fn vec4_identity() -> vec4 { vec4(1f, 1f, 1f, 1f) }

//
//  Vec4 Constructor
//
#[inline(always)]
pure fn vec4(x:float, y:float, z:float, w:float) -> vec4 {
    vec4 { data: [ x, y, z, w ] }
}

//
//  Vector4 Implementation
//
impl vec4: Vector4<float> {
    #[inline(always)] pure fn x() -> float { self.data[0] }
    #[inline(always)] pure fn y() -> float { self.data[1] }
    #[inline(always)] pure fn z() -> float { self.data[2] }
    #[inline(always)] pure fn w() -> float { self.data[3] }
}

//
//  Vector Implementation
//
impl vec4: Vector<float> {
    #[inline(always)]
    pure fn dim() -> uint { 4 }

    #[inline(always)]
    pure fn index(&&i: uint) -> float {
        self.data[i]
    }

    #[inline(always)]
    pure fn neg() -> vec4 {
        vec4(-self[0], -self[1], -self[2], -self[3])
    }

    #[inline(always)]
    pure fn add_f(&&value:float) -> vec4 {
        vec4(self[0] + value,
             self[1] + value,
             self[2] + value,
             self[3] + value)
    }

    #[inline(always)]
    pure fn sub_f(&&value:float) -> vec4 {
        vec4(self[0] - value,
             self[1] - value,
             self[2] - value,
             self[3] - value)
    }

    #[inline(always)]
    pure fn mul_f(&&value:float) -> vec4 {
        vec4(self[0] * value,
             self[1] * value,
             self[2] * value,
             self[3] * value)
    }

    #[inline(always)]
    pure fn div_f(&&value:float) -> vec4 {
        vec4(self[0] / value,
             self[1] / value,
             self[2] / value,
             self[3] / value)
    }

    #[inline(always)]
    pure fn add_v(&&other: vec4) -> vec4{
        vec4(self[0] + other[0],
             self[1] + other[1],
             self[2] + other[2],
             self[3] + other[3])
    }

    #[inline(always)]
    pure fn sub_v(&&other: vec4) -> vec4{
        vec4(self[0] - other[0],
             self[1] - other[1],
             self[2] - other[2],
             self[3] - other[3])
    }

    #[inline(always)]
    pure fn exact_eq(&&other:vec4) -> bool {
        self[0] == other[0] &&
        self[1] == other[1] &&
        self[2] == other[2] &&
        self[3] == other[3]
    }

    #[inline(always)]
    pure fn fuzzy_eq(&&other: vec4) -> bool {
        self[0].fuzzy_eq(&other[0]) &&
        self[1].fuzzy_eq(&other[1]) &&
        self[2].fuzzy_eq(&other[2]) &&
        self[3].fuzzy_eq(&other[3])
    }

    #[inline(always)]
    pure fn eq(&&other:vec4) -> bool {
        self.fuzzy_eq(other)
    }

    #[inline(always)]
    pure fn dot(&&other:vec4) -> float {
        self[0] * other[0] +
        self[1] * other[1] +
        self[2] * other[2] +
        self[3] * other[3]
    }

    #[inline(always)]
    pure fn magnitude2() -> float {
        self[0] * self[0] +
        self[1] * self[1] +
        self[2] * self[2] +
        self[3] + self[3]
    }

    #[inline(always)]
    pure fn magnitude() -> float {
        sqrt(self.magnitude2())
    }

    #[inline(always)]
    pure fn normalize() -> vec4 {
        let n = 1f / self.magnitude();
        return self.mul_f(n);
    }
}

//
//  Convert To String
//
impl vec4: ToStr {
    fn to_str() -> ~str {
        fmt!("vec4[ %f, %f, %f, %f ]", self[0], self[1], self[2], self[3])
    }
}<commit_msg>OCD - move dot product methods<commit_after>import std::cmp::FuzzyEq;
import cmp::Ord;
import num::Num;
import float::sqrt;
import to_str::ToStr;

// TODO: Unittests! I've probably made lots of mistakes...

//
//  N-dimensional Vector
//
trait Vector<T:Num Ord FuzzyEq> {
    pure fn dim() -> uint;

    pure fn index(&&index:uint) -> T;

    pure fn neg() -> self;

    pure fn add_f(&&value:T) -> self;
    pure fn sub_f(&&value:T) -> self;
    pure fn mul_f(&&value:T) -> self;
    pure fn div_f(&&value:T) -> self;

    pure fn add_v(&&other: self) -> self;
    pure fn sub_v(&&other: self) -> self;

    pure fn dot(&&other: self) -> T;

    pure fn exact_eq(&&other:self) -> bool;
    pure fn fuzzy_eq(&&other:self) -> bool;
    pure fn eq(&&other:self) -> bool;

    pure fn magnitude2() -> T;
    pure fn magnitude() -> T;
    pure fn normalize() -> self;

    // pure fn lerp(&&other:self, &&value:T) -> self;
    // pure fn abs(&&other:self) -> self;
    // pure fn min(&&other:self) -> self;
    // pure fn max(&&other:self) -> self;
}

//
//  2-Dimensional Vector
//
trait Vector2<T:Num Ord FuzzyEq> {
    // This is where I wish rust had properties ;)
    pure fn x() -> T;
    pure fn y() -> T;
}

//
//  3-Dimensional Vector
//
trait Vector3<T:Num Ord FuzzyEq> {
    pure fn x() -> T;
    pure fn y() -> T;
    pure fn z() -> T;

    fn cross(&&other:self) -> self;
}

//
//  4-Dimensional Vector
//
trait Vector4<T:Num Ord FuzzyEq> {
    pure fn x() -> T;
    pure fn y() -> T;
    pure fn z() -> T;
    pure fn w() -> T;
}

//
//  Vec2 struct definition
//
struct vec2 { data:[float * 2] }

//
//  Vec2 Constructor
//
#[inline(always)]
pure fn vec2(x:float, y:float) -> vec2 {
    vec2 { data: [ x, y ] }
}

//
//  Constants
//
#[inline(always)] pure fn vec2_zero()     -> vec2 { vec2 (0f, 0f) }
#[inline(always)] pure fn vec2_unit_x()   -> vec2 { vec2 (1f, 0f) }
#[inline(always)] pure fn vec2_unit_y()   -> vec2 { vec2 (0f, 1f) }
#[inline(always)] pure fn vec2_identity() -> vec2 { vec2 (1f, 1f) }

//
//  Vector2 Implementation
//
impl vec2: Vector2<float> {
    #[inline(always)] pure fn x() -> float { self.data[0] }
    #[inline(always)] pure fn y() -> float { self.data[1] }
}

//
//  Vector Implementation
//
impl vec2: Vector<float> {
    #[inline(always)]
    pure fn dim() -> uint { 2 }

    #[inline(always)]
    pure fn index(&&i: uint) -> float {
        self.data[i]
    }

    #[inline(always)]
    pure fn neg() -> vec2 {
        vec2(-self[0], -self[1])
    }

    #[inline(always)]
    pure fn add_f(&&value:float) -> vec2 {
        vec2(self[0] + value,
             self[1] + value)
    }

    #[inline(always)]
    pure fn sub_f(&&value:float) -> vec2 {
        vec2(self[0] - value,
             self[1] - value)
    }

    #[inline(always)]
    pure fn mul_f(&&value:float) -> vec2 {
        vec2(self[0] * value,
             self[1] * value)
    }

    #[inline(always)]
    pure fn div_f(&&value:float) -> vec2 {
        vec2(self[0] / value,
             self[1] / value)
    }

    #[inline(always)]
    pure fn add_v(&&other: vec2) -> vec2{
        vec2(self[0] + other[0],
             self[1] + other[1])
    }

    #[inline(always)]
    pure fn sub_v(&&other: vec2) -> vec2{
        vec2(self[0] - other[0],
             self[1] - other[1])
    }

    #[inline(always)]
    pure fn dot(&&other: vec2) -> float {
        self[0] * other[0] +
        self[1] * other[1]
    }

    #[inline(always)]
    pure fn exact_eq(&&other:vec2) -> bool {
        self[0] == other[0] &&
        self[1] == other[1]
    }

    #[inline(always)]
    pure fn fuzzy_eq(&&other: vec2) -> bool {
        self[0].fuzzy_eq(&other[0]) &&
        self[1].fuzzy_eq(&other[1])
    }

    #[inline(always)]
    pure fn eq(&&other:vec2) -> bool {
        self.fuzzy_eq(other)
    }

    #[inline(always)]
    pure fn magnitude2() -> float {
        self[0] * self[0] +
        self[1] * self[1]
    }

    #[inline(always)]
    pure fn magnitude() -> float {
        sqrt(self.magnitude2())
    }

    #[inline(always)]
    pure fn normalize() -> vec2 {
        let n = 1f / self.magnitude();
        return self.mul_f(n);
    }
}

//
//  Convert To String
//
impl vec2: ToStr {
    fn to_str() -> ~str {
        fmt!("vec2[ %f, %f ]", self[0], self[1])
    }
}

//
//  Vec3 struct definition
//
struct vec3 { data:[float * 3] }

//
//  Constants
//
#[inline(always)] pure fn vec3_zero()     -> vec3 { vec3(0f, 0f, 0f) }
#[inline(always)] pure fn vec3_unit_x()   -> vec3 { vec3(1f, 0f, 0f) }
#[inline(always)] pure fn vec3_unit_y()   -> vec3 { vec3(0f, 1f, 0f) }
#[inline(always)] pure fn vec3_unit_z()   -> vec3 { vec3(0f, 0f, 1f) }
#[inline(always)] pure fn vec3_identity() -> vec3 { vec3(1f, 1f, 1f) }

//
//  Vec3 Constructor
//
#[inline(always)]
pure fn vec3(x:float, y:float, z:float) -> vec3 {
    vec3 { data: [ x, y, z ] }
}

//
//  Vector3 Implementation
//
impl vec3: Vector3<float> {
    #[inline(always)] pure fn x() -> float { self.data[0] }
    #[inline(always)] pure fn y() -> float { self.data[1] }
    #[inline(always)] pure fn z() -> float { self.data[2] }

    #[inline(always)]
    fn cross(&&other:vec3) -> vec3 {
        vec3((self[1] * other[2]) - (self[2] * other[1]),
             (self[2] * other[0]) - (self[0] * other[2]),
             (self[0] * other[1]) - (self[1] * other[0]))
    }
}

//
//  Vector Implementation
//
impl vec3: Vector<float> {
    #[inline(always)]
    pure fn dim() -> uint { 3 }

    #[inline(always)]
    pure fn index(&&i: uint) -> float {
        self.data[i]
    }

    #[inline(always)]
    pure fn neg() -> vec3 {
        vec3(-self[0], -self[1], -self[2])
    }

    #[inline(always)]
    pure fn add_f(&&value:float) -> vec3 {
        vec3(self[0] + value,
             self[1] + value,
             self[2] + value)
    }

    #[inline(always)]
    pure fn sub_f(&&value:float) -> vec3 {
        vec3(self[0] - value,
             self[1] - value,
             self[2] - value)
    }

    #[inline(always)]
    pure fn mul_f(&&value:float) -> vec3 {
        vec3(self[0] * value,
             self[1] * value,
             self[2] * value)
    }

    #[inline(always)]
    pure fn div_f(&&value:float) -> vec3 {
        vec3(self[0] / value,
             self[1] / value,
             self[2] / value)
    }

    #[inline(always)]
    pure fn add_v(&&other: vec3) -> vec3{
        vec3(self[0] + other[0],
             self[1] + other[1],
             self[2] + other[2])
    }

    #[inline(always)]
    pure fn sub_v(&&other: vec3) -> vec3{
        vec3(self[0] - other[0],
             self[1] - other[1],
             self[2] - other[2])
    }

    #[inline(always)]
    pure fn dot(&&other: vec3) -> float {
        self[0] * other[0] +
        self[1] * other[1] +
        self[2] * other[2]
    }

    #[inline(always)]
    pure fn exact_eq(&&other:vec3) -> bool {
        self[0] == other[0] &&
        self[1] == other[1] &&
        self[2] == other[2]
    }

    #[inline(always)]
    pure fn fuzzy_eq(&&other: vec3) -> bool {
        self[0].fuzzy_eq(&other[0]) &&
        self[1].fuzzy_eq(&other[1]) &&
        self[2].fuzzy_eq(&other[2])
    }

    #[inline(always)]
    pure fn eq(&&other:vec3) -> bool {
        self.fuzzy_eq(other)
    }

    #[inline(always)]
    pure fn magnitude2() -> float {
        self[0] * self[0] +
        self[1] * self[1] +
        self[2] * self[2]
    }

    #[inline(always)]
    pure fn magnitude() -> float {
        sqrt(self.magnitude2())
    }

    #[inline(always)]
    pure fn normalize() -> vec3 {
        let n = 1f / self.magnitude();
        return self.mul_f(n);
    }
}

//
//  Convert To String
//
impl vec3: ToStr {
    fn to_str() -> ~str {
        fmt!("vec3[ %f, %f, %f ]", self[0], self[1], self[2])
    }
}

//
//  Vec4 struct definition
//
struct vec4 { data:[float * 4] }

//
//  Constants
//
#[inline(always)] pure fn vec4_zero()     -> vec4 { vec4(0f, 0f, 0f, 0f) }
#[inline(always)] pure fn vec4_unit_x()   -> vec4 { vec4(1f, 0f, 0f, 0f) }
#[inline(always)] pure fn vec4_unit_y()   -> vec4 { vec4(0f, 1f, 0f, 0f) }
#[inline(always)] pure fn vec4_unit_z()   -> vec4 { vec4(0f, 0f, 1f, 0f) }
#[inline(always)] pure fn vec4_unit_w()   -> vec4 { vec4(0f, 0f, 0f, 1f) }
#[inline(always)] pure fn vec4_identity() -> vec4 { vec4(1f, 1f, 1f, 1f) }

//
//  Vec4 Constructor
//
#[inline(always)]
pure fn vec4(x:float, y:float, z:float, w:float) -> vec4 {
    vec4 { data: [ x, y, z, w ] }
}

//
//  Vector4 Implementation
//
impl vec4: Vector4<float> {
    #[inline(always)] pure fn x() -> float { self.data[0] }
    #[inline(always)] pure fn y() -> float { self.data[1] }
    #[inline(always)] pure fn z() -> float { self.data[2] }
    #[inline(always)] pure fn w() -> float { self.data[3] }
}

//
//  Vector Implementation
//
impl vec4: Vector<float> {
    #[inline(always)]
    pure fn dim() -> uint { 4 }

    #[inline(always)]
    pure fn index(&&i: uint) -> float {
        self.data[i]
    }

    #[inline(always)]
    pure fn neg() -> vec4 {
        vec4(-self[0], -self[1], -self[2], -self[3])
    }

    #[inline(always)]
    pure fn add_f(&&value:float) -> vec4 {
        vec4(self[0] + value,
             self[1] + value,
             self[2] + value,
             self[3] + value)
    }

    #[inline(always)]
    pure fn sub_f(&&value:float) -> vec4 {
        vec4(self[0] - value,
             self[1] - value,
             self[2] - value,
             self[3] - value)
    }

    #[inline(always)]
    pure fn mul_f(&&value:float) -> vec4 {
        vec4(self[0] * value,
             self[1] * value,
             self[2] * value,
             self[3] * value)
    }

    #[inline(always)]
    pure fn div_f(&&value:float) -> vec4 {
        vec4(self[0] / value,
             self[1] / value,
             self[2] / value,
             self[3] / value)
    }

    #[inline(always)]
    pure fn add_v(&&other: vec4) -> vec4{
        vec4(self[0] + other[0],
             self[1] + other[1],
             self[2] + other[2],
             self[3] + other[3])
    }

    #[inline(always)]
    pure fn sub_v(&&other: vec4) -> vec4{
        vec4(self[0] - other[0],
             self[1] - other[1],
             self[2] - other[2],
             self[3] - other[3])
    }

    #[inline(always)]
    pure fn dot(&&other:vec4) -> float {
        self[0] * other[0] +
        self[1] * other[1] +
        self[2] * other[2] +
        self[3] * other[3]
    }

    #[inline(always)]
    pure fn exact_eq(&&other:vec4) -> bool {
        self[0] == other[0] &&
        self[1] == other[1] &&
        self[2] == other[2] &&
        self[3] == other[3]
    }

    #[inline(always)]
    pure fn fuzzy_eq(&&other: vec4) -> bool {
        self[0].fuzzy_eq(&other[0]) &&
        self[1].fuzzy_eq(&other[1]) &&
        self[2].fuzzy_eq(&other[2]) &&
        self[3].fuzzy_eq(&other[3])
    }

    #[inline(always)]
    pure fn eq(&&other:vec4) -> bool {
        self.fuzzy_eq(other)
    }

    #[inline(always)]
    pure fn magnitude2() -> float {
        self[0] * self[0] +
        self[1] * self[1] +
        self[2] * self[2] +
        self[3] + self[3]
    }

    #[inline(always)]
    pure fn magnitude() -> float {
        sqrt(self.magnitude2())
    }

    #[inline(always)]
    pure fn normalize() -> vec4 {
        let n = 1f / self.magnitude();
        return self.mul_f(n);
    }
}

//
//  Convert To String
//
impl vec4: ToStr {
    fn to_str() -> ~str {
        fmt!("vec4[ %f, %f, %f, %f ]", self[0], self[1], self[2], self[3])
    }
}<|endoftext|>


<commit_before>extern crate winapi;
extern crate user32;

use self::user32::*;
use self::winapi::*;

use super::{KeyboardControllable, MouseControllable};
use std::mem::*;

/// The main struct for handling the event emitting
pub struct Enigo {
    current_x: i32,
    current_y: i32,
}

impl Enigo {
    // TODO(dustin): to the right initialisation

    /// Constructs a new `Enigo` instance.
    ///
    /// # Example
    ///
    /// ```no_run
    /// use enigo::*;
    /// let mut enigo = Enigo::new();
    /// ```
    pub fn new() -> Self {
        Enigo {
            current_x: 0,
            current_y: 0,
        }
    }
}

impl MouseControllable for Enigo {
    fn mouse_move_to(&mut self, x: i32, y: i32) {
        // TODO(dustin): use interior mutability
        self.current_x = x;
        self.current_y = y;
        unsafe { SetCursorPos(self.current_x, self.current_y) };
    }

    fn mouse_move_relative(&mut self, x: i32, y: i32) {
        // TODO(dustin): use interior mutability
        self.current_x += x;
        self.current_y += y;
        unsafe { SetCursorPos(self.current_x, self.current_y) };
    }

    // TODO(dustin): use button parameter, current implementation
    // is using the left mouse button every time
    fn mouse_down(&mut self, button: u32) {
        unsafe {
            let mut input = INPUT {
                type_: INPUT_MOUSE,
                u: transmute_copy(&MOUSEINPUT {
                                       dx: 0,
                                       dy: 0,
                                       mouseData: 0,
                                       dwFlags: MOUSEEVENTF_LEFTDOWN,
                                       time: 0,
                                       dwExtraInfo: 0,
                                   }),
            };

            SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int);
        }
    }

    // TODO(dustin): use button parameter, current implementation
    // is using the left mouse button every time
    fn mouse_up(&mut self, button: u32) {
        unsafe {
            let mut input = INPUT {
                type_: INPUT_MOUSE,
                u: transmute_copy(&MOUSEINPUT {
                                       dx: 0,
                                       dy: 0,
                                       mouseData: 0,
                                       dwFlags: MOUSEEVENTF_LEFTUP,
                                       time: 0,
                                       dwExtraInfo: 0,
                                   }),
            };

            SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int);
        }
    }

    fn mouse_click(&mut self, button: u32) {
        self.mouse_down(button);
        self.mouse_up(button);
    }

    fn mouse_scroll_x(&mut self, length: i32) {
        let mut scroll_direction = 1 * 50; // 1 left -1 right
        let mut length = length;

        if length < 0 {
            length *= -1;
            scroll_direction *= -1;
        }

        for _ in 0..length {
            unsafe {
                let mut input = INPUT {
                    type_: INPUT_MOUSE,
                    u: transmute_copy(&MOUSEINPUT {
                                           dx: 0,
                                           dy: 0,
                                           mouseData: transmute_copy(&scroll_direction),
                                           dwFlags: MOUSEEVENTF_HWHEEL,
                                           time: 0,
                                           dwExtraInfo: 0,
                                       }),
                };

                SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int);
            }
        }
    }

    fn mouse_scroll_y(&mut self, length: i32) {
        let mut scroll_direction = -1 * 50; // 1 left -1 right
        let mut length = length;

        if length < 0 {
            length *= -1;
            scroll_direction *= -1;
        }

        for _ in 0..length {
            unsafe {
                let mut input = INPUT {
                    type_: INPUT_MOUSE,
                    u: transmute_copy(&MOUSEINPUT {
                                           dx: 0,
                                           dy: 0,
                                           mouseData: transmute_copy(&scroll_direction),
                                           dwFlags: MOUSEEVENTF_WHEEL,
                                           time: 0,
                                           dwExtraInfo: 0,
                                       }),
                };

                SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int);
            }
        }
    }
}

impl KeyboardControllable for Enigo {
    fn key_sequence(&self, sequence: &str) {
        //unimplemented!()

        for c in sequence.chars() {
            let mut buffer = [0; 2];
            let result = c.encode_utf16(&mut buffer);
            //Note(dustin): this is wrong utf16 is variable length
            //but i don't know how to feed that properly into SendInput
            let single_u16_result = result[0];
            self.keyclick(single_u16_result);
        }
    }
}

impl Enigo {
    fn keyclick(&self, unicode_char: u16) {
        use std::{thread, time};
        thread::sleep(time::Duration::from_millis(20));
        self.keydown(unicode_char);
        self.keyup(unicode_char);
        thread::sleep(time::Duration::from_millis(20));
    }

    fn keydown(&self, unicode_char: u16) {
        unsafe {
            let mut input = INPUT {
                type_: INPUT_KEYBOARD,
                u: transmute_copy(&KEYBDINPUT {
                    wVk: 0,
                    wScan: unicode_char,
                    dwFlags: KEYEVENTF_UNICODE,
                    time: 0,
                    dwExtraInfo: 0,
                }),
            };

            SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int);
        }
    }

    fn keyup(&self, unicode_char: u16) {
        unsafe {
            let mut input = INPUT {
                type_: INPUT_MOUSE,
                u: transmute_copy(&KEYBDINPUT {
                    wVk: 0,
                    wScan: unicode_char,
                    dwFlags: KEYEVENTF_UNICODE | KEYEVENTF_KEYUP,
                    time: 0,
                    dwExtraInfo: 0,
                }),
            };

            SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int);
        }
    }
}
<commit_msg>fix win keyboard impl<commit_after>extern crate winapi;
extern crate user32;

use self::user32::*;
use self::winapi::*;

use super::{KeyboardControllable, MouseControllable};
use std::mem::*;

/// The main struct for handling the event emitting
pub struct Enigo {
    current_x: i32,
    current_y: i32,
}

impl Enigo {
    // TODO(dustin): to the right initialisation

    /// Constructs a new `Enigo` instance.
    ///
    /// # Example
    ///
    /// ```no_run
    /// use enigo::*;
    /// let mut enigo = Enigo::new();
    /// ```
    pub fn new() -> Self {
        Enigo {
            current_x: 0,
            current_y: 0,
        }
    }
}

impl MouseControllable for Enigo {
    fn mouse_move_to(&mut self, x: i32, y: i32) {
        // TODO(dustin): use interior mutability
        self.current_x = x;
        self.current_y = y;
        unsafe { SetCursorPos(self.current_x, self.current_y) };
    }

    fn mouse_move_relative(&mut self, x: i32, y: i32) {
        // TODO(dustin): use interior mutability
        self.current_x += x;
        self.current_y += y;
        unsafe { SetCursorPos(self.current_x, self.current_y) };
    }

    // TODO(dustin): use button parameter, current implementation
    // is using the left mouse button every time
    fn mouse_down(&mut self, button: u32) {
        unsafe {
            let mut input = INPUT {
                type_: INPUT_MOUSE,
                u: transmute_copy(&MOUSEINPUT {
                                       dx: 0,
                                       dy: 0,
                                       mouseData: 0,
                                       dwFlags: MOUSEEVENTF_LEFTDOWN,
                                       time: 0,
                                       dwExtraInfo: 0,
                                   }),
            };

            SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int);
        }
    }

    // TODO(dustin): use button parameter, current implementation
    // is using the left mouse button every time
    fn mouse_up(&mut self, button: u32) {
        unsafe {
            let mut input = INPUT {
                type_: INPUT_MOUSE,
                u: transmute_copy(&MOUSEINPUT {
                                       dx: 0,
                                       dy: 0,
                                       mouseData: 0,
                                       dwFlags: MOUSEEVENTF_LEFTUP,
                                       time: 0,
                                       dwExtraInfo: 0,
                                   }),
            };

            SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int);
        }
    }

    fn mouse_click(&mut self, button: u32) {
        self.mouse_down(button);
        self.mouse_up(button);
    }

    fn mouse_scroll_x(&mut self, length: i32) {
        let mut scroll_direction = 1 * 50; // 1 left -1 right
        let mut length = length;

        if length < 0 {
            length *= -1;
            scroll_direction *= -1;
        }

        for _ in 0..length {
            unsafe {
                let mut input = INPUT {
                    type_: INPUT_MOUSE,
                    u: transmute_copy(&MOUSEINPUT {
                                           dx: 0,
                                           dy: 0,
                                           mouseData: transmute_copy(&scroll_direction),
                                           dwFlags: MOUSEEVENTF_HWHEEL,
                                           time: 0,
                                           dwExtraInfo: 0,
                                       }),
                };

                SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int);
            }
        }
    }

    fn mouse_scroll_y(&mut self, length: i32) {
        let mut scroll_direction = -1 * 50; // 1 left -1 right
        let mut length = length;

        if length < 0 {
            length *= -1;
            scroll_direction *= -1;
        }

        for _ in 0..length {
            unsafe {
                let mut input = INPUT {
                    type_: INPUT_MOUSE,
                    u: transmute_copy(&MOUSEINPUT {
                                           dx: 0,
                                           dy: 0,
                                           mouseData: transmute_copy(&scroll_direction),
                                           dwFlags: MOUSEEVENTF_WHEEL,
                                           time: 0,
                                           dwExtraInfo: 0,
                                       }),
                };

                SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int);
            }
        }
    }
}

impl KeyboardControllable for Enigo {
    fn key_sequence(&mut self, sequence: &str) {
        //unimplemented!()

        for c in sequence.chars() {
            let mut buffer = [0; 2];
            let result = c.encode_utf16(&mut buffer);
            //Note(dustin): this is wrong utf16 is variable length
            //but i don't know how to feed that properly into SendInput
            let single_u16_result = result[0];
            self.keyclick(single_u16_result);
        }
    }
}

impl Enigo {
    fn keyclick(&self, unicode_char: u16) {
        use std::{thread, time};
        thread::sleep(time::Duration::from_millis(20));
        self.keydown(unicode_char);
        self.keyup(unicode_char);
        thread::sleep(time::Duration::from_millis(20));
    }

    fn keydown(&self, unicode_char: u16) {
        unsafe {
            let mut input = INPUT {
                type_: INPUT_KEYBOARD,
                u: transmute_copy(&KEYBDINPUT {
                    wVk: 0,
                    wScan: unicode_char,
                    dwFlags: KEYEVENTF_UNICODE,
                    time: 0,
                    dwExtraInfo: 0,
                }),
            };

            SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int);
        }
    }

    fn keyup(&self, unicode_char: u16) {
        unsafe {
            let mut input = INPUT {
                type_: INPUT_MOUSE,
                u: transmute_copy(&KEYBDINPUT {
                    wVk: 0,
                    wScan: unicode_char,
                    dwFlags: KEYEVENTF_UNICODE | KEYEVENTF_KEYUP,
                    time: 0,
                    dwExtraInfo: 0,
                }),
            };

            SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int);
        }
    }
}
<|endoftext|>


<commit_before>//
// Sysinfo
//
// Copyright (c) 2017 Guillaume Gomez
//

#![crate_type = "bin"]
#![allow(unused_must_use, non_upper_case_globals)]

extern crate sysinfo;

use std::io::{self, BufRead, Write};
use std::str::FromStr;
use sysinfo::Signal::*;
use sysinfo::{NetworkExt, NetworksExt, Pid, ProcessExt, ProcessorExt, Signal, System, SystemExt};

const signals: [Signal; 31] = [
    Hangup,
    Interrupt,
    Quit,
    Illegal,
    Trap,
    Abort,
    Bus,
    FloatingPointException,
    Kill,
    User1,
    Segv,
    User2,
    Pipe,
    Alarm,
    Term,
    Stklft,
    Child,
    Continue,
    Stop,
    TSTP,
    TTIN,
    TTOU,
    Urgent,
    XCPU,
    XFSZ,
    VirtualAlarm,
    Profiling,
    Winch,
    IO,
    Power,
    Sys,
];

fn print_help() {
    writeln!(&mut io::stdout(), "== Help menu ==");
    writeln!(&mut io::stdout(), "help               : show this menu");
    writeln!(
        &mut io::stdout(),
        "signals            : show the available signals"
    );
    writeln!(
        &mut io::stdout(),
        "refresh            : reloads all processes' information"
    );
    writeln!(
        &mut io::stdout(),
        "refresh [pid]      : reloads corresponding process' information"
    );
    writeln!(
        &mut io::stdout(),
        "refresh_disks      : reloads only disks' information"
    );
    writeln!(
        &mut io::stdout(),
        "show [pid | name]  : show information of the given process \
                                 corresponding to [pid | name]"
    );
    writeln!(
        &mut io::stdout(),
        "kill [pid] [signal]: send [signal] to the process with this \
                                 [pid]. 0 < [signal] < 32"
    );
    writeln!(
        &mut io::stdout(),
        "procd              : Displays processors state"
    );
    writeln!(
        &mut io::stdout(),
        "memory             : Displays memory state"
    );
    writeln!(
        &mut io::stdout(),
        "temperature        : Displays components' temperature"
    );
    writeln!(
        &mut io::stdout(),
        "disks              : Displays disks' information"
    );
    writeln!(
        &mut io::stdout(),
        "network            : Displays network' information"
    );
    writeln!(
        &mut io::stdout(),
        "all                : Displays all process name and pid"
    );
    writeln!(
        &mut io::stdout(),
        "uptime             : Displays system uptime"
    );
    writeln!(
        &mut io::stdout(),
        "vendor_id          : Displays processor vendor id"
    );
    writeln!(
        &mut io::stdout(),
        "brand              : Displays processor brand"
    );
    writeln!(
        &mut io::stdout(),
        "load_avg           : Displays system load average"
    );
    writeln!(
        &mut io::stdout(),
        "frequency          : Displays processor frequency"
    );
    writeln!(&mut io::stdout(), "quit               : exit the program");
}

fn interpret_input(input: &str, sys: &mut System) -> bool {
    match input.trim() {
        "help" => print_help(),
        "refresh_disks" => {
            writeln!(&mut io::stdout(), "Refreshing disk list...");
            sys.refresh_disk_list();
            writeln!(&mut io::stdout(), "Done.");
        }
        "signals" => {
            let mut nb = 1i32;

            for sig in &signals {
                writeln!(&mut io::stdout(), "{:2}:{:?}", nb, sig);
                nb += 1;
            }
        }
        "procs" => {
            // Note: you should refresh a few times before using this, so that usage statistics
            // can be ascertained
            let procs = sys.get_processor_list();

            writeln!(
                &mut io::stdout(),
                "total process usage: {}%",
                procs[0].get_cpu_usage()
            );
            for proc_ in procs.iter().skip(1) {
                writeln!(&mut io::stdout(), "{:?}", proc_);
            }
        }
        "memory" => {
            writeln!(
                &mut io::stdout(),
                "total memory: {} KiB",
                sys.get_total_memory()
            );
            writeln!(
                &mut io::stdout(),
                "used memory : {} KiB",
                sys.get_used_memory()
            );
            writeln!(
                &mut io::stdout(),
                "total swap  : {} KiB",
                sys.get_total_swap()
            );
            writeln!(
                &mut io::stdout(),
                "used swap   : {} KiB",
                sys.get_used_swap()
            );
        }
        "quit" | "exit" => return true,
        "all" => {
            for (pid, proc_) in sys.get_process_list() {
                writeln!(
                    &mut io::stdout(),
                    "{}:{} status={:?}",
                    pid,
                    proc_.name(),
                    proc_.status()
                );
            }
        }
        "frequency" => {
            let procs = sys.get_processor_list();
            // On windows, the first processor is the "all processors", so not interesting in here.
            writeln!(
                &mut io::stdout(),
                "{} MHz",
                procs[if procs.len() > 1 { 1 } else { 0 }].get_frequency()
            );
        }
        "vendor_id" => {
            writeln!(
                &mut io::stdout(),
                "vendor ID: {}",
                sys.get_processor_list()[0].get_vendor_id()
            );
        }
        "brand" => {
            writeln!(
                &mut io::stdout(),
                "brand: {}",
                sys.get_processor_list()[0].get_brand()
            );
        }
        "load_avg" => {
            let load_avg = sys.get_load_average();
            writeln!(&mut io::stdout(), "one minute     : {}%", load_avg.one);
            writeln!(&mut io::stdout(), "five minutes   : {}%", load_avg.five);
            writeln!(&mut io::stdout(), "fifteen minutes: {}%", load_avg.fifteen);
        }
        e if e.starts_with("show ") => {
            let tmp: Vec<&str> = e.split(' ').collect();

            if tmp.len() != 2 {
                writeln!(
                    &mut io::stdout(),
                    "show command takes a pid or a name in parameter!"
                );
                writeln!(&mut io::stdout(), "example: show 1254");
            } else if let Ok(pid) = Pid::from_str(tmp[1]) {
                match sys.get_process(pid) {
                    Some(p) => writeln!(&mut io::stdout(), "{:?}", *p),
                    None => writeln!(&mut io::stdout(), "pid \"{:?}\" not found", pid),
                };
            } else {
                let proc_name = tmp[1];
                for proc_ in sys.get_process_by_name(proc_name) {
                    writeln!(&mut io::stdout(), "==== {} ====", proc_.name());
                    writeln!(&mut io::stdout(), "{:?}", proc_);
                }
            }
        }
        "temperature" => {
            for component in sys.get_components_list() {
                writeln!(&mut io::stdout(), "{:?}", component);
            }
        }
        "network" => {
            for (interface_name, data) in sys.get_networks().iter() {
                writeln!(
                    &mut io::stdout(),
                    "{}:\n  input data  (new / total): {} / {} B\n  output data (new / total): {} / {} B",
                    interface_name,
                    data.get_income(),
                    data.get_total_income(),
                    data.get_outcome(),
                    data.get_total_outcome(),
                );
            }
        }
        "show" => {
            writeln!(
                &mut io::stdout(),
                "'show' command expects a pid number or a process name"
            );
        }
        e if e.starts_with("kill ") => {
            let tmp: Vec<&str> = e.split(' ').collect();

            if tmp.len() != 3 {
                writeln!(
                    &mut io::stdout(),
                    "kill command takes the pid and a signal number in parameter !"
                );
                writeln!(&mut io::stdout(), "example: kill 1254 9");
            } else {
                let pid = Pid::from_str(tmp[1]).unwrap();
                let signal = i32::from_str(tmp[2]).unwrap();

                if signal < 1 || signal > 31 {
                    writeln!(
                        &mut io::stdout(),
                        "Signal must be between 0 and 32 ! See the signals list with the \
                              signals command"
                    );
                } else {
                    match sys.get_process(pid) {
                        Some(p) => {
                            writeln!(
                                &mut io::stdout(),
                                "kill: {}",
                                p.kill(*signals.get(signal as usize - 1).unwrap())
                            );
                        }
                        None => {
                            writeln!(&mut io::stdout(), "pid not found");
                        }
                    };
                }
            }
        }
        "disks" => {
            for disk in sys.get_disks() {
                writeln!(&mut io::stdout(), "{:?}", disk);
            }
        }
        "uptime" => {
            let mut uptime = sys.get_uptime();
            let days = uptime / 86400;
            uptime -= days * 86400;
            let hours = uptime / 3600;
            uptime -= hours * 3600;
            let minutes = uptime / 60;
            writeln!(
                &mut io::stdout(),
                "{} days {} hours {} minutes",
                days,
                hours,
                minutes
            );
        }
        x if x.starts_with("refresh") => {
            if x == "refresh" {
                writeln!(&mut io::stdout(), "Getting processes' information...");
                sys.refresh_all();
                writeln!(&mut io::stdout(), "Done.");
            } else if x.starts_with("refresh ") {
                writeln!(&mut io::stdout(), "Getting process' information...");
                if let Some(pid) = x
                    .split(' ')
                    .filter_map(|pid| pid.parse().ok())
                    .take(1)
                    .next()
                {
                    if sys.refresh_process(pid) {
                        writeln!(&mut io::stdout(), "Process `{}` updated successfully", pid);
                    } else {
                        writeln!(
                            &mut io::stdout(),
                            "Process `{}` couldn't be updated...",
                            pid
                        );
                    }
                } else {
                    writeln!(&mut io::stdout(), "Invalid [pid] received...");
                }
            } else {
                writeln!(
                    &mut io::stdout(),
                    "\"{}\": Unknown command. Enter 'help' if you want to get the commands' \
                      list.",
                    x
                );
            }
        }
        e => {
            writeln!(
                &mut io::stdout(),
                "\"{}\": Unknown command. Enter 'help' if you want to get the commands' \
                      list.",
                e
            );
        }
    }
    false
}

fn main() {
    println!("Getting processes' information...");
    let mut t = System::new();
    println!("Done.");
    let t_stin = io::stdin();
    let mut stin = t_stin.lock();
    let mut done = false;

    println!("To get the commands' list, enter 'help'.");
    while !done {
        let mut input = String::new();
        write!(&mut io::stdout(), "> ");
        io::stdout().flush();

        stin.read_line(&mut input);
        if input.is_empty() {
            // The string is empty, meaning there is no '\n', meaning
            // that the user used CTRL+D so we can just quit!
            println!("\nLeaving, bye!");
            break;
        }
        if (&input as &str).ends_with('\n') {
            input.pop();
        }
        done = interpret_input(input.as_ref(), &mut t);
    }
}
<commit_msg>Improve network display in example<commit_after>//
// Sysinfo
//
// Copyright (c) 2017 Guillaume Gomez
//

#![crate_type = "bin"]
#![allow(unused_must_use, non_upper_case_globals)]

extern crate sysinfo;

use std::io::{self, BufRead, Write};
use std::str::FromStr;
use sysinfo::Signal::*;
use sysinfo::{NetworkExt, NetworksExt, Pid, ProcessExt, ProcessorExt, Signal, System, SystemExt};

const signals: [Signal; 31] = [
    Hangup,
    Interrupt,
    Quit,
    Illegal,
    Trap,
    Abort,
    Bus,
    FloatingPointException,
    Kill,
    User1,
    Segv,
    User2,
    Pipe,
    Alarm,
    Term,
    Stklft,
    Child,
    Continue,
    Stop,
    TSTP,
    TTIN,
    TTOU,
    Urgent,
    XCPU,
    XFSZ,
    VirtualAlarm,
    Profiling,
    Winch,
    IO,
    Power,
    Sys,
];

fn print_help() {
    writeln!(&mut io::stdout(), "== Help menu ==");
    writeln!(&mut io::stdout(), "help               : show this menu");
    writeln!(
        &mut io::stdout(),
        "signals            : show the available signals"
    );
    writeln!(
        &mut io::stdout(),
        "refresh            : reloads all processes' information"
    );
    writeln!(
        &mut io::stdout(),
        "refresh [pid]      : reloads corresponding process' information"
    );
    writeln!(
        &mut io::stdout(),
        "refresh_disks      : reloads only disks' information"
    );
    writeln!(
        &mut io::stdout(),
        "show [pid | name]  : show information of the given process \
                                 corresponding to [pid | name]"
    );
    writeln!(
        &mut io::stdout(),
        "kill [pid] [signal]: send [signal] to the process with this \
                                 [pid]. 0 < [signal] < 32"
    );
    writeln!(
        &mut io::stdout(),
        "procd              : Displays processors state"
    );
    writeln!(
        &mut io::stdout(),
        "memory             : Displays memory state"
    );
    writeln!(
        &mut io::stdout(),
        "temperature        : Displays components' temperature"
    );
    writeln!(
        &mut io::stdout(),
        "disks              : Displays disks' information"
    );
    writeln!(
        &mut io::stdout(),
        "network            : Displays network' information"
    );
    writeln!(
        &mut io::stdout(),
        "all                : Displays all process name and pid"
    );
    writeln!(
        &mut io::stdout(),
        "uptime             : Displays system uptime"
    );
    writeln!(
        &mut io::stdout(),
        "vendor_id          : Displays processor vendor id"
    );
    writeln!(
        &mut io::stdout(),
        "brand              : Displays processor brand"
    );
    writeln!(
        &mut io::stdout(),
        "load_avg           : Displays system load average"
    );
    writeln!(
        &mut io::stdout(),
        "frequency          : Displays processor frequency"
    );
    writeln!(&mut io::stdout(), "quit               : exit the program");
}

fn interpret_input(input: &str, sys: &mut System) -> bool {
    match input.trim() {
        "help" => print_help(),
        "refresh_disks" => {
            writeln!(&mut io::stdout(), "Refreshing disk list...");
            sys.refresh_disk_list();
            writeln!(&mut io::stdout(), "Done.");
        }
        "signals" => {
            let mut nb = 1i32;

            for sig in &signals {
                writeln!(&mut io::stdout(), "{:2}:{:?}", nb, sig);
                nb += 1;
            }
        }
        "procs" => {
            // Note: you should refresh a few times before using this, so that usage statistics
            // can be ascertained
            let procs = sys.get_processor_list();

            writeln!(
                &mut io::stdout(),
                "total process usage: {}%",
                procs[0].get_cpu_usage()
            );
            for proc_ in procs.iter().skip(1) {
                writeln!(&mut io::stdout(), "{:?}", proc_);
            }
        }
        "memory" => {
            writeln!(
                &mut io::stdout(),
                "total memory: {} KiB",
                sys.get_total_memory()
            );
            writeln!(
                &mut io::stdout(),
                "used memory : {} KiB",
                sys.get_used_memory()
            );
            writeln!(
                &mut io::stdout(),
                "total swap  : {} KiB",
                sys.get_total_swap()
            );
            writeln!(
                &mut io::stdout(),
                "used swap   : {} KiB",
                sys.get_used_swap()
            );
        }
        "quit" | "exit" => return true,
        "all" => {
            for (pid, proc_) in sys.get_process_list() {
                writeln!(
                    &mut io::stdout(),
                    "{}:{} status={:?}",
                    pid,
                    proc_.name(),
                    proc_.status()
                );
            }
        }
        "frequency" => {
            let procs = sys.get_processor_list();
            // On windows, the first processor is the "all processors", so not interesting in here.
            writeln!(
                &mut io::stdout(),
                "{} MHz",
                procs[if procs.len() > 1 { 1 } else { 0 }].get_frequency()
            );
        }
        "vendor_id" => {
            writeln!(
                &mut io::stdout(),
                "vendor ID: {}",
                sys.get_processor_list()[0].get_vendor_id()
            );
        }
        "brand" => {
            writeln!(
                &mut io::stdout(),
                "brand: {}",
                sys.get_processor_list()[0].get_brand()
            );
        }
        "load_avg" => {
            let load_avg = sys.get_load_average();
            writeln!(&mut io::stdout(), "one minute     : {}%", load_avg.one);
            writeln!(&mut io::stdout(), "five minutes   : {}%", load_avg.five);
            writeln!(&mut io::stdout(), "fifteen minutes: {}%", load_avg.fifteen);
        }
        e if e.starts_with("show ") => {
            let tmp: Vec<&str> = e.split(' ').collect();

            if tmp.len() != 2 {
                writeln!(
                    &mut io::stdout(),
                    "show command takes a pid or a name in parameter!"
                );
                writeln!(&mut io::stdout(), "example: show 1254");
            } else if let Ok(pid) = Pid::from_str(tmp[1]) {
                match sys.get_process(pid) {
                    Some(p) => writeln!(&mut io::stdout(), "{:?}", *p),
                    None => writeln!(&mut io::stdout(), "pid \"{:?}\" not found", pid),
                };
            } else {
                let proc_name = tmp[1];
                for proc_ in sys.get_process_by_name(proc_name) {
                    writeln!(&mut io::stdout(), "==== {} ====", proc_.name());
                    writeln!(&mut io::stdout(), "{:?}", proc_);
                }
            }
        }
        "temperature" => {
            for component in sys.get_components_list() {
                writeln!(&mut io::stdout(), "{:?}", component);
            }
        }
        "network" => {
            for (interface_name, data) in sys.get_networks().iter() {
                writeln!(
                    &mut io::stdout(),
                    "{}:\n  input data  (new / total): {} / {} B\n  output data (new / total): {} / {} B",
                    interface_name,
                    data.get_income(),
                    data.get_total_income(),
                    data.get_outcome(),
                    data.get_total_outcome(),
                );
            }
        }
        "show" => {
            writeln!(
                &mut io::stdout(),
                "'show' command expects a pid number or a process name"
            );
        }
        e if e.starts_with("kill ") => {
            let tmp: Vec<&str> = e.split(' ').collect();

            if tmp.len() != 3 {
                writeln!(
                    &mut io::stdout(),
                    "kill command takes the pid and a signal number in parameter !"
                );
                writeln!(&mut io::stdout(), "example: kill 1254 9");
            } else {
                let pid = Pid::from_str(tmp[1]).unwrap();
                let signal = i32::from_str(tmp[2]).unwrap();

                if signal < 1 || signal > 31 {
                    writeln!(
                        &mut io::stdout(),
                        "Signal must be between 0 and 32 ! See the signals list with the \
                              signals command"
                    );
                } else {
                    match sys.get_process(pid) {
                        Some(p) => {
                            writeln!(
                                &mut io::stdout(),
                                "kill: {}",
                                p.kill(*signals.get(signal as usize - 1).unwrap())
                            );
                        }
                        None => {
                            writeln!(&mut io::stdout(), "pid not found");
                        }
                    };
                }
            }
        }
        "disks" => {
            for disk in sys.get_disks() {
                writeln!(&mut io::stdout(), "{:?}", disk);
            }
        }
        "uptime" => {
            let mut uptime = sys.get_uptime();
            let days = uptime / 86400;
            uptime -= days * 86400;
            let hours = uptime / 3600;
            uptime -= hours * 3600;
            let minutes = uptime / 60;
            writeln!(
                &mut io::stdout(),
                "{} days {} hours {} minutes",
                days,
                hours,
                minutes
            );
        }
        x if x.starts_with("refresh") => {
            if x == "refresh" {
                writeln!(&mut io::stdout(), "Getting processes' information...");
                sys.refresh_all();
                writeln!(&mut io::stdout(), "Done.");
            } else if x.starts_with("refresh ") {
                writeln!(&mut io::stdout(), "Getting process' information...");
                if let Some(pid) = x
                    .split(' ')
                    .filter_map(|pid| pid.parse().ok())
                    .take(1)
                    .next()
                {
                    if sys.refresh_process(pid) {
                        writeln!(&mut io::stdout(), "Process `{}` updated successfully", pid);
                    } else {
                        writeln!(
                            &mut io::stdout(),
                            "Process `{}` couldn't be updated...",
                            pid
                        );
                    }
                } else {
                    writeln!(&mut io::stdout(), "Invalid [pid] received...");
                }
            } else {
                writeln!(
                    &mut io::stdout(),
                    "\"{}\": Unknown command. Enter 'help' if you want to get the commands' \
                      list.",
                    x
                );
            }
        }
        e => {
            writeln!(
                &mut io::stdout(),
                "\"{}\": Unknown command. Enter 'help' if you want to get the commands' \
                      list.",
                e
            );
        }
    }
    false
}

fn main() {
    println!("Getting processes' information...");
    let mut t = System::new_all();
    println!("Done.");
    let t_stin = io::stdin();
    let mut stin = t_stin.lock();
    let mut done = false;

    println!("To get the commands' list, enter 'help'.");
    while !done {
        let mut input = String::new();
        write!(&mut io::stdout(), "> ");
        io::stdout().flush();

        stin.read_line(&mut input);
        if input.is_empty() {
            // The string is empty, meaning there is no '\n', meaning
            // that the user used CTRL+D so we can just quit!
            println!("\nLeaving, bye!");
            break;
        }
        if (&input as &str).ends_with('\n') {
            input.pop();
        }
        done = interpret_input(input.as_ref(), &mut t);
    }
}
<|endoftext|>