<commit_before>use std;
use std::ffi;
use std::fmt;
use std::os::raw::{c_char, c_int, c_long, c_uchar, c_uint, c_ulong, c_void};
use std::ptr;
use std::slice;

use x11::xlib;

use debug;
use keys::{KeyCombo, KeyHandlers, ModKey};

/// A handle to an X Window.
#[derive(Debug, PartialEq)]
pub struct WindowId(xlib::Window);

impl WindowId {
    fn to_x(&self) -> xlib::Window {
        self.0
    }
}

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

#[allow(non_snake_case)]
struct InternedAtoms {
    WM_DELETE_WINDOW: xlib::Atom,
    WM_PROTOCOLS: xlib::Atom,
}

pub struct Connection {
    display: *mut xlib::Display,
    root: WindowId,
    atoms: InternedAtoms,
}

// TODO: Implement Drop so that we can call XCloseDisplay?

impl Connection {
    /// Opens a connection to the X server, returning a new Connection object.
    pub fn connect() -> Result<Connection, String> {
        let (display, root) = unsafe {
            let display: *mut xlib::Display = xlib::XOpenDisplay(ptr::null_mut());
            let root: xlib::Window = xlib::XDefaultRootWindow(display);
            (display, root)
        };

        if display.is_null() {
            return Err("XOpenDisplay returned null pointer".to_owned());
        }
        if root == 0 {
            return Err("XDefaultRootWindow returned 0".to_owned());
        }

        Ok(Connection {
               display: display,
               root: WindowId(root),
               atoms: InternedAtoms {
                   WM_PROTOCOLS: Self::intern_atom(display, "WM_PROTOCOLS"),
                   WM_DELETE_WINDOW: Self::intern_atom(display, "WM_DELETE_WINDOW"),
               },
           })
    }

    /// Returns the Atom identifier associated with the atom_name str.
    fn intern_atom(display: *mut xlib::Display, atom_name: &str) -> xlib::Atom {
        // Note: the CString is bound to a variable to ensure adequate lifetime.
        let cstring = ffi::CString::new(atom_name).unwrap();
        let ptr = cstring.as_ptr() as *const c_char;
        unsafe { xlib::XInternAtom(display, ptr, 0) }
    }

    /// Installs the Connection as a window manager, by registers for
    /// SubstructureNotify and SubstructureRedirect events on the root window.
    /// If there is already a window manager on the display, then this will
    /// fail.
    pub fn install_as_wm(&self, key_handlers: &KeyHandlers) -> Result<(), String> {
        unsafe {
            // It's tricky to get state from the error handler to here, so we install a
            // special handler while becoming the WM that panics on error.
            xlib::XSetErrorHandler(Some(debug::error_handler_init));
            xlib::XSelectInput(self.display,
                               self.root.to_x(),
                               xlib::SubstructureNotifyMask | xlib::SubstructureRedirectMask);
            xlib::XSync(self.display, 0);

            // If we get this far, then our error handler didn't panic. Set a more useful
            // error handler.
            xlib::XSetErrorHandler(Some(debug::error_handler));
        }

        self.enable_window_key_events(&self.root, key_handlers);

        Ok(())
    }

    /// Returns the ID of the root window.
    pub fn root_window_id(&self) -> &WindowId {
        &self.root
    }

    pub fn top_level_windows(&self) -> Vec<WindowId> {
        let mut root: xlib::Window = 0;
        let mut parent: xlib::Window = 0;
        let mut children: *mut xlib::Window = ptr::null_mut();
        let mut num_children: c_uint = 0;
        unsafe {
            xlib::XQueryTree(self.display,
                             self.root.to_x(),
                             &mut root,
                             &mut parent,
                             &mut children,
                             &mut num_children);
        }

        if children.is_null() || num_children == 0 {
            return vec![];
        }

        let slice = unsafe { slice::from_raw_parts(children, num_children as usize) };
        let vec: Vec<WindowId> = slice.iter().map(|id| WindowId(*id)).collect();

        unsafe {
            xlib::XFree(children as *mut c_void);
        }

        vec
    }

    /// Queries the WM_PROTOCOLS property of a window, returning a list of the
    /// protocols that it supports.
    // TODO: Have this return a list of atoms, rather than a list of strings.
    // (Perhaps we should
    // have a separate function to convert to a list of strings for debugging?)
    pub fn get_wm_protocols(&self, window_id: &WindowId) -> Vec<String> {
        let mut atoms: *mut c_ulong = ptr::null_mut();
        let mut count: c_int = 0;
        unsafe {
            xlib::XGetWMProtocols(self.display, window_id.to_x(), &mut atoms, &mut count);
        }

        if atoms.is_null() {
            error!("XGetWMProtocols returned null pointer");
            return Vec::new();
        }
        if count == 0 {
            return Vec::new();
        }

        let mut pointers: Vec<*mut c_char> = Vec::with_capacity(count as usize);
        let protocols: Vec<String> = unsafe {
            xlib::XGetAtomNames(self.display, atoms, count, pointers.as_mut_ptr());
            pointers.set_len(count as usize);
            pointers
                .iter()
                .map(|buffer| {
                         ffi::CStr::from_ptr(*buffer)
                             .to_str()
                             .unwrap()
                             .to_owned()
                     })
                .collect()
        };

        unsafe {
            for pointer in pointers.iter() {
                xlib::XFree(*pointer as *mut c_void);
            }
            xlib::XFree(atoms as *mut c_void);
        }

        protocols
    }

    // TODO: This, as it'd make the WM_DELETE_WINDOW code a little clearer.
    // pub fn supports_protocol(&self, window_id, WindowId, atom: Atom) -> bool;

    /// Closes a window.
    ///
    /// The window will be closed gracefully using the ICCCM WM_DELETE_WINDOW
    /// protocol if it is supported.
    pub fn close_window(&self, window_id: &WindowId) {
        let protocols = self.get_wm_protocols(window_id);
        let has_wm_delete_window = protocols.contains(&"WM_DELETE_WINDOW".to_owned());

        // TODO: Use XDestroyWindow to forcefully close windows that do not support
        // WM_DELETE_WINDOW.
        if !has_wm_delete_window {
            panic!("Not implemented: closing windows that don't expose WM_DELETE_WINDOW");
        }

        let mut client_message = xlib::XClientMessageEvent {
            type_: xlib::ClientMessage,
            serial: 0,
            send_event: 0,
            display: ptr::null_mut(),
            window: window_id.to_x(),
            message_type: self.atoms.WM_PROTOCOLS,
            format: 32,
            data: xlib::ClientMessageData::new(),
        };
        client_message
            .data
            .set_long(0, self.atoms.WM_DELETE_WINDOW as c_long);
        client_message
            .data
            .set_long(1, xlib::CurrentTime as c_long);
        let mut event = xlib::XEvent::from(client_message);
        unsafe {
            xlib::XSendEvent(self.display,
                             window_id.to_x(),
                             0,
                             xlib::NoEventMask,
                             &mut event);
        }
    }

    /// Sets the window's position and size.
    pub fn configure_window(&self, window_id: &WindowId, x: i32, y: i32, width: i32, height: i32) {
        let mut changes = xlib::XWindowChanges {
            x: x,
            y: y,
            width: width,
            height: height,

            // Ignored:
            border_width: 0,
            sibling: 0,
            stack_mode: 0,
        };
        let flags = xlib::CWX | xlib::CWY | xlib::CWWidth | xlib::CWHeight;

        unsafe {
            xlib::XConfigureWindow(self.display, window_id.to_x(), flags as u32, &mut changes);
        };
    }

    /// Get's the window's width and height.
    pub fn get_window_geometry(&self, window_id: &WindowId) -> (i32, i32) {
        unsafe {
            let mut attrs: xlib::XWindowAttributes = std::mem::zeroed();
            xlib::XGetWindowAttributes(self.display, window_id.to_x(), &mut attrs);

            (attrs.width, attrs.height)
        }
    }

    /// Map a window.
    pub fn map_window(&self, window_id: &WindowId) {
        unsafe {
            xlib::XMapWindow(self.display, window_id.to_x());
        }
    }

    /// Unmap a window.
    pub fn unmap_window(&self, window_id: &WindowId) {
        unsafe {
            xlib::XUnmapWindow(self.display, window_id.to_x());
        }
    }

    /// Registers for key events.
    pub fn enable_window_key_events(&self, window_id: &WindowId, key_handlers: &KeyHandlers) {
        unsafe {
            for key in key_handlers.key_combos() {
                let keycode = xlib::XKeysymToKeycode(self.display, key.keysym as u64) as i32;
                xlib::XGrabKey(self.display,
                               keycode,
                               key.mod_mask,
                               window_id.to_x(),
                               0,
                               xlib::GrabModeAsync,
                               xlib::GrabModeAsync);
            }
        }
    }

    pub fn enable_window_focus_tracking(&self, window_id: &WindowId) {
        unsafe {
            xlib::XSelectInput(self.display, window_id.to_x(), xlib::EnterWindowMask);
        }
    }

    pub fn disable_window_focus_tracking(&self, window_id: &WindowId) {
        unsafe {
            xlib::XSelectInput(self.display, window_id.to_x(), 0);
        }
    }

    pub fn focus_window(&self, window_id: &WindowId) {
        self.map_window(&window_id);
        unsafe {
            xlib::XSetInputFocus(self.display,
                                 window_id.to_x(),
                                 xlib::RevertToPointerRoot,
                                 xlib::CurrentTime);
            // TODO: _NET_ACTIVE_WINDOW
        }
    }

    pub fn get_event_loop(&self) -> EventLoop {
        EventLoop { connection: &self }
    }
}

/// Events received from the `EventLoop`.
pub enum Event {
    MapRequest(WindowId),
    DestroyNotify(WindowId),
    KeyPress(KeyCombo),
    EnterNotify(WindowId),
}

/// An iterator that yields events from the X event loop.
///
/// Use `Connection::get_event_loop()` to get one.
pub struct EventLoop<'a> {
    connection: &'a Connection,
}

impl<'a> Iterator for EventLoop<'a> {
    type Item = Event;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            unsafe {
                let mut event = std::mem::zeroed();
                xlib::XNextEvent(self.connection.display, &mut event);

                let event = match event.get_type() {
                    xlib::ConfigureRequest => {
                        self.on_configure_request(xlib::XConfigureRequestEvent::from(event))
                    }
                    // TODO: move most of these handlers up to the window manager. The
                    // only one that out to stay here is the ConfigureRequest, as we're
                    // not going to do much with it!
                    xlib::MapRequest => self.on_map_request(xlib::XMapRequestEvent::from(event)),
                    xlib::DestroyNotify => {
                        self.on_destroy_notify(xlib::XDestroyWindowEvent::from(event))
                    }
                    xlib::KeyPress => self.on_key_press(xlib::XKeyPressedEvent::from(event)),
                    xlib::EnterNotify => self.on_enter_notify(xlib::XEnterWindowEvent::from(event)),
                    _ => None,
                };

                if let Some(event) = event {
                    return Some(event);
                }
            }
        }
    }
}

impl<'a> EventLoop<'a> {
    fn on_configure_request(&self, event: xlib::XConfigureRequestEvent) -> Option<Event> {
        // This request is not interesting for us: grant it unchanged.
        let mut changes = xlib::XWindowChanges {
            x: event.x,
            y: event.y,
            width: event.width,
            height: event.height,
            border_width: event.border_width,
            sibling: event.above,
            stack_mode: event.detail,
        };

        unsafe {
            xlib::XConfigureWindow(self.connection.display,
                                   event.window,
                                   event.value_mask as u32,
                                   &mut changes);
        }

        // There's no value in propogating this event.
        None
    }

    fn on_map_request(&self, event: xlib::XMapRequestEvent) -> Option<Event> {
        Some(Event::MapRequest(WindowId(event.window)))
    }

    fn on_destroy_notify(&self, event: xlib::XDestroyWindowEvent) -> Option<Event> {
        Some(Event::DestroyNotify(WindowId(event.window)))
    }

    fn on_key_press(&self, event: xlib::XKeyPressedEvent) -> Option<Event> {
        let mod_mask = event.state & ModKey::mask_all();
        let keysym = unsafe {
            xlib::XKeycodeToKeysym(self.connection.display, event.keycode as c_uchar, 0)
        } as c_uint;
        let key = KeyCombo {
            mod_mask: mod_mask,
            keysym: keysym,
        };

        Some(Event::KeyPress(key))
    }

    fn on_enter_notify(&self, event: xlib::XEnterWindowEvent) -> Option<Event> {
        Some(Event::EnterNotify(WindowId(event.window)))
    }
}
<commit_msg>Log unhandled events.<commit_after>use std;
use std::ffi;
use std::fmt;
use std::os::raw::{c_char, c_int, c_long, c_uchar, c_uint, c_ulong, c_void};
use std::ptr;
use std::slice;

use x11::xlib;

use debug;
use keys::{KeyCombo, KeyHandlers, ModKey};

/// A handle to an X Window.
#[derive(Debug, PartialEq)]
pub struct WindowId(xlib::Window);

impl WindowId {
    fn to_x(&self) -> xlib::Window {
        self.0
    }
}

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

#[allow(non_snake_case)]
struct InternedAtoms {
    WM_DELETE_WINDOW: xlib::Atom,
    WM_PROTOCOLS: xlib::Atom,
}

pub struct Connection {
    display: *mut xlib::Display,
    root: WindowId,
    atoms: InternedAtoms,
}

// TODO: Implement Drop so that we can call XCloseDisplay?

impl Connection {
    /// Opens a connection to the X server, returning a new Connection object.
    pub fn connect() -> Result<Connection, String> {
        let (display, root) = unsafe {
            let display: *mut xlib::Display = xlib::XOpenDisplay(ptr::null_mut());
            let root: xlib::Window = xlib::XDefaultRootWindow(display);
            (display, root)
        };

        if display.is_null() {
            return Err("XOpenDisplay returned null pointer".to_owned());
        }
        if root == 0 {
            return Err("XDefaultRootWindow returned 0".to_owned());
        }

        Ok(Connection {
               display: display,
               root: WindowId(root),
               atoms: InternedAtoms {
                   WM_PROTOCOLS: Self::intern_atom(display, "WM_PROTOCOLS"),
                   WM_DELETE_WINDOW: Self::intern_atom(display, "WM_DELETE_WINDOW"),
               },
           })
    }

    /// Returns the Atom identifier associated with the atom_name str.
    fn intern_atom(display: *mut xlib::Display, atom_name: &str) -> xlib::Atom {
        // Note: the CString is bound to a variable to ensure adequate lifetime.
        let cstring = ffi::CString::new(atom_name).unwrap();
        let ptr = cstring.as_ptr() as *const c_char;
        unsafe { xlib::XInternAtom(display, ptr, 0) }
    }

    /// Installs the Connection as a window manager, by registers for
    /// SubstructureNotify and SubstructureRedirect events on the root window.
    /// If there is already a window manager on the display, then this will
    /// fail.
    pub fn install_as_wm(&self, key_handlers: &KeyHandlers) -> Result<(), String> {
        unsafe {
            // It's tricky to get state from the error handler to here, so we install a
            // special handler while becoming the WM that panics on error.
            xlib::XSetErrorHandler(Some(debug::error_handler_init));
            xlib::XSelectInput(self.display,
                               self.root.to_x(),
                               xlib::SubstructureNotifyMask | xlib::SubstructureRedirectMask);
            xlib::XSync(self.display, 0);

            // If we get this far, then our error handler didn't panic. Set a more useful
            // error handler.
            xlib::XSetErrorHandler(Some(debug::error_handler));
        }

        self.enable_window_key_events(&self.root, key_handlers);

        Ok(())
    }

    /// Returns the ID of the root window.
    pub fn root_window_id(&self) -> &WindowId {
        &self.root
    }

    pub fn top_level_windows(&self) -> Vec<WindowId> {
        let mut root: xlib::Window = 0;
        let mut parent: xlib::Window = 0;
        let mut children: *mut xlib::Window = ptr::null_mut();
        let mut num_children: c_uint = 0;
        unsafe {
            xlib::XQueryTree(self.display,
                             self.root.to_x(),
                             &mut root,
                             &mut parent,
                             &mut children,
                             &mut num_children);
        }

        if children.is_null() || num_children == 0 {
            return vec![];
        }

        let slice = unsafe { slice::from_raw_parts(children, num_children as usize) };
        let vec: Vec<WindowId> = slice.iter().map(|id| WindowId(*id)).collect();

        unsafe {
            xlib::XFree(children as *mut c_void);
        }

        vec
    }

    /// Queries the WM_PROTOCOLS property of a window, returning a list of the
    /// protocols that it supports.
    // TODO: Have this return a list of atoms, rather than a list of strings.
    // (Perhaps we should
    // have a separate function to convert to a list of strings for debugging?)
    pub fn get_wm_protocols(&self, window_id: &WindowId) -> Vec<String> {
        let mut atoms: *mut c_ulong = ptr::null_mut();
        let mut count: c_int = 0;
        unsafe {
            xlib::XGetWMProtocols(self.display, window_id.to_x(), &mut atoms, &mut count);
        }

        if atoms.is_null() {
            error!("XGetWMProtocols returned null pointer");
            return Vec::new();
        }
        if count == 0 {
            return Vec::new();
        }

        let mut pointers: Vec<*mut c_char> = Vec::with_capacity(count as usize);
        let protocols: Vec<String> = unsafe {
            xlib::XGetAtomNames(self.display, atoms, count, pointers.as_mut_ptr());
            pointers.set_len(count as usize);
            pointers
                .iter()
                .map(|buffer| {
                         ffi::CStr::from_ptr(*buffer)
                             .to_str()
                             .unwrap()
                             .to_owned()
                     })
                .collect()
        };

        unsafe {
            for pointer in pointers.iter() {
                xlib::XFree(*pointer as *mut c_void);
            }
            xlib::XFree(atoms as *mut c_void);
        }

        protocols
    }

    // TODO: This, as it'd make the WM_DELETE_WINDOW code a little clearer.
    // pub fn supports_protocol(&self, window_id, WindowId, atom: Atom) -> bool;

    /// Closes a window.
    ///
    /// The window will be closed gracefully using the ICCCM WM_DELETE_WINDOW
    /// protocol if it is supported.
    pub fn close_window(&self, window_id: &WindowId) {
        let protocols = self.get_wm_protocols(window_id);
        let has_wm_delete_window = protocols.contains(&"WM_DELETE_WINDOW".to_owned());

        // TODO: Use XDestroyWindow to forcefully close windows that do not support
        // WM_DELETE_WINDOW.
        if !has_wm_delete_window {
            panic!("Not implemented: closing windows that don't expose WM_DELETE_WINDOW");
        }

        let mut client_message = xlib::XClientMessageEvent {
            type_: xlib::ClientMessage,
            serial: 0,
            send_event: 0,
            display: ptr::null_mut(),
            window: window_id.to_x(),
            message_type: self.atoms.WM_PROTOCOLS,
            format: 32,
            data: xlib::ClientMessageData::new(),
        };
        client_message
            .data
            .set_long(0, self.atoms.WM_DELETE_WINDOW as c_long);
        client_message
            .data
            .set_long(1, xlib::CurrentTime as c_long);
        let mut event = xlib::XEvent::from(client_message);
        unsafe {
            xlib::XSendEvent(self.display,
                             window_id.to_x(),
                             0,
                             xlib::NoEventMask,
                             &mut event);
        }
    }

    /// Sets the window's position and size.
    pub fn configure_window(&self, window_id: &WindowId, x: i32, y: i32, width: i32, height: i32) {
        let mut changes = xlib::XWindowChanges {
            x: x,
            y: y,
            width: width,
            height: height,

            // Ignored:
            border_width: 0,
            sibling: 0,
            stack_mode: 0,
        };
        let flags = xlib::CWX | xlib::CWY | xlib::CWWidth | xlib::CWHeight;

        unsafe {
            xlib::XConfigureWindow(self.display, window_id.to_x(), flags as u32, &mut changes);
        };
    }

    /// Get's the window's width and height.
    pub fn get_window_geometry(&self, window_id: &WindowId) -> (i32, i32) {
        unsafe {
            let mut attrs: xlib::XWindowAttributes = std::mem::zeroed();
            xlib::XGetWindowAttributes(self.display, window_id.to_x(), &mut attrs);

            (attrs.width, attrs.height)
        }
    }

    /// Map a window.
    pub fn map_window(&self, window_id: &WindowId) {
        unsafe {
            xlib::XMapWindow(self.display, window_id.to_x());
        }
    }

    /// Unmap a window.
    pub fn unmap_window(&self, window_id: &WindowId) {
        unsafe {
            xlib::XUnmapWindow(self.display, window_id.to_x());
        }
    }

    /// Registers for key events.
    pub fn enable_window_key_events(&self, window_id: &WindowId, key_handlers: &KeyHandlers) {
        unsafe {
            for key in key_handlers.key_combos() {
                let keycode = xlib::XKeysymToKeycode(self.display, key.keysym as u64) as i32;
                xlib::XGrabKey(self.display,
                               keycode,
                               key.mod_mask,
                               window_id.to_x(),
                               0,
                               xlib::GrabModeAsync,
                               xlib::GrabModeAsync);
            }
        }
    }

    pub fn enable_window_focus_tracking(&self, window_id: &WindowId) {
        unsafe {
            xlib::XSelectInput(self.display, window_id.to_x(), xlib::EnterWindowMask);
        }
    }

    pub fn disable_window_focus_tracking(&self, window_id: &WindowId) {
        unsafe {
            xlib::XSelectInput(self.display, window_id.to_x(), 0);
        }
    }

    pub fn focus_window(&self, window_id: &WindowId) {
        self.map_window(&window_id);
        unsafe {
            xlib::XSetInputFocus(self.display,
                                 window_id.to_x(),
                                 xlib::RevertToPointerRoot,
                                 xlib::CurrentTime);
            // TODO: _NET_ACTIVE_WINDOW
        }
    }

    pub fn get_event_loop(&self) -> EventLoop {
        EventLoop { connection: &self }
    }
}

/// Events received from the `EventLoop`.
pub enum Event {
    MapRequest(WindowId),
    DestroyNotify(WindowId),
    KeyPress(KeyCombo),
    EnterNotify(WindowId),
}

/// An iterator that yields events from the X event loop.
///
/// Use `Connection::get_event_loop()` to get one.
pub struct EventLoop<'a> {
    connection: &'a Connection,
}

impl<'a> Iterator for EventLoop<'a> {
    type Item = Event;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            unsafe {
                let mut event = std::mem::zeroed();
                xlib::XNextEvent(self.connection.display, &mut event);

                let event = match event.get_type() {
                    xlib::ConfigureRequest => {
                        self.on_configure_request(xlib::XConfigureRequestEvent::from(event))
                    }
                    // TODO: move most of these handlers up to the window manager. The
                    // only one that out to stay here is the ConfigureRequest, as we're
                    // not going to do much with it!
                    xlib::MapRequest => self.on_map_request(xlib::XMapRequestEvent::from(event)),
                    xlib::DestroyNotify => {
                        self.on_destroy_notify(xlib::XDestroyWindowEvent::from(event))
                    }
                    xlib::KeyPress => self.on_key_press(xlib::XKeyPressedEvent::from(event)),
                    xlib::EnterNotify => self.on_enter_notify(xlib::XEnterWindowEvent::from(event)),
                    _ => {
                        debug!("Unhandled event: {}", debug::xevent_to_str(&event));
                        None
                    }
                };

                if let Some(event) = event {
                    return Some(event);
                }
            }
        }
    }
}

impl<'a> EventLoop<'a> {
    fn on_configure_request(&self, event: xlib::XConfigureRequestEvent) -> Option<Event> {
        // This request is not interesting for us: grant it unchanged.
        let mut changes = xlib::XWindowChanges {
            x: event.x,
            y: event.y,
            width: event.width,
            height: event.height,
            border_width: event.border_width,
            sibling: event.above,
            stack_mode: event.detail,
        };

        unsafe {
            xlib::XConfigureWindow(self.connection.display,
                                   event.window,
                                   event.value_mask as u32,
                                   &mut changes);
        }

        // There's no value in propogating this event.
        None
    }

    fn on_map_request(&self, event: xlib::XMapRequestEvent) -> Option<Event> {
        Some(Event::MapRequest(WindowId(event.window)))
    }

    fn on_destroy_notify(&self, event: xlib::XDestroyWindowEvent) -> Option<Event> {
        Some(Event::DestroyNotify(WindowId(event.window)))
    }

    fn on_key_press(&self, event: xlib::XKeyPressedEvent) -> Option<Event> {
        let mod_mask = event.state & ModKey::mask_all();
        let keysym = unsafe {
            xlib::XKeycodeToKeysym(self.connection.display, event.keycode as c_uchar, 0)
        } as c_uint;
        let key = KeyCombo {
            mod_mask: mod_mask,
            keysym: keysym,
        };

        Some(Event::KeyPress(key))
    }

    fn on_enter_notify(&self, event: xlib::XEnterWindowEvent) -> Option<Event> {
        Some(Event::EnterNotify(WindowId(event.window)))
    }
}
<|endoftext|>


<commit_before>//
//  SOS: the Stupid Operating System
//  by Eliza Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015-2017 Eliza Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
use super::{ElfResult, ElfWord, Section, section};
use super::ValidatesWord;
use core::{fmt, mem};

pub trait Header {
    type Word: ElfWord;

    /// Attempt to extract an ELF file header from a slice of bytes.
    /// TODO: should this be a From impl maybe?
    //          - eliza, 03/08/2017
    fn from_slice<'a>(input: &'a [u8]) -> ElfResult<&'a Self>;

    /// Attempt to extract a section header from a slice of bytes.
    /// TODO: can/should the index be `usize`?
    //          - eliza, 03/08/2017
    fn parse_section<'a>(&'a self, input: &'a [u8], idx: u16)
                            -> ElfResult<&'a Section>;

    // Field accessors -------------------------------------------
    fn ident(&self) -> Ident;
    fn get_type(&self) -> Type;
    fn machine(&self) -> Machine;
    /// Offset of the program entry point
    fn entry_point(&self) -> usize;
    /// Offset of the start of program headers
    fn ph_offset(&self) -> usize;
    /// Number of program headers.
    fn ph_count(&self) -> usize;
    /// Size of a program header.
    /// TODO: add function for using this and `ph_count` to make a memrange
    ///       representing the program header entries?
    //          - eliza, 03/08/2017
    fn ph_entry_size(&self) -> usize;
    /// Offset of the start of [section header]s.
    ///
    /// [section header]: ../section/struct.Header.html
    fn sh_offset(&self) -> usize;
    /// Number of [section header]s.
    ///
    /// [section header]: ../section/struct.Header.html
    fn sh_count(&self) -> usize;
    /// Size of a [section header].
    ///
    /// [section header]: ../section/struct.Header.html
    /// TODO: add function for using this and `sh_count` to make a memrange
    ///       representing the section header entries?
    //          - eliza, 03/08/2017
    fn sh_entry_size(&self) -> usize;
    /// TODO: can this return the flags type?
    //          - eliza, 03/08/2017
    fn flags(&self) -> u32;
    /// Index of the section header [string table].
    ///
    /// [string table]: ../section/struct.StrTable.html"]
    fn sh_str_idx(&self) -> usize;

}

/// FIXME(style): generate more stuff with macros/use `macro_attr` to derive
///               these...
//                  - eliza, 03/08/2017
macro_rules! impl_getters {
    ($(#[$attr:meta])* pub fn $name:ident(&self) -> $ty:ident; $($rest:tt)*) => {
        $(#[$attr])* #[inline] pub fn $name(&self) -> $ty { self.$name as $ty }
        impl_getters!{ $( $rest )* }
    };
    ($(#[$attr:meta])* fn $name:ident(&self) -> $ty:ident; $($rest:tt)*) => {
        $(#[$attr])* #[inline] fn $name(&self) -> $ty { self.$name as $ty }
        impl_getters!{ $( $rest )* }
    };
    ( $(#[$attr:meta])* pub fn $name: ident (&self)-> $ty: ident; ) => {
        $(#[$attr])* #[inline] pub fn $name(&self) -> $ty { self.$name as $ty }
    };
    ( $(#[$attr:meta])* fn $name: ident (&self)-> $ty: ident; ) => {
        $(#[$attr])* #[inline] fn $name(&self) -> $ty { self.$name as $ty }
    };
    () => {};
}

macro_rules! Header {
    (($($size:ty),+) $(pub)* enum $name:ident $($tail:tt)* ) => {
        Header! { @impl $name, $($size)+ }
    };
    (($($size:ty),+) $(pub)* struct $name:ident $($tail:tt)*) => {
        Header! { @impl $name, $($size)+ }
    };
    (@impl $name:ident, $($size:ty)+) => {
        $(impl Header for $name<$size> {
            type Word = $size;
            /// Attempt to extract an ELF file header from a slice of bytes.
            fn from_slice<'a>(input: &'a [u8]) -> ElfResult<&'a Self> {
                if input.len() < mem::size_of::<Self>() {
                    Err("Input too short to extract ELF header")
                } else {
                    unsafe { Ok(&super::extract_from_slice::<Self>(input, 0, 1)[0]) }
                }
            }

            /// Attempt to extract a section header from a slice of bytes.
            fn parse_section<'a>(&'a self, input: &'a [u8], idx: u16)
                                    -> ElfResult<&'a Section>
            {
                if idx < section::SHN_LORESERVE {
                    Err("Cannot parse reserved section.")
                } else {
                    // use ValidatesWord to check if this section's Class field
                    // will let us interpret the section with the requested
                    // word length. this is a bit of a hack around the type
                    // system not letting me do this the way I wanted to to....
                    let validator: &ValidatesWord<Self::Word>
                        = &self.ident.class;
                    validator.check()?;

                    // start offset for section
                    let start = self.sh_offset() + idx as usize *
                                self.sh_entry_size();
                    // end offset for section
                    let end = start + self.sh_entry_size();
                    let raw = &input[start .. end];

                    unsafe {
                        Ok(&*(raw as *const [u8]
                                  as *const _
                                  as *const Section))
                    }
                }
            }

            #[inline] fn get_type(&self) -> Type { self.elftype.as_type() }

            impl_getters! {
                #[doc = "Index for the start of [section header]s. \
                         [section header]: ../section/struct.Header.html"]
                fn sh_offset(&self) -> usize;
                fn sh_entry_size(&self) -> usize;
                fn sh_count(&self) -> usize;

                #[doc = "Index for the start of program headers"]
                fn ph_offset(&self) -> usize;
                fn ph_entry_size(&self) -> usize;
                fn ph_count(&self) -> usize;

                #[doc = "Index for the program entry point"]
                fn entry_point(&self) -> usize;
                #[doc = "Index of the section header [string table] \
                         [string table]: ../section/struct.StrTable.html"]
                fn sh_str_idx(&self) -> usize;
                fn flags(&self) -> u32;
                fn ident(&self) -> Ident;
                fn machine(&self) -> Machine;
            }
        })+
    }
}

macro_attr! {
    /// An ELF file header
    #[derive(Copy, Clone, Debug, Header!(u32, u64))]
    #[repr(C, packed)]
    pub struct HeaderRepr<W: ElfWord> {
        /// the ELF [file identifier](struct.Ident.html)
        pub ident: Ident
      , elftype: TypeRepr
      , pub machine: Machine
      , /// Program entry point
        entry_point: W
      , /// Offset for start of program headers
        ph_offset: W
      , /// Offset for start of [section header]s.
        /// [section header]: ../section/struct.Header.html
        sh_offset: W
      , pub flags: u32
      , pub header_size: u16
      , pub ph_entry_size: u16
      , pub ph_count: u16
      , pub sh_entry_size: u16
      , pub sh_count: u16
      , /// Index of the section header string table
        sh_str_idx: u16
    }
}

/// ELF header magic
pub const MAGIC: Magic = [0x7f, b'E', b'L', b'F'];

/// Type of header magic
pub type Magic = [u8; 4];

/// ELF identifier (`e_ident` in the ELF standard)
#[derive(Copy, Clone, Debug)]
#[repr(C, packed)]
pub struct Ident {
    /// ELF magic numbers. Must be equal to the [ELF magic], `[0x7, E, L, F]`.
    ///
    /// [ELF magic]: constant.MAGIC.html
    pub magic: Magic
  , /// ELF [file class](enum.Class.html) (32- or 64-bit)
    pub class: Class
  , /// ELF [data encoding](enum.DataEncoding.html) (big- or little-endian)
    pub encoding: DataEncoding
  , /// ELF file [version](enum.Version.html)
    pub version: Version
  , /// What [operating system ABI] this file was compiled for.
    ///
    /// [operating system ABI]: enum.OsAbi.html
    pub abi: OsAbi
  , /// ABI version (often this is just padding)
    pub abi_version: u8
  , _padding: [u8; 7]
}

impl Ident {
    #[inline] pub fn check_magic(&self) -> bool { self.magic == MAGIC }

    /// Returns true if the identifier section identifies a valid ELF file.
    #[inline] pub fn is_valid(&self) -> bool {
        // the ELF magic number is correct
        self.check_magic() &&
        // the file class is either 32- or 64-bits
        self.class.is_valid() &&
        // the data encoding is either big- or little-endian
        self.encoding.is_valid()
    }
}

/// Identifies the class of the ELF file
#[derive(Copy, Clone, PartialEq, Debug)]
#[repr(u8)]
pub enum Class {
    /// Invalid ELF class file (`ELFCLASSNONE` in the standard)
    None  = 0
  , /// 32-bit ELF file (`ELFCLASS32` in the standard)
    Elf32 = 1
  , /// 64-bit ELF file (`ELFCLASS64` in the standard)
    Elf64 = 2
}

impl Class {
    /// Returns true if the class field for this file is valid.
    #[inline]
    pub fn is_valid(&self) -> bool {
        match *self { Class::None => false
                    , _ => true
                    }
    }

}

impl ValidatesWord<u64> for Class {
    #[inline]
    fn check(&self) -> ElfResult<()> {
        use self::Class::*;
        match *self {
            None => Err("Invalid ELF type ELFCLASSNONE!")
          , Elf32 => Err("Cannot extract 64-bit section from 32-bit ELF")
          , Elf64 => Ok(())
        }
    }
}

impl ValidatesWord<u32> for Class {
    #[inline]
    fn check(&self) -> ElfResult<()> {
        use self::Class::*;
        match *self {
            None => Err("Invalid ELF type ELFCLASSNONE!")
          , Elf64 =>
                // TODO: is this actually true?
                //          - eliza, 03/08/2017
                Err("Cannot extract 32-bit section from 64-bit ELF")
          , Elf32 => Ok(())
        }
    }
}

/// Identifies the data encoding of the ELF file
#[derive(Copy, Clone, PartialEq, Debug)]
#[repr(u8)]
pub enum DataEncoding {
    /// Invalid data encoding (`ELFDATANONE` in the standard)
    None  = 0
  , /// Twos-complement little-endian data encoding
    /// (`ELFDATA2LSB` in the standard)
    LittleEndian = 1
  , /// Twos-complement big-endian data encoding
    /// (`ELFDATA2MSB` in the standard)
    BigEndian = 2
}

impl DataEncoding {
    /// Returns true if the data encoding field for this file is valid.
    #[inline]
    pub fn is_valid(&self) -> bool {
        match *self { DataEncoding::None => false
                    , _ => true
                    }
    }
}

/// Operating system ABI
#[derive(Copy, Clone, Debug)]
#[repr(u8)]
pub enum OsAbi { /// Ox00 also represents "none"
                 SystemV = 0x00
               , HpUx    = 0x01
               , NetBsd  = 0x02
               , Linux   = 0x03
               , Solaris = 0x06
               , Aix     = 0x07
               , Irix    = 0x08
               , FreeBsd = 0x09
               , OpenBsd = 0x0C
               , OpenVms = 0x0D
               }

/// Identifies the version of the ELF file
#[derive(Copy, Clone, PartialEq, Debug)]
#[repr(u8)]
pub enum Version { None = 0, Current = 1 }

#[derive(Clone, Copy, PartialEq)]
struct TypeRepr(u16);

impl TypeRepr {
    pub fn as_type(&self) -> Type {
        match self.0 {
            0 => Type::None
          , 1 => Type::Relocatable
          , 2 => Type::Executable
          , 3 => Type::SharedObject
          , 4 => Type::Core
          , anything => Type::Other(anything)
        }
    }
}

impl fmt::Debug for TypeRepr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.as_type().fmt(f)
    }
}

#[derive(Clone, Copy, PartialEq, Debug)]
pub enum Type { None
              , Relocatable
              , Executable
              , SharedObject
              , Core
              , Other(u16)
              }

#[allow(non_camel_case_types)]
#[derive(Clone, Copy, PartialEq, Debug)]
#[repr(u16)]
pub enum Machine { None    = 0
                 , Sparc   = 0x02
                 , X86     = 0x03
                 , Mips    = 0x08
                 , PowerPc = 0x14
                 , Arm     = 0x28
                 , SuperH  = 0x2A
                 , Ia64    = 0x32
                 , X86_64  = 0x3E
                 , AArch64 = 0xB7
                 }
<commit_msg>docs(elf): improve ELF file header documentation<commit_after>//
//  SOS: the Stupid Operating System
//  by Eliza Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015-2017 Eliza Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! ELF file header
use super::{ElfResult, ElfWord, Section, section};
use super::ValidatesWord;
use core::{fmt, mem};

/// Trait representing an ELF File Header.
///
/// This trait allows [HeaderRepr] to provide a consistent API regardless
/// of whether the header section uses 32- or 64-bit [ELF word]s. A number of
/// field values in the header of various sizes are converted to `usize` by
/// this API so that they can be used as indices, etc.
///
/// For more information on ELF File Headers, refer to:
/// + the ELF [specification]
/// + the [OS Dev Wiki]
///
/// [ELF word]: ../type.ElfWord.html
/// [HeaderRepr]: struct.HeaderRepr.html
/// [specification](http://www.sco.com/developers/gabi/latest/ch4.eheader.html)
/// [OS Dev Wiki](http://wiki.osdev.org/ELF#Header)
pub trait Header {
    type Word: ElfWord;

    /// Attempt to extract an ELF file header from a slice of bytes.
    /// TODO: should this be a From impl maybe?
    //          - eliza, 03/08/2017
    fn from_slice<'a>(input: &'a [u8]) -> ElfResult<&'a Self>;

    /// Attempt to extract a section header from a slice of bytes.
    /// TODO: can/should the index be `usize`?
    //          - eliza, 03/08/2017
    fn parse_section<'a>(&'a self, input: &'a [u8], idx: u16)
                            -> ElfResult<&'a Section>;

    // Field accessors -------------------------------------------
    fn ident(&self) -> Ident;
    fn get_type(&self) -> Type;
    fn machine(&self) -> Machine;
    /// Offset of the program entry point
    fn entry_point(&self) -> usize;
    /// Offset of the start of program headers
    fn ph_offset(&self) -> usize;
    /// Number of program headers.
    fn ph_count(&self) -> usize;
    /// Size of a program header.
    /// TODO: add function for using this and `ph_count` to make a memrange
    ///       representing the program header entries?
    //          - eliza, 03/08/2017
    fn ph_entry_size(&self) -> usize;
    /// Offset of the start of [section header]s.
    ///
    /// [section header]: ../section/struct.Header.html
    fn sh_offset(&self) -> usize;
    /// Number of [section header]s.
    ///
    /// [section header]: ../section/struct.Header.html
    fn sh_count(&self) -> usize;
    /// Size of a [section header].
    ///
    /// [section header]: ../section/struct.Header.html
    /// TODO: add function for using this and `sh_count` to make a memrange
    ///       representing the section header entries?
    //          - eliza, 03/08/2017
    fn sh_entry_size(&self) -> usize;
    /// TODO: can this return the flags type?
    //          - eliza, 03/08/2017
    fn flags(&self) -> u32;
    /// Index of the section header [string table].
    ///
    /// [string table]: ../section/struct.StrTable.html"]
    fn sh_str_idx(&self) -> usize;

}

/// FIXME(style): generate more stuff with macros/use `macro_attr` to derive
///               these...
//                  - eliza, 03/08/2017
macro_rules! impl_getters {
    ($(#[$attr:meta])* pub fn $name:ident(&self) -> $ty:ident; $($rest:tt)*) => {
        $(#[$attr])* #[inline] pub fn $name(&self) -> $ty { self.$name as $ty }
        impl_getters!{ $( $rest )* }
    };
    ($(#[$attr:meta])* fn $name:ident(&self) -> $ty:ident; $($rest:tt)*) => {
        $(#[$attr])* #[inline] fn $name(&self) -> $ty { self.$name as $ty }
        impl_getters!{ $( $rest )* }
    };
    ( $(#[$attr:meta])* pub fn $name: ident (&self)-> $ty: ident; ) => {
        $(#[$attr])* #[inline] pub fn $name(&self) -> $ty { self.$name as $ty }
    };
    ( $(#[$attr:meta])* fn $name: ident (&self)-> $ty: ident; ) => {
        $(#[$attr])* #[inline] fn $name(&self) -> $ty { self.$name as $ty }
    };
    () => {};
}

macro_rules! Header {
    (($($size:ty),+) $(pub)* enum $name:ident $($tail:tt)* ) => {
        Header! { @impl $name, $($size)+ }
    };
    (($($size:ty),+) $(pub)* struct $name:ident $($tail:tt)*) => {
        Header! { @impl $name, $($size)+ }
    };
    (@impl $name:ident, $($size:ty)+) => {
        $(impl Header for $name<$size> {
            type Word = $size;
            /// Attempt to extract an ELF file header from a slice of bytes.
            fn from_slice<'a>(input: &'a [u8]) -> ElfResult<&'a Self> {
                if input.len() < mem::size_of::<Self>() {
                    Err("Input too short to extract ELF header")
                } else {
                    unsafe { Ok(&super::extract_from_slice::<Self>(input, 0, 1)[0]) }
                }
            }

            /// Attempt to extract a section header from a slice of bytes.
            fn parse_section<'a>(&'a self, input: &'a [u8], idx: u16)
                                    -> ElfResult<&'a Section>
            {
                if idx < section::SHN_LORESERVE {
                    Err("Cannot parse reserved section.")
                } else {
                    // use ValidatesWord to check if this section's Class field
                    // will let us interpret the section with the requested
                    // word length. this is a bit of a hack around the type
                    // system not letting me do this the way I wanted to to....
                    let validator: &ValidatesWord<Self::Word>
                        = &self.ident.class;
                    validator.check()?;

                    // start offset for section
                    let start = self.sh_offset() + idx as usize *
                                self.sh_entry_size();
                    // end offset for section
                    let end = start + self.sh_entry_size();
                    let raw = &input[start .. end];

                    unsafe {
                        Ok(&*(raw as *const [u8]
                                  as *const _
                                  as *const Section))
                    }
                }
            }

            #[inline] fn get_type(&self) -> Type { self.elftype.as_type() }

            impl_getters! {
                #[doc = "Index for the start of [section header]s. \
                         [section header]: ../section/struct.Header.html"]
                fn sh_offset(&self) -> usize;
                fn sh_entry_size(&self) -> usize;
                fn sh_count(&self) -> usize;

                #[doc = "Index for the start of program headers"]
                fn ph_offset(&self) -> usize;
                fn ph_entry_size(&self) -> usize;
                fn ph_count(&self) -> usize;

                #[doc = "Index for the program entry point"]
                fn entry_point(&self) -> usize;
                #[doc = "Index of the section header [string table] \
                         [string table]: ../section/struct.StrTable.html"]
                fn sh_str_idx(&self) -> usize;
                fn flags(&self) -> u32;
                fn ident(&self) -> Ident;
                fn machine(&self) -> Machine;
            }
        })+
    }
}

macro_attr! {
    /// Raw representation of an ELF file header.
    #[derive(Copy, Clone, Debug, Header!(u32, u64))]
    #[repr(C, packed)]
    pub struct HeaderRepr<W: ElfWord> {
        /// the ELF [file identifier](struct.Ident.html)
        pub ident: Ident
      , elftype: TypeRepr
      , pub machine: Machine
      , /// Program entry point
        entry_point: W
      , /// Offset for start of program headers
        ph_offset: W
      , /// Offset for start of [section header]s.
        /// [section header]: ../section/struct.Header.html
        sh_offset: W
      , pub flags: u32
      , pub header_size: u16
      , pub ph_entry_size: u16
      , pub ph_count: u16
      , pub sh_entry_size: u16
      , pub sh_count: u16
      , /// Index of the section header string table
        sh_str_idx: u16
    }
}

/// ELF header magic
pub const MAGIC: Magic = [0x7f, b'E', b'L', b'F'];

/// Type of header magic
pub type Magic = [u8; 4];

/// ELF identifier (`e_ident` in the ELF standard)
#[derive(Copy, Clone, Debug)]
#[repr(C, packed)]
pub struct Ident {
    /// ELF magic numbers. Must be equal to the [ELF magic], `[0x7, E, L, F]`.
    ///
    /// [ELF magic]: constant.MAGIC.html
    pub magic: Magic
  , /// ELF [file class](enum.Class.html) (32- or 64-bit)
    pub class: Class
  , /// ELF [data encoding](enum.DataEncoding.html) (big- or little-endian)
    pub encoding: DataEncoding
  , /// ELF file [version](enum.Version.html)
    pub version: Version
  , /// What [operating system ABI] this file was compiled for.
    ///
    /// [operating system ABI]: enum.OsAbi.html
    pub abi: OsAbi
  , /// ABI version (often this is just padding)
    pub abi_version: u8
  , _padding: [u8; 7]
}

impl Ident {
    #[inline] pub fn check_magic(&self) -> bool { self.magic == MAGIC }

    /// Returns true if the identifier section identifies a valid ELF file.
    #[inline] pub fn is_valid(&self) -> bool {
        // the ELF magic number is correct
        self.check_magic() &&
        // the file class is either 32- or 64-bits
        self.class.is_valid() &&
        // the data encoding is either big- or little-endian
        self.encoding.is_valid()
    }
}

/// Identifies the class of the ELF file
#[derive(Copy, Clone, PartialEq, Debug)]
#[repr(u8)]
pub enum Class {
    /// Invalid ELF class file (`ELFCLASSNONE` in the standard)
    None  = 0
  , /// 32-bit ELF file (`ELFCLASS32` in the standard)
    Elf32 = 1
  , /// 64-bit ELF file (`ELFCLASS64` in the standard)
    Elf64 = 2
}

impl Class {
    /// Returns true if the class field for this file is valid.
    #[inline]
    pub fn is_valid(&self) -> bool {
        match *self { Class::None => false
                    , _ => true
                    }
    }

}

impl ValidatesWord<u64> for Class {
    #[inline]
    fn check(&self) -> ElfResult<()> {
        use self::Class::*;
        match *self {
            None => Err("Invalid ELF type ELFCLASSNONE!")
          , Elf32 => Err("Cannot extract 64-bit section from 32-bit ELF")
          , Elf64 => Ok(())
        }
    }
}

impl ValidatesWord<u32> for Class {
    #[inline]
    fn check(&self) -> ElfResult<()> {
        use self::Class::*;
        match *self {
            None => Err("Invalid ELF type ELFCLASSNONE!")
          , Elf64 =>
                // TODO: is this actually true?
                //          - eliza, 03/08/2017
                Err("Cannot extract 32-bit section from 64-bit ELF")
          , Elf32 => Ok(())
        }
    }
}

/// Identifies the data encoding of the ELF file
#[derive(Copy, Clone, PartialEq, Debug)]
#[repr(u8)]
pub enum DataEncoding {
    /// Invalid data encoding (`ELFDATANONE` in the standard)
    None  = 0
  , /// Twos-complement little-endian data encoding
    /// (`ELFDATA2LSB` in the standard)
    LittleEndian = 1
  , /// Twos-complement big-endian data encoding
    /// (`ELFDATA2MSB` in the standard)
    BigEndian = 2
}

impl DataEncoding {
    /// Returns true if the data encoding field for this file is valid.
    #[inline]
    pub fn is_valid(&self) -> bool {
        match *self { DataEncoding::None => false
                    , _ => true
                    }
    }
}

/// Operating system ABI
#[derive(Copy, Clone, Debug)]
#[repr(u8)]
pub enum OsAbi { /// Ox00 also represents "none"
                 SystemV = 0x00
               , HpUx    = 0x01
               , NetBsd  = 0x02
               , Linux   = 0x03
               , Solaris = 0x06
               , Aix     = 0x07
               , Irix    = 0x08
               , FreeBsd = 0x09
               , OpenBsd = 0x0C
               , OpenVms = 0x0D
               }

/// Identifies the version of the ELF file
#[derive(Copy, Clone, PartialEq, Debug)]
#[repr(u8)]
pub enum Version { None = 0, Current = 1 }

#[derive(Clone, Copy, PartialEq)]
struct TypeRepr(u16);

impl TypeRepr {
    pub fn as_type(&self) -> Type {
        match self.0 {
            0 => Type::None
          , 1 => Type::Relocatable
          , 2 => Type::Executable
          , 3 => Type::SharedObject
          , 4 => Type::Core
          , anything => Type::Other(anything)
        }
    }
}

impl fmt::Debug for TypeRepr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.as_type().fmt(f)
    }
}

#[derive(Clone, Copy, PartialEq, Debug)]
pub enum Type { None
              , Relocatable
              , Executable
              , SharedObject
              , Core
              , Other(u16)
              }

#[allow(non_camel_case_types)]
#[derive(Clone, Copy, PartialEq, Debug)]
#[repr(u16)]
pub enum Machine { None    = 0
                 , Sparc   = 0x02
                 , X86     = 0x03
                 , Mips    = 0x08
                 , PowerPc = 0x14
                 , Arm     = 0x28
                 , SuperH  = 0x2A
                 , Ia64    = 0x32
                 , X86_64  = 0x3E
                 , AArch64 = 0xB7
                 }
<|endoftext|>


<commit_before>use super::*;
use core::iter::FromIterator;

#[derive(Clone, PartialEq, Copy)]
/// The type of the insert mode
pub enum InsertMode {
    /// Append text (after the cursor)
    Append,
    /// Insert text (before the cursor)
    Insert,
    /// Replace text (on the cursor)
    Replace,
}

#[derive(Clone, PartialEq, Copy)]
/// The insert options
pub struct InsertOptions {
    /// The mode type
    pub mode: InsertMode,
}

impl Editor {
    /// Insert text
    pub fn insert(&mut self, k: Key, InsertOptions { mode: mode }: InsertOptions) {
        let mut x = self.x();
        let mut y = self.y();
        match mode {
            InsertMode::Insert => match k {
                Key::Char('\n') => {
                    let ln = self.text[y].clone();
                    let (slice, _) = ln.as_slices();

                    let first_part = (&slice[..x]).clone();
                    let second_part = (&slice[x..]).clone();

                    self.text[y] = VecDeque::from_iter(first_part.iter().map(|x| *x));
                    self.text.insert(y + 1, VecDeque::from_iter(second_part.iter().map(|x| *x)));

                    self.goto_next();
                },
                Key::Escape => { // Escape key
                    self.cursor_mut().mode = Mode::Command(CommandMode::Normal);
                },
                Key::Backspace => { // Backspace
                    if self.x() != 0 || self.y() != 0 {
                        self.goto_previous();
                        self.delete();
                    }
                },
                Key::Char(c) => {
                    self.text[y].insert(x, c);
                    self.goto_next();
                }
                _ => {},
            },
            InsertMode::Replace => match k {
                Key::Char(c) => {
                    if x == self.text[y].len() {
                        self.goto_next();
                        x = self.x();
                        y = self.y();
                    }

                    if self.text.len() != y {
                        if self.text[y].len() == x {
                            self.goto_next();
                        } else {
                            self.text[y][x] = c;
                        }
                    }
                    self.goto_next();
                },
                _ => {},
            },
            _ => {},
        }
    }
}
<commit_msg>Add insert_str method<commit_after>use redox::*;
use super::*;
use core::iter::FromIterator;

#[derive(Clone, PartialEq, Copy)]
/// The type of the insert mode
pub enum InsertMode {
    /// Append text (after the cursor)
    Append,
    /// Insert text (before the cursor)
    Insert,
    /// Replace text (on the cursor)
    Replace,
}

#[derive(Clone, PartialEq, Copy)]
/// The insert options
pub struct InsertOptions {
    /// The mode type
    pub mode: InsertMode,
}

impl Editor {
    /// Insert text
    pub fn insert(&mut self, k: Key, InsertOptions { mode: mode }: InsertOptions) {
        let mut x = self.x();
        let mut y = self.y();
        match mode {
            InsertMode::Insert => match k {
                Key::Char('\n') => {
                    let ln = self.text[y].clone();
                    let (slice, _) = ln.as_slices();

                    let first_part = (&slice[..x]).clone();
                    let second_part = (&slice[x..]).clone();

                    self.text[y] = VecDeque::from_iter(first_part.iter().map(|x| *x));
                    self.text.insert(y + 1, VecDeque::from_iter(second_part.iter().map(|x| *x)));

                    self.goto_next();
                },
                Key::Escape => { // Escape key
                    self.cursor_mut().mode = Mode::Command(CommandMode::Normal);
                },
                Key::Backspace => { // Backspace
                    if self.x() != 0 || self.y() != 0 {
                        self.goto_previous();
                        self.delete();
                    }
                },
                Key::Char(c) => {
                    self.text[y].insert(x, c);
                    self.goto_next();
                }
                _ => {},
            },
            InsertMode::Replace => match k {
                Key::Char(c) => {
                    if x == self.text[y].len() {
                        self.goto_next();
                        x = self.x();
                        y = self.y();
                    }

                    if self.text.len() != y {
                        if self.text[y].len() == x {
                            self.goto_next();
                        } else {
                            self.text[y][x] = c;
                        }
                    }
                    self.goto_next();
                },
                _ => {},
            },
            _ => {},
        }
    }

    /// Insert a string
    pub fn insert_str(&mut self, txt: String, opt: InsertOptions) {
        for c in txt.chars() {
            self.insert(Key::Char(c), opt);
        }
    }

}
<|endoftext|>


<commit_before>use std::collections::HashSet;
use std::fmt;
use std::ptr;
use std::sync::Arc;

use crate::cpu::flush_icache;
use crate::dseg::DSeg;
use crate::gc::Address;
use crate::language::ty::SourceTypeArray;
use crate::os;
use crate::utils::GrowableVec;
use crate::vm::FctDefinitionId;
use crate::vm::VM;

use dora_parser::Position;

#[derive(Debug, Clone)]
pub enum CodeDescriptor {
    DoraFct(FctDefinitionId),
    CompileStub,
    TrapStub,
    AllocStub,
    VerifyStub,
    NativeStub(FctDefinitionId),
    DoraStub,
    GuardCheckStub,
    SafepointStub,
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct CodeId(usize);

impl CodeId {
    pub fn from(idx: usize) -> CodeId {
        CodeId(idx)
    }

    pub fn idx(self) -> usize {
        self.0
    }
}

impl From<usize> for CodeId {
    fn from(data: usize) -> CodeId {
        CodeId(data)
    }
}

impl GrowableVec<Code> {
    pub fn idx(&self, index: CodeId) -> Arc<Code> {
        self.idx_usize(index.0)
    }
}

pub struct Code {
    code_start: Address,
    code_end: Address,

    // pointer to beginning of function
    function_entry: Address,

    desc: CodeDescriptor,

    framesize: i32,
    lazy_compilation: LazyCompilationData,
    gcpoints: GcPointTable,
    comments: CommentTable,
    positions: PositionTable,
}

impl Code {
    pub fn from_optimized_buffer(vm: &VM, buffer: &[u8], desc: CodeDescriptor) -> Code {
        let dseg = DSeg::new();

        Code::from_buffer(
            vm,
            &dseg,
            buffer,
            LazyCompilationData::new(),
            GcPointTable::new(),
            0,
            CommentTable::new(),
            PositionTable::new(),
            desc,
        )
    }

    pub fn from_buffer(
        vm: &VM,
        dseg: &DSeg,
        buffer: &[u8],
        lazy_compilation: LazyCompilationData,
        gcpoints: GcPointTable,
        framesize: i32,
        comments: CommentTable,
        positions: PositionTable,
        desc: CodeDescriptor,
    ) -> Code {
        let code_space_size = dseg.size() as usize + buffer.len();
        let code_start = vm.gc.alloc_code(code_space_size);
        let code_end = code_start.offset(code_space_size);

        if code_start.is_null() {
            panic!("out of memory: not enough executable memory left!");
        }

        os::jit_writable();

        dseg.finish(code_start.to_ptr());

        let function_entry = code_start.offset(dseg.size() as usize);

        unsafe {
            ptr::copy_nonoverlapping(buffer.as_ptr(), function_entry.to_mut_ptr(), buffer.len());
        }

        os::jit_executable();

        flush_icache(code_start.to_ptr(), code_space_size);

        Code {
            code_start,
            code_end,
            function_entry,
            desc,
            lazy_compilation,
            gcpoints,
            comments,
            framesize,
            positions,
        }
    }

    pub fn position_for_offset(&self, offset: u32) -> Option<Position> {
        self.positions.get(offset)
    }

    pub fn gcpoint_for_offset(&self, offset: u32) -> Option<&GcPoint> {
        self.gcpoints.get(offset)
    }

    pub fn ptr_start(&self) -> Address {
        self.code_start
    }

    pub fn ptr_end(&self) -> Address {
        self.code_end
    }

    pub fn fct_id(&self) -> FctDefinitionId {
        match self.desc {
            CodeDescriptor::NativeStub(fct_id) => fct_id,
            CodeDescriptor::DoraFct(fct_id) => fct_id,
            _ => panic!("no fctid found"),
        }
    }

    pub fn instruction_start(&self) -> Address {
        self.function_entry
    }

    pub fn instruction_end(&self) -> Address {
        self.code_end
    }

    pub fn framesize(&self) -> i32 {
        self.framesize
    }

    pub fn comment_for_offset(&self, offset: u32) -> Option<&String> {
        self.comments.get(offset)
    }

    pub fn lazy_for_offset(&self, offset: u32) -> Option<&LazyCompilationSite> {
        self.lazy_compilation.get(offset)
    }

    pub fn descriptor(&self) -> CodeDescriptor {
        self.desc.clone()
    }
}

impl fmt::Debug for Code {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "Code {{ start: {:?}, end: {:?}, desc: {:?} }}",
            self.ptr_start(),
            self.ptr_end(),
            self.desc,
        )
    }
}

#[derive(Debug)]
pub struct GcPointTable {
    entries: Vec<(u32, GcPoint)>,
}

impl GcPointTable {
    pub fn new() -> GcPointTable {
        GcPointTable {
            entries: Vec::new(),
        }
    }

    pub fn get(&self, offset: u32) -> Option<&GcPoint> {
        let result = self
            .entries
            .binary_search_by_key(&offset, |&(offset, _)| offset);

        match result {
            Ok(idx) => Some(&self.entries[idx].1),
            Err(_) => None,
        }
    }

    pub fn insert(&mut self, offset: u32, gcpoint: GcPoint) {
        if let Some(last) = self.entries.last_mut() {
            debug_assert!(offset > last.0);
        }

        self.entries.push((offset, gcpoint));
    }
}

#[derive(Debug)]
pub struct GcPoint {
    pub offsets: Vec<i32>,
}

impl GcPoint {
    pub fn new() -> GcPoint {
        GcPoint {
            offsets: Vec::new(),
        }
    }

    pub fn merge(lhs: GcPoint, rhs: GcPoint) -> GcPoint {
        let mut offsets = HashSet::new();

        for offset in lhs.offsets {
            offsets.insert(offset);
        }

        for offset in rhs.offsets {
            offsets.insert(offset);
        }

        GcPoint::from_offsets(offsets.drain().collect())
    }

    pub fn from_offsets(offsets: Vec<i32>) -> GcPoint {
        GcPoint { offsets }
    }
}

pub struct CommentTable {
    entries: Vec<(u32, String)>,
}

impl CommentTable {
    pub fn new() -> CommentTable {
        CommentTable {
            entries: Vec::new(),
        }
    }

    pub fn get(&self, offset: u32) -> Option<&String> {
        let result = self
            .entries
            .binary_search_by_key(&offset, |&(offset, _)| offset);

        match result {
            Ok(idx) => Some(&self.entries[idx].1),
            Err(_) => None,
        }
    }

    pub fn insert(&mut self, offset: u32, comment: String) {
        if let Some(last) = self.entries.last_mut() {
            debug_assert!(offset >= last.0);
        }

        self.entries.push((offset, comment));
    }
}

#[derive(Debug)]
pub struct PositionTable {
    entries: Vec<(u32, Position)>,
}

impl PositionTable {
    pub fn new() -> PositionTable {
        PositionTable {
            entries: Vec::new(),
        }
    }

    pub fn insert(&mut self, offset: u32, position: Position) {
        if let Some(last) = self.entries.last() {
            debug_assert!(offset > last.0);
        }

        self.entries.push((offset, position));
    }

    pub fn get(&self, offset: u32) -> Option<Position> {
        let result = self
            .entries
            .binary_search_by_key(&offset, |&(offset, _)| offset);

        match result {
            Ok(idx) => Some(self.entries[idx].1),
            Err(_) => None,
        }
    }
}

#[derive(Debug)]
pub struct LazyCompilationData {
    entries: Vec<(u32, LazyCompilationSite)>,
}

impl LazyCompilationData {
    pub fn new() -> LazyCompilationData {
        LazyCompilationData {
            entries: Vec::new(),
        }
    }

    pub fn insert(&mut self, offset: u32, info: LazyCompilationSite) {
        if let Some(last) = self.entries.last() {
            debug_assert!(offset > last.0);
        }

        self.entries.push((offset, info));
    }

    pub fn get(&self, offset: u32) -> Option<&LazyCompilationSite> {
        let result = self
            .entries
            .binary_search_by_key(&offset, |&(offset, _)| offset);

        match result {
            Ok(idx) => Some(&self.entries[idx].1),
            Err(_) => None,
        }
    }
}

#[derive(Clone, Debug)]
pub enum LazyCompilationSite {
    Direct(FctDefinitionId, i32, SourceTypeArray),
    Virtual(bool, FctDefinitionId, u32, SourceTypeArray),
}
<commit_msg>reserve space for code object header<commit_after>use std::collections::HashSet;
use std::fmt;
use std::ptr;
use std::sync::Arc;

use crate::cpu::flush_icache;
use crate::dseg::DSeg;
use crate::gc::Address;
use crate::language::ty::SourceTypeArray;
use crate::mem;
use crate::os;
use crate::utils::GrowableVec;
use crate::vm::FctDefinitionId;
use crate::vm::VM;

use dora_parser::Position;

#[derive(Debug, Clone)]
pub enum CodeDescriptor {
    DoraFct(FctDefinitionId),
    CompileStub,
    TrapStub,
    AllocStub,
    VerifyStub,
    NativeStub(FctDefinitionId),
    DoraStub,
    GuardCheckStub,
    SafepointStub,
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct CodeId(usize);

impl CodeId {
    pub fn from(idx: usize) -> CodeId {
        CodeId(idx)
    }

    pub fn idx(self) -> usize {
        self.0
    }
}

impl From<usize> for CodeId {
    fn from(data: usize) -> CodeId {
        CodeId(data)
    }
}

impl GrowableVec<Code> {
    pub fn idx(&self, index: CodeId) -> Arc<Code> {
        self.idx_usize(index.0)
    }
}

pub struct Code {
    code_start: Address,
    code_end: Address,

    // pointer to beginning of function
    function_entry: Address,

    desc: CodeDescriptor,

    framesize: i32,
    lazy_compilation: LazyCompilationData,
    gcpoints: GcPointTable,
    comments: CommentTable,
    positions: PositionTable,
}

impl Code {
    pub fn from_optimized_buffer(vm: &VM, buffer: &[u8], desc: CodeDescriptor) -> Code {
        let dseg = DSeg::new();

        Code::from_buffer(
            vm,
            &dseg,
            buffer,
            LazyCompilationData::new(),
            GcPointTable::new(),
            0,
            CommentTable::new(),
            PositionTable::new(),
            desc,
        )
    }

    pub fn from_buffer(
        vm: &VM,
        dseg: &DSeg,
        buffer: &[u8],
        lazy_compilation: LazyCompilationData,
        gcpoints: GcPointTable,
        framesize: i32,
        comments: CommentTable,
        positions: PositionTable,
        desc: CodeDescriptor,
    ) -> Code {
        let code_object_header_size = mem::ptr_width_usize() * 4;
        let code_space_size = code_object_header_size + dseg.size() as usize + buffer.len();

        let code_start = vm.gc.alloc_code(code_space_size);

        let code_content_start = code_start.offset(code_object_header_size);
        let code_end = code_start.offset(code_space_size);

        if code_start.is_null() {
            panic!("out of memory: not enough executable memory left!");
        }

        os::jit_writable();

        dseg.finish(code_content_start.to_ptr());

        let function_entry = code_content_start.offset(dseg.size() as usize);

        unsafe {
            ptr::copy_nonoverlapping(buffer.as_ptr(), function_entry.to_mut_ptr(), buffer.len());
        }

        os::jit_executable();

        flush_icache(code_start.to_ptr(), code_space_size);

        Code {
            code_start,
            code_end,
            function_entry,
            desc,
            lazy_compilation,
            gcpoints,
            comments,
            framesize,
            positions,
        }
    }

    pub fn position_for_offset(&self, offset: u32) -> Option<Position> {
        self.positions.get(offset)
    }

    pub fn gcpoint_for_offset(&self, offset: u32) -> Option<&GcPoint> {
        self.gcpoints.get(offset)
    }

    pub fn ptr_start(&self) -> Address {
        self.code_start
    }

    pub fn ptr_end(&self) -> Address {
        self.code_end
    }

    pub fn fct_id(&self) -> FctDefinitionId {
        match self.desc {
            CodeDescriptor::NativeStub(fct_id) => fct_id,
            CodeDescriptor::DoraFct(fct_id) => fct_id,
            _ => panic!("no fctid found"),
        }
    }

    pub fn instruction_start(&self) -> Address {
        self.function_entry
    }

    pub fn instruction_end(&self) -> Address {
        self.code_end
    }

    pub fn framesize(&self) -> i32 {
        self.framesize
    }

    pub fn comment_for_offset(&self, offset: u32) -> Option<&String> {
        self.comments.get(offset)
    }

    pub fn lazy_for_offset(&self, offset: u32) -> Option<&LazyCompilationSite> {
        self.lazy_compilation.get(offset)
    }

    pub fn descriptor(&self) -> CodeDescriptor {
        self.desc.clone()
    }
}

impl fmt::Debug for Code {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "Code {{ start: {:?}, end: {:?}, desc: {:?} }}",
            self.ptr_start(),
            self.ptr_end(),
            self.desc,
        )
    }
}

#[derive(Debug)]
pub struct GcPointTable {
    entries: Vec<(u32, GcPoint)>,
}

impl GcPointTable {
    pub fn new() -> GcPointTable {
        GcPointTable {
            entries: Vec::new(),
        }
    }

    pub fn get(&self, offset: u32) -> Option<&GcPoint> {
        let result = self
            .entries
            .binary_search_by_key(&offset, |&(offset, _)| offset);

        match result {
            Ok(idx) => Some(&self.entries[idx].1),
            Err(_) => None,
        }
    }

    pub fn insert(&mut self, offset: u32, gcpoint: GcPoint) {
        if let Some(last) = self.entries.last_mut() {
            debug_assert!(offset > last.0);
        }

        self.entries.push((offset, gcpoint));
    }
}

#[derive(Debug)]
pub struct GcPoint {
    pub offsets: Vec<i32>,
}

impl GcPoint {
    pub fn new() -> GcPoint {
        GcPoint {
            offsets: Vec::new(),
        }
    }

    pub fn merge(lhs: GcPoint, rhs: GcPoint) -> GcPoint {
        let mut offsets = HashSet::new();

        for offset in lhs.offsets {
            offsets.insert(offset);
        }

        for offset in rhs.offsets {
            offsets.insert(offset);
        }

        GcPoint::from_offsets(offsets.drain().collect())
    }

    pub fn from_offsets(offsets: Vec<i32>) -> GcPoint {
        GcPoint { offsets }
    }
}

pub struct CommentTable {
    entries: Vec<(u32, String)>,
}

impl CommentTable {
    pub fn new() -> CommentTable {
        CommentTable {
            entries: Vec::new(),
        }
    }

    pub fn get(&self, offset: u32) -> Option<&String> {
        let result = self
            .entries
            .binary_search_by_key(&offset, |&(offset, _)| offset);

        match result {
            Ok(idx) => Some(&self.entries[idx].1),
            Err(_) => None,
        }
    }

    pub fn insert(&mut self, offset: u32, comment: String) {
        if let Some(last) = self.entries.last_mut() {
            debug_assert!(offset >= last.0);
        }

        self.entries.push((offset, comment));
    }
}

#[derive(Debug)]
pub struct PositionTable {
    entries: Vec<(u32, Position)>,
}

impl PositionTable {
    pub fn new() -> PositionTable {
        PositionTable {
            entries: Vec::new(),
        }
    }

    pub fn insert(&mut self, offset: u32, position: Position) {
        if let Some(last) = self.entries.last() {
            debug_assert!(offset > last.0);
        }

        self.entries.push((offset, position));
    }

    pub fn get(&self, offset: u32) -> Option<Position> {
        let result = self
            .entries
            .binary_search_by_key(&offset, |&(offset, _)| offset);

        match result {
            Ok(idx) => Some(self.entries[idx].1),
            Err(_) => None,
        }
    }
}

#[derive(Debug)]
pub struct LazyCompilationData {
    entries: Vec<(u32, LazyCompilationSite)>,
}

impl LazyCompilationData {
    pub fn new() -> LazyCompilationData {
        LazyCompilationData {
            entries: Vec::new(),
        }
    }

    pub fn insert(&mut self, offset: u32, info: LazyCompilationSite) {
        if let Some(last) = self.entries.last() {
            debug_assert!(offset > last.0);
        }

        self.entries.push((offset, info));
    }

    pub fn get(&self, offset: u32) -> Option<&LazyCompilationSite> {
        let result = self
            .entries
            .binary_search_by_key(&offset, |&(offset, _)| offset);

        match result {
            Ok(idx) => Some(&self.entries[idx].1),
            Err(_) => None,
        }
    }
}

#[derive(Clone, Debug)]
pub enum LazyCompilationSite {
    Direct(FctDefinitionId, i32, SourceTypeArray),
    Virtual(bool, FctDefinitionId, u32, SourceTypeArray),
}
<|endoftext|>


<commit_before>// Copyright 2017-2019 int08h LLC

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// for value_t_or_exit!()
#[macro_use]
extern crate clap;

use ring::rand;
use ring::rand::SecureRandom;

use byteorder::{LittleEndian, ReadBytesExt};

use chrono::offset::Utc;
use chrono::TimeZone;

use std::collections::HashMap;
use std::fs::File;
use std::io::Write;
use std::iter::Iterator;
use std::net::{SocketAddr, ToSocketAddrs, UdpSocket};

use clap::{App, Arg};
use roughenough::merkle::root_from_paths;
use roughenough::sign::Verifier;
use roughenough::{
    roughenough_version, RtMessage, Tag, CERTIFICATE_CONTEXT, SIGNED_RESPONSE_CONTEXT,
};

fn create_nonce() -> [u8; 64] {
    let rng = rand::SystemRandom::new();
    let mut nonce = [0u8; 64];
    rng.fill(&mut nonce).unwrap();

    nonce
}

fn make_request(nonce: &[u8]) -> Vec<u8> {
    let mut msg = RtMessage::new(1);
    msg.add_field(Tag::NONC, nonce).unwrap();
    msg.pad_to_kilobyte();

    msg.encode().unwrap()
}

fn receive_response(sock: &mut UdpSocket) -> RtMessage {
    let mut buf = [0; 744];
    let resp_len = sock.recv_from(&mut buf).unwrap().0;

    RtMessage::from_bytes(&buf[0..resp_len]).unwrap()
}

fn stress_test_forever(addr: &SocketAddr) -> ! {
    if !addr.ip().is_loopback() {
        panic!("Cannot use non-loopback address {} for stress testing", addr.ip());
    }

    println!("Stress testing!");

    let nonce = create_nonce();
    let socket = UdpSocket::bind("0.0.0.0:0").expect("Couldn't open UDP socket");
    let request = make_request(&nonce);
    loop {
        socket.send_to(&request, addr).unwrap();
    }
}

struct ResponseHandler {
    pub_key: Option<Vec<u8>>,
    msg: HashMap<Tag, Vec<u8>>,
    srep: HashMap<Tag, Vec<u8>>,
    cert: HashMap<Tag, Vec<u8>>,
    dele: HashMap<Tag, Vec<u8>>,
    nonce: [u8; 64],
}

struct ParsedResponse {
    verified: bool,
    midpoint: u64,
    radius: u32,
}

impl ResponseHandler {
    pub fn new(pub_key: Option<Vec<u8>>, response: RtMessage, nonce: [u8; 64]) -> ResponseHandler {
        let msg = response.into_hash_map();
        let srep = RtMessage::from_bytes(&msg[&Tag::SREP])
            .unwrap()
            .into_hash_map();
        let cert = RtMessage::from_bytes(&msg[&Tag::CERT])
            .unwrap()
            .into_hash_map();
        let dele = RtMessage::from_bytes(&cert[&Tag::DELE])
            .unwrap()
            .into_hash_map();

        ResponseHandler {
            pub_key,
            msg,
            srep,
            cert,
            dele,
            nonce,
        }
    }

    pub fn extract_time(&self) -> ParsedResponse {
        let midpoint = self.srep[&Tag::MIDP]
            .as_slice()
            .read_u64::<LittleEndian>()
            .unwrap();
        let radius = self.srep[&Tag::RADI]
            .as_slice()
            .read_u32::<LittleEndian>()
            .unwrap();

        let verified = if self.pub_key.is_some() {
            self.validate_dele();
            self.validate_srep();
            self.validate_merkle();
            self.validate_midpoint(midpoint);
            true
        } else {
            false
        };

        ParsedResponse {
            verified,
            midpoint,
            radius,
        }
    }

    fn validate_dele(&self) {
        let mut full_cert = Vec::from(CERTIFICATE_CONTEXT.as_bytes());
        full_cert.extend(&self.cert[&Tag::DELE]);

        assert!(
            self.validate_sig(
                self.pub_key.as_ref().unwrap(),
                &self.cert[&Tag::SIG],
                &full_cert
            ),
            "Invalid signature on DELE tag, response may not be authentic"
        );
    }

    fn validate_srep(&self) {
        let mut full_srep = Vec::from(SIGNED_RESPONSE_CONTEXT.as_bytes());
        full_srep.extend(&self.msg[&Tag::SREP]);

        assert!(
            self.validate_sig(&self.dele[&Tag::PUBK], &self.msg[&Tag::SIG], &full_srep),
            "Invalid signature on SREP tag, response may not be authentic"
        );
    }

    fn validate_merkle(&self) {
        let srep = RtMessage::from_bytes(&self.msg[&Tag::SREP])
            .unwrap()
            .into_hash_map();
        let index = self.msg[&Tag::INDX]
            .as_slice()
            .read_u32::<LittleEndian>()
            .unwrap();
        let paths = &self.msg[&Tag::PATH];

        let hash = root_from_paths(index as usize, &self.nonce, paths);

        assert_eq!(
            hash, srep[&Tag::ROOT],
            "Nonce is not present in the response's merkle tree"
        );
    }

    fn validate_midpoint(&self, midpoint: u64) {
        let mint = self.dele[&Tag::MINT]
            .as_slice()
            .read_u64::<LittleEndian>()
            .unwrap();
        let maxt = self.dele[&Tag::MAXT]
            .as_slice()
            .read_u64::<LittleEndian>()
            .unwrap();

        assert!(
            midpoint >= mint,
            "Response midpoint {} lies *before* delegation span ({}, {})",
            midpoint, mint, maxt
        );
        assert!(
            midpoint <= maxt,
            "Response midpoint {} lies *after* delegation span ({}, {})",
            midpoint, mint, maxt
        );
    }

    fn validate_sig(&self, public_key: &[u8], sig: &[u8], data: &[u8]) -> bool {
        let mut verifier = Verifier::new(public_key);
        verifier.update(data);
        verifier.verify(sig)
    }
}

fn main() {
    let matches = App::new("roughenough client")
    .version(roughenough_version().as_ref())
    .arg(Arg::with_name("host")
      .required(true)
      .help("The Roughtime server to connect to.")
      .takes_value(true))
    .arg(Arg::with_name("port")
      .required(true)
      .help("The Roughtime server port to connect to.")
      .takes_value(true))
    .arg(Arg::with_name("verbose")
      .short("v")
      .long("verbose")
      .help("Output additional details about the server's response."))
    .arg(Arg::with_name("json")
      .short("j")
      .long("json")
      .help("Output the server's response in JSON format."))
    .arg(Arg::with_name("public-key")
      .short("p")
      .long("public-key")
      .takes_value(true)
      .help("The server public key used to validate responses. If unset, no validation will be performed."))
    .arg(Arg::with_name("time-format")
      .short("f")
      .long("time-format")
      .takes_value(true)
      .help("The strftime format string used to print the time recieved from the server.")
      .default_value("%b %d %Y %H:%M:%S")
    )
    .arg(Arg::with_name("num-requests")
      .short("n")
      .long("num-requests")
      .takes_value(true)
      .help("The number of requests to make to the server (each from a different source port). This is mainly useful for testing batch response handling.")
      .default_value("1")
    )
    .arg(Arg::with_name("stress")
      .short("s")
      .long("stress")
      .help("Stress test the server by sending the same request as fast as possible. Please only use this on your own server.")
    )
    .arg(Arg::with_name("output")
      .short("o")
      .long("output")
      .takes_value(true)
      .help("Writes all requests to the specified file, in addition to sending them to the server. Useful for generating fuzzer inputs.")
    )
    .get_matches();

    let host = matches.value_of("host").unwrap();
    let port = value_t_or_exit!(matches.value_of("port"), u16);
    let verbose = matches.is_present("verbose");
    let json = matches.is_present("json");
    let num_requests = value_t_or_exit!(matches.value_of("num-requests"), u16) as usize;
    let time_format = matches.value_of("time-format").unwrap();
    let stress = matches.is_present("stress");
    let pub_key = matches
        .value_of("public-key")
        .map(|pkey| hex::decode(pkey).expect("Error parsing public key!"));
    let out = matches.value_of("output");

    if verbose {
        eprintln!("Requesting time from: {:?}:{:?}", host, port);
    }

    let addr = (host, port).to_socket_addrs().unwrap().next().unwrap();

    if stress {
        stress_test_forever(&addr)
    }

    let mut requests = Vec::with_capacity(num_requests);
    let mut file = out.map(|o| File::create(o).expect("Failed to create file!"));

    for _ in 0..num_requests {
        let nonce = create_nonce();
        let socket = UdpSocket::bind("0.0.0.0:0").expect("Couldn't open UDP socket");
        let request = make_request(&nonce);

        if let Some(f) = file.as_mut() {
            f.write_all(&request).expect("Failed to write to file!")
        }

        requests.push((nonce, request, socket));
    }

    for &mut (_, ref request, ref mut socket) in &mut requests {
        socket.send_to(request, addr).unwrap();
    }

    for (nonce, _, mut socket) in requests {
        let resp = receive_response(&mut socket);

        let ParsedResponse {
            verified,
            midpoint,
            radius,
        } = ResponseHandler::new(pub_key.clone(), resp.clone(), nonce).extract_time();

        let map = resp.into_hash_map();
        let index = map[&Tag::INDX]
            .as_slice()
            .read_u32::<LittleEndian>()
            .unwrap();

        let seconds = midpoint / 10_u64.pow(6);
        let nsecs = (midpoint - (seconds * 10_u64.pow(6))) * 10_u64.pow(3);
        let spec = Utc.timestamp(seconds as i64, nsecs as u32);
        let out = spec.format(time_format).to_string();
        let verify_str = if verified { "Yes" } else { "No" };

        if verbose {
            eprintln!(
                "Received time from server: midpoint={:?}, radius={:?}, verified={} (merkle_index={})",
                out, radius, verify_str, index
            );
        }

        if json {
            println!(
                r#"{{ "midpoint": {:?}, "radius": {:?}, "verified": {}, "merkle_index": {} }}"#,
                out, radius, verified, index
            );
        } else {
            println!("{}", out);
        }
    }
}

<commit_msg>client: output local time by default, add -z/--zulu for UTC<commit_after>// Copyright 2017-2019 int08h LLC

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// for value_t_or_exit!()
#[macro_use]
extern crate clap;

use ring::rand;
use ring::rand::SecureRandom;

use byteorder::{LittleEndian, ReadBytesExt};

use chrono::offset::Utc;
use chrono::{TimeZone, Local};

use std::collections::HashMap;
use std::fs::File;
use std::io::Write;
use std::iter::Iterator;
use std::net::{SocketAddr, ToSocketAddrs, UdpSocket};

use clap::{App, Arg};
use roughenough::merkle::root_from_paths;
use roughenough::sign::Verifier;
use roughenough::{
    roughenough_version, RtMessage, Tag, CERTIFICATE_CONTEXT, SIGNED_RESPONSE_CONTEXT,
};

fn create_nonce() -> [u8; 64] {
    let rng = rand::SystemRandom::new();
    let mut nonce = [0u8; 64];
    rng.fill(&mut nonce).unwrap();

    nonce
}

fn make_request(nonce: &[u8]) -> Vec<u8> {
    let mut msg = RtMessage::new(1);
    msg.add_field(Tag::NONC, nonce).unwrap();
    msg.pad_to_kilobyte();

    msg.encode().unwrap()
}

fn receive_response(sock: &mut UdpSocket) -> RtMessage {
    let mut buf = [0; 744];
    let resp_len = sock.recv_from(&mut buf).unwrap().0;

    RtMessage::from_bytes(&buf[0..resp_len]).unwrap()
}

fn stress_test_forever(addr: &SocketAddr) -> ! {
    if !addr.ip().is_loopback() {
        panic!("Cannot use non-loopback address {} for stress testing", addr.ip());
    }

    println!("Stress testing!");

    let nonce = create_nonce();
    let socket = UdpSocket::bind("0.0.0.0:0").expect("Couldn't open UDP socket");
    let request = make_request(&nonce);
    loop {
        socket.send_to(&request, addr).unwrap();
    }
}

struct ResponseHandler {
    pub_key: Option<Vec<u8>>,
    msg: HashMap<Tag, Vec<u8>>,
    srep: HashMap<Tag, Vec<u8>>,
    cert: HashMap<Tag, Vec<u8>>,
    dele: HashMap<Tag, Vec<u8>>,
    nonce: [u8; 64],
}

struct ParsedResponse {
    verified: bool,
    midpoint: u64,
    radius: u32,
}

impl ResponseHandler {
    pub fn new(pub_key: Option<Vec<u8>>, response: RtMessage, nonce: [u8; 64]) -> ResponseHandler {
        let msg = response.into_hash_map();
        let srep = RtMessage::from_bytes(&msg[&Tag::SREP])
            .unwrap()
            .into_hash_map();
        let cert = RtMessage::from_bytes(&msg[&Tag::CERT])
            .unwrap()
            .into_hash_map();
        let dele = RtMessage::from_bytes(&cert[&Tag::DELE])
            .unwrap()
            .into_hash_map();

        ResponseHandler {
            pub_key,
            msg,
            srep,
            cert,
            dele,
            nonce,
        }
    }

    pub fn extract_time(&self) -> ParsedResponse {
        let midpoint = self.srep[&Tag::MIDP]
            .as_slice()
            .read_u64::<LittleEndian>()
            .unwrap();
        let radius = self.srep[&Tag::RADI]
            .as_slice()
            .read_u32::<LittleEndian>()
            .unwrap();

        let verified = if self.pub_key.is_some() {
            self.validate_dele();
            self.validate_srep();
            self.validate_merkle();
            self.validate_midpoint(midpoint);
            true
        } else {
            false
        };

        ParsedResponse {
            verified,
            midpoint,
            radius,
        }
    }

    fn validate_dele(&self) {
        let mut full_cert = Vec::from(CERTIFICATE_CONTEXT.as_bytes());
        full_cert.extend(&self.cert[&Tag::DELE]);

        assert!(
            self.validate_sig(
                self.pub_key.as_ref().unwrap(),
                &self.cert[&Tag::SIG],
                &full_cert
            ),
            "Invalid signature on DELE tag, response may not be authentic"
        );
    }

    fn validate_srep(&self) {
        let mut full_srep = Vec::from(SIGNED_RESPONSE_CONTEXT.as_bytes());
        full_srep.extend(&self.msg[&Tag::SREP]);

        assert!(
            self.validate_sig(&self.dele[&Tag::PUBK], &self.msg[&Tag::SIG], &full_srep),
            "Invalid signature on SREP tag, response may not be authentic"
        );
    }

    fn validate_merkle(&self) {
        let srep = RtMessage::from_bytes(&self.msg[&Tag::SREP])
            .unwrap()
            .into_hash_map();
        let index = self.msg[&Tag::INDX]
            .as_slice()
            .read_u32::<LittleEndian>()
            .unwrap();
        let paths = &self.msg[&Tag::PATH];

        let hash = root_from_paths(index as usize, &self.nonce, paths);

        assert_eq!(
            hash, srep[&Tag::ROOT],
            "Nonce is not present in the response's merkle tree"
        );
    }

    fn validate_midpoint(&self, midpoint: u64) {
        let mint = self.dele[&Tag::MINT]
            .as_slice()
            .read_u64::<LittleEndian>()
            .unwrap();
        let maxt = self.dele[&Tag::MAXT]
            .as_slice()
            .read_u64::<LittleEndian>()
            .unwrap();

        assert!(
            midpoint >= mint,
            "Response midpoint {} lies *before* delegation span ({}, {})",
            midpoint, mint, maxt
        );
        assert!(
            midpoint <= maxt,
            "Response midpoint {} lies *after* delegation span ({}, {})",
            midpoint, mint, maxt
        );
    }

    fn validate_sig(&self, public_key: &[u8], sig: &[u8], data: &[u8]) -> bool {
        let mut verifier = Verifier::new(public_key);
        verifier.update(data);
        verifier.verify(sig)
    }
}

fn main() {
    let matches = App::new("roughenough client")
    .version(roughenough_version().as_ref())
    .arg(Arg::with_name("host")
      .required(true)
      .help("The Roughtime server to connect to.")
      .takes_value(true))
    .arg(Arg::with_name("port")
      .required(true)
      .help("The Roughtime server port to connect to.")
      .takes_value(true))
    .arg(Arg::with_name("verbose")
      .short("v")
      .long("verbose")
      .help("Output additional details about the server's response."))
    .arg(Arg::with_name("json")
      .short("j")
      .long("json")
      .help("Output the server's response in JSON format."))
    .arg(Arg::with_name("public-key")
      .short("p")
      .long("public-key")
      .takes_value(true)
      .help("The server public key used to validate responses. If unset, no validation will be performed."))
    .arg(Arg::with_name("time-format")
      .short("f")
      .long("time-format")
      .takes_value(true)
      .help("The strftime format string used to print the time recieved from the server.")
      .default_value("%b %d %Y %H:%M:%S %Z")
    )
    .arg(Arg::with_name("num-requests")
      .short("n")
      .long("num-requests")
      .takes_value(true)
      .help("The number of requests to make to the server (each from a different source port). This is mainly useful for testing batch response handling.")
      .default_value("1")
    )
    .arg(Arg::with_name("stress")
      .short("s")
      .long("stress")
      .help("Stress test the server by sending the same request as fast as possible. Please only use this on your own server.")
    )
    .arg(Arg::with_name("output")
      .short("o")
      .long("output")
      .takes_value(true)
      .help("Writes all requests to the specified file, in addition to sending them to the server. Useful for generating fuzzer inputs.")
    )
    .arg(Arg::with_name("zulu")
      .short("z")
      .long("zulu")
      .help("Display time in UTC (default is local time zone)")
    )
    .get_matches();

    let host = matches.value_of("host").unwrap();
    let port = value_t_or_exit!(matches.value_of("port"), u16);
    let verbose = matches.is_present("verbose");
    let json = matches.is_present("json");
    let num_requests = value_t_or_exit!(matches.value_of("num-requests"), u16) as usize;
    let time_format = matches.value_of("time-format").unwrap();
    let stress = matches.is_present("stress");
    let pub_key = matches
        .value_of("public-key")
        .map(|pkey| hex::decode(pkey).expect("Error parsing public key!"));
    let out = matches.value_of("output");
    let use_utc = matches.is_present("zulu");

    if verbose {
        eprintln!("Requesting time from: {:?}:{:?}", host, port);
    }

    let addr = (host, port).to_socket_addrs().unwrap().next().unwrap();

    if stress {
        stress_test_forever(&addr)
    }

    let mut requests = Vec::with_capacity(num_requests);
    let mut file = out.map(|o| File::create(o).expect("Failed to create file!"));

    for _ in 0..num_requests {
        let nonce = create_nonce();
        let socket = UdpSocket::bind("0.0.0.0:0").expect("Couldn't open UDP socket");
        let request = make_request(&nonce);

        if let Some(f) = file.as_mut() {
            f.write_all(&request).expect("Failed to write to file!")
        }

        requests.push((nonce, request, socket));
    }

    for &mut (_, ref request, ref mut socket) in &mut requests {
        socket.send_to(request, addr).unwrap();
    }

    for (nonce, _, mut socket) in requests {
        let resp = receive_response(&mut socket);

        let ParsedResponse {
            verified,
            midpoint,
            radius,
        } = ResponseHandler::new(pub_key.clone(), resp.clone(), nonce).extract_time();

        let map = resp.into_hash_map();
        let index = map[&Tag::INDX]
            .as_slice()
            .read_u32::<LittleEndian>()
            .unwrap();

        let seconds = midpoint / 10_u64.pow(6);
        let nsecs = (midpoint - (seconds * 10_u64.pow(6))) * 10_u64.pow(3);
        let verify_str = if verified { "Yes" } else { "No" };

        let out = if use_utc {
            let ts = Utc.timestamp(seconds as i64, nsecs as u32);
            ts.format(time_format).to_string()
        } else {
            let ts = Local.timestamp(seconds as i64, nsecs as u32);
            ts.format(time_format).to_string()
        };

        if verbose {
            eprintln!(
                "Received time from server: midpoint={:?}, radius={:?}, verified={} (merkle_index={})",
                out, radius, verify_str, index
            );
        }

        if json {
            println!(
                r#"{{ "midpoint": {:?}, "radius": {:?}, "verified": {}, "merkle_index": {} }}"#,
                out, radius, verified, index
            );
        } else {
            println!("{}", out);
        }
    }
}

<|endoftext|>


<commit_before>
/// Trait for fixed size arrays.
pub unsafe trait Array {
    /// The array's element type
    type Item;
    #[doc(hidden)]
    /// The smallest index type that indexes the array.
    type Index: Index;
    #[doc(hidden)]
    fn as_ptr(&self) -> *const Self::Item;
    #[doc(hidden)]
    fn as_mut_ptr(&mut self) -> *mut Self::Item;
    #[doc(hidden)]
    fn capacity() -> usize;
}

pub trait Index : PartialEq + Copy {
    fn zero() -> Self;
    fn to_usize(self) -> usize;
    fn from(usize) -> Self;
}

impl Index for u8 {
    fn zero() -> Self { 0 }
    fn to_usize(self) -> usize { self as usize }
    fn from(ix: usize) ->  Self { ix as u8 }
}

impl Index for u16 {
    fn zero() -> Self { 0 }
    fn to_usize(self) -> usize { self as usize }
    fn from(ix: usize) ->  Self { ix as u16 }
}

macro_rules! fix_array_impl {
    ($index_type:ty, $len:expr ) => (
        unsafe impl<T> Array for [T; $len] {
            type Item = T;
            type Index = $index_type;
            #[inline(always)]
            fn as_ptr(&self) -> *const T { self as *const _ as *const _ }
            #[inline(always)]
            fn as_mut_ptr(&mut self) -> *mut T { self as *mut _ as *mut _}
            #[inline(always)]
            fn capacity() -> usize { $len }
        }
    )
}

macro_rules! fix_array_impl_recursive {
    ($index_type:ty, ) => ();
    ($index_type:ty, $len:expr, $($more:expr,)*) => (
        fix_array_impl!($index_type, $len);
        fix_array_impl_recursive!($index_type, $($more,)*);
    );
}

fix_array_impl_recursive!(u8, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
                          16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
                          32, 40, 48, 56, 64, 72, 96, 128, 160, 192, 224,);
fix_array_impl_recursive!(u16, 256, 384, 512, 768, 1024, 2048, 4096, 8192, 16384, 32768,);

<commit_msg>Make sure methods in helper trait Index are inlined<commit_after>
/// Trait for fixed size arrays.
pub unsafe trait Array {
    /// The array's element type
    type Item;
    #[doc(hidden)]
    /// The smallest index type that indexes the array.
    type Index: Index;
    #[doc(hidden)]
    fn as_ptr(&self) -> *const Self::Item;
    #[doc(hidden)]
    fn as_mut_ptr(&mut self) -> *mut Self::Item;
    #[doc(hidden)]
    fn capacity() -> usize;
}

pub trait Index : PartialEq + Copy {
    fn zero() -> Self;
    fn to_usize(self) -> usize;
    fn from(usize) -> Self;
}

impl Index for u8 {
    #[inline(always)]
    fn zero() -> Self { 0 }
    #[inline(always)]
    fn to_usize(self) -> usize { self as usize }
    #[inline(always)]
    fn from(ix: usize) ->  Self { ix as u8 }
}

impl Index for u16 {
    #[inline(always)]
    fn zero() -> Self { 0 }
    #[inline(always)]
    fn to_usize(self) -> usize { self as usize }
    #[inline(always)]
    fn from(ix: usize) ->  Self { ix as u16 }
}

macro_rules! fix_array_impl {
    ($index_type:ty, $len:expr ) => (
        unsafe impl<T> Array for [T; $len] {
            type Item = T;
            type Index = $index_type;
            #[inline(always)]
            fn as_ptr(&self) -> *const T { self as *const _ as *const _ }
            #[inline(always)]
            fn as_mut_ptr(&mut self) -> *mut T { self as *mut _ as *mut _}
            #[inline(always)]
            fn capacity() -> usize { $len }
        }
    )
}

macro_rules! fix_array_impl_recursive {
    ($index_type:ty, ) => ();
    ($index_type:ty, $len:expr, $($more:expr,)*) => (
        fix_array_impl!($index_type, $len);
        fix_array_impl_recursive!($index_type, $($more,)*);
    );
}

fix_array_impl_recursive!(u8, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
                          16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
                          32, 40, 48, 56, 64, 72, 96, 128, 160, 192, 224,);
fix_array_impl_recursive!(u16, 256, 384, 512, 768, 1024, 2048, 4096, 8192, 16384, 32768,);

<|endoftext|>


<commit_before><commit_msg>Adding IpNet methods and some documentation.<commit_after><|endoftext|>


<commit_before><commit_msg>Add ASCII art to show axial coordinate system<commit_after><|endoftext|>