<commit_before>extern crate libc;

use std::ptr;
use std::mem;
use std::ffi;
use std::str;
use std::slice::from_raw_parts;
use std::string::String;
use std::collections::HashMap;
use std::boxed::Box;
use x11::xlib;
use x11::keysym;

use super::super::libx;

use super::config::Config;
use super::{ Workspace, Workspaces };
use super::handler;

unsafe extern fn error_handler(display: *mut xlib::Display, event: *mut xlib::XErrorEvent) -> libc::c_int {
    // match event.error_code {
    //     xlib::BadAtom => {
    //         println!("bad atom");
    //     }
    //     _ => {}
    // }
    1
}

pub struct WindowManager {
    pub context: libx::Context,
    pub screen_num: libc::c_int,
    pub root:    xlib::Window,

    pub workspaces: Workspaces,
    config: Config
}

impl WindowManager {
    pub fn new() -> WindowManager {
	let context = libx::open_display(None);
        let context = match context {
            Some(p) => {
                p
            }
            None => {
                panic!("can't open display")
            }
        };

	let screen_num  = libx::default_screen(context);
	let root = libx::root_window(context, screen_num);
        println!("root window {}", root);
	let mut wm = WindowManager {
            context: context,
            screen_num: screen_num,
	    root: root,

            config: Config::load(),
            workspaces: Workspaces::new()
        };
        wm.workspaces.create('1', screen_num);
        wm
    }

    pub fn clean(&mut self) {
        libx::close_display(self.context);
    }

    pub fn is_top_window(&self, window: xlib::Window) -> bool{
        let attrs = libx::get_window_attributes(self.context, window);
        let transientfor_hint = libx::get_transient_for_hint(self.context, window);
        attrs.override_redirect == 0 && transientfor_hint == 0
    }

    pub fn handle_create(&mut self, event: &xlib::XCreateWindowEvent) {
        if event.override_redirect != 0 {
            return;
        }

        let attrs = libx::get_window_attributes(self.context, event.window);

        // get window property
        let n = libx::get_text_property(self.context, event.window, xlib::XA_WM_NAME);
        match n {
            Some(s) => {debug!("create window {} for {}", event.window, s);}
            None => {}
        }

        // let atoms = libx::get_wm_protocols(self.context, event.window);
        // for a in atoms.iter() {
        //     println!("atom {}", a);
        //     let name = libx::get_atom_name(self.context, *a);
        //     match name {
        //         Some(n) => println!("name {}", n),
        //         None => println!("name {}", a),
        //     };
        // }
    }

    pub fn handle_destroy(&mut self, event: &xlib::XDestroyWindowEvent) {
        let workspace = self.workspaces.current();
        println!("current windows {}", workspace.size());
        match workspace.contain(event.window) {
            Some(index) => {
                println!("in workspace");
                workspace.remove(event.window);
                workspace.config(self.context);
            }
            None => { println!("not in workspace"); }
        }
    }

    pub fn handle_map_request(&mut self, event: &xlib::XMapRequestEvent) {
        libx::map_window(self.context, event.window);

        // add app top-level window to workspace
        let manage = self.is_top_window(event.window);
        if manage {
            debug!("top level window");
            let mut workspace = self.workspaces.current();
            if workspace.contain(event.window).is_none() {
                workspace.add(event.window);
                workspace.config(self.context);
            }

            libx::set_input_focus(self.context, event.window);

            let attrs = libx::get_window_attributes(self.context, event.window);
            println!("masks {}", attrs.all_event_masks);
            println!("mask button press {}", attrs.all_event_masks | xlib::ButtonPressMask);
            // change attributes before display
            unsafe{
                let mask = xlib::OwnerGrabButtonMask | xlib::KeyReleaseMask | xlib::PointerMotionHintMask | xlib::EnterWindowMask;
                // let mut attrs: xlib::XSetWindowAttributes = mem::zeroed();
                // attrs.event_mask = xlib::KeyReleaseMask | xlib::ButtonPressMask | xlib::ButtonReleaseMask | xlib::EnterWindowMask;
                // let valuemask = xlib::CWEventMask;
                // libx::change_window_attributes(self.context, event.window, valuemask, &mut attrs);
                libx::select_input(self.context, event.window, mask);
            }
        }
    }

    pub fn handle_client_message(&mut self, event: &xlib::XClientMessageEvent) {
        println!("message type {}", event.message_type);
        let s = libx::get_atom_name(self.context, event.message_type);
        match s {
            Some(v) => println!("{}", &v),
            None => {}
        }

        match event.format {
            8 => {
                for i in 0..20 {
                    println!("{}", event.data.get_byte(i));
                }
            }
            16 => {
                for i in 0..10 {
                    println!("{}", event.data.get_short(i))
                }
            }
            32 => {
                for i in 0..5 {
                    let a = event.data.get_long(i);
                    if a != 0{
                        let s = libx::get_atom_name(self.context, a as xlib::Atom);
                        match s {
                            Some(v) => println!("{}", v),
                            None => {}
                        }
                    }
                }
            }
            _ => {}
        }
    }

    pub fn handle_button_motion(&mut self, event: &xlib::XMotionEvent) {
        let (window, _) = libx::get_input_focus(self.context);
        if window != event.window {
            libx::set_input_focus(self.context, window);
        }
    }

    pub fn handle_key_release(&mut self, event: &mut xlib::XKeyEvent) {
        if event.state > 0 {
            let mut sym: xlib::KeySym = 0;
            let status: *mut xlib::XComposeStatus = ptr::null_mut();
            unsafe{
                xlib::XLookupString(event, ptr::null_mut(), 0, &mut sym, status);
            }
            let b = handler::KeyBind {
                key: sym,
                mask: event.state,
            };
            debug!("key {} {}", event.state, sym);
            // let mut h: Box<handler::Handler>;
            match self.config.bindsyms.get_mut(&b) {
                Some(handler) => {
                    handler.handle(&mut self.workspaces, self.context, self.screen_num);
                }
                None => {
                    println!("no bind");
                }
            }
        }
    }

    pub fn handle_configure_request(&mut self, event: &xlib::XConfigureRequestEvent) {
        let mut change = 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
        };
        debug!("config x: {}, y: {}, width: {}, height: {}",
               change.x, change.y, change.width, change.height);
        libx::configure_window(self.context, event.window, event.value_mask as u32, change);
    }

    pub fn handle_focus_in(&mut self, event: &xlib::XFocusChangeEvent) {
        libx::set_input_focus(self.context, event.window);
        let (window, _) = libx::get_input_focus(self.context);
        println!("window {}", window);
      }

    pub fn handle_enter(&mut self, event: &xlib::XCrossingEvent){
        if event.focus == 0 {
            libx::set_input_focus(self.context, event.window);
        }
    }

    pub fn handle(&mut self, e: xlib::XEvent) {
        let t = e.get_type();
        match t {
            xlib::CreateNotify => {
                let event: xlib::XCreateWindowEvent = From::from(e);
                debug!("create notify {}", event.window);
                self.handle_create(&event);
            }
            xlib::DestroyNotify => {
                let event: xlib::XDestroyWindowEvent = From::from(e);
                debug!("destroy notify {}", event.window);
                self.handle_destroy(&event);
            }
            xlib::MapNotify => {
                let event: xlib::XMapEvent = From::from(e);
                debug!("map notify {}", event.window);
            }
            xlib::UnmapNotify => {
                let event: xlib::XUnmapEvent = From::from(e);
                debug!("unmap notify {}", event.window);
            }
            xlib::MapRequest => {
                let event: xlib::XMapRequestEvent = From::from(e);
                debug!("map request {}", event.window);
                self.handle_map_request(&event);
            }
            xlib::ClientMessage => {
                debug!("client message");
                // let event = cast_event::<xlib::XClientMessageEvent>(&e);
                let event: xlib::XClientMessageEvent = From::from(e);
                self.handle_client_message(&event);
            }
            xlib::KeyRelease => {
                debug!("key release");
                let mut event: xlib::XKeyEvent = From::from(e);
                self.handle_key_release(&mut event);
            }
            xlib::MotionNotify => {
                let mut event: xlib::XMotionEvent = From::from(e);
                debug!("button motion {}", event.window);
                self.handle_button_motion(&event);
            }
            xlib::ButtonRelease => {
                let mut event: xlib::XButtonEvent = From::from(e);
                debug!("button release {}", event.window);
            }
            xlib::ButtonPress => {
                let mut event: xlib::XButtonEvent = From::from(e);
                debug!("button press {}", event.window);
            }
            xlib::ConfigureNotify => {
                debug!("configure notify");
            }
            xlib::ConfigureRequest =>{
                let mut event: xlib::XConfigureRequestEvent = From::from(e);
                debug!("configure request {}", event.window);
                self.handle_configure_request(&event);
            }
            xlib::FocusIn => {
                let mut event: xlib::XFocusChangeEvent = From::from(e);
                debug!("focus in {}", event.window);
                self.handle_focus_in(&event);

            }
            xlib::FocusOut => {
                let mut event: xlib::XFocusChangeEvent = From::from(e);
                debug!("focus out {}", event.window);
            }

            xlib::EnterNotify => {
                let mut event: xlib::XCrossingEvent = From::from(e);
                debug!("enter window {}", event.window);
                self.handle_enter(&event);
            }
            _ => {
                debug!("unhandled event {}", t);
            }
        }
    }
    pub fn run(&mut self) {
        loop {
            //handle events here
            let mut e = libx::next_event(self.context);
            self.handle(e);
        }
    }

    pub fn init(&mut self) {
        let mask = xlib::SubstructureRedirectMask | xlib::SubstructureNotifyMask;
        let keymask = xlib::KeyPressMask | xlib::KeyReleaseMask | xlib::ButtonPressMask | xlib::ButtonReleaseMask;
        unsafe{
            // xlib::XSetErrorHandler(Some(error_handler));
            libx::select_input(self.context, self.root,
                               mask | keymask);
            libx::sync(self.context, 0);
        }
    }
}
<commit_msg>use wrappers<commit_after>extern crate libc;

use std::ptr;
use std::mem;
use std::ffi;
use std::str;
use std::slice::from_raw_parts;
use std::string::String;
use std::collections::HashMap;
use std::boxed::Box;
use x11::xlib;
use x11::keysym;

use super::super::libx;

use super::config::Config;
use super::{ Workspace, Workspaces };
use super::handler;

unsafe extern fn error_handler(display: *mut xlib::Display, event: *mut xlib::XErrorEvent) -> libc::c_int {
    // match event.error_code {
    //     xlib::BadAtom => {
    //         println!("bad atom");
    //     }
    //     _ => {}
    // }
    1
}

pub struct WindowManager {
    pub context: libx::Context,
    pub screen_num: libc::c_int,
    pub root:    xlib::Window,

    pub workspaces: Workspaces,
    config: Config
}

impl WindowManager {
    pub fn new() -> WindowManager {
	let context = libx::open_display(None);
        let context = match context {
            Some(p) => {
                p
            }
            None => {
                panic!("can't open display")
            }
        };

	let screen_num  = libx::default_screen(context);
	let root = libx::root_window(context, screen_num);
        println!("root window {}", root);
	let mut wm = WindowManager {
            context: context,
            screen_num: screen_num,
	    root: root,

            config: Config::load(),
            workspaces: Workspaces::new()
        };
        wm.workspaces.create('1', screen_num);
        wm.workspaces.get('1').unwrap().visible = true;
        wm.workspaces.switch_current('1', context);
        wm
    }

    pub fn clean(&mut self) {
        libx::close_display(self.context);
    }

    pub fn is_top_window(&self, window: xlib::Window) -> bool{
        let attrs = libx::get_window_attributes(self.context, window);
        let transientfor_hint = libx::get_transient_for_hint(self.context, window);
        attrs.override_redirect == 0 && transientfor_hint == 0
    }

    pub fn handle_create(&mut self, event: &xlib::XCreateWindowEvent) {
        if event.override_redirect != 0 {
            return;
        }

        let attrs = libx::get_window_attributes(self.context, event.window);

        // get window property
        let n = libx::get_text_property(self.context, event.window, xlib::XA_WM_NAME);
        match n {
            Some(s) => {debug!("create window {} for {}", event.window, s);}
            None => {}
        }

        // let atoms = libx::get_wm_protocols(self.context, event.window);
        // for a in atoms.iter() {
        //     println!("atom {}", a);
        //     let name = libx::get_atom_name(self.context, *a);
        //     match name {
        //         Some(n) => println!("name {}", n),
        //         None => println!("name {}", a),
        //     };
        // }
    }

    pub fn handle_destroy(&mut self, event: &xlib::XDestroyWindowEvent) {
        self.workspaces.remove_window(event.window, self.context);
    }

    pub fn handle_map_request(&mut self, event: &xlib::XMapRequestEvent) {
        libx::map_window(self.context, event.window);

        // add app top-level window to workspace
        let manage = self.is_top_window(event.window);

        if manage {
            debug!("top level window");
            self.workspaces.add_window(event.window, None, self.context);

            libx::set_input_focus(self.context, event.window);

            let attrs = libx::get_window_attributes(self.context, event.window);
            println!("masks {}", attrs.all_event_masks);
            println!("mask button press {}", attrs.all_event_masks | xlib::ButtonPressMask);
            // change attributes before display
            unsafe{
                let mask = xlib::OwnerGrabButtonMask | xlib::KeyReleaseMask | xlib::PointerMotionHintMask | xlib::EnterWindowMask;
                // let mut attrs: xlib::XSetWindowAttributes = mem::zeroed();
                // attrs.event_mask = xlib::KeyReleaseMask | xlib::ButtonPressMask | xlib::ButtonReleaseMask | xlib::EnterWindowMask;
                // let valuemask = xlib::CWEventMask;
                // libx::change_window_attributes(self.context, event.window, valuemask, &mut attrs);
                libx::select_input(self.context, event.window, mask);
            }
        }
    }

    pub fn handle_client_message(&mut self, event: &xlib::XClientMessageEvent) {
        println!("message type {}", event.message_type);
        let s = libx::get_atom_name(self.context, event.message_type);
        match s {
            Some(v) => println!("{}", &v),
            None => {}
        }

        match event.format {
            8 => {
                for i in 0..20 {
                    println!("{}", event.data.get_byte(i));
                }
            }
            16 => {
                for i in 0..10 {
                    println!("{}", event.data.get_short(i))
                }
            }
            32 => {
                for i in 0..5 {
                    let a = event.data.get_long(i);
                    if a != 0{
                        let s = libx::get_atom_name(self.context, a as xlib::Atom);
                        match s {
                            Some(v) => println!("{}", v),
                            None => {}
                        }
                    }
                }
            }
            _ => {}
        }
    }

    pub fn handle_button_motion(&mut self, event: &xlib::XMotionEvent) {
        let (window, _) = libx::get_input_focus(self.context);
        if window != event.window {
            libx::set_input_focus(self.context, window);
        }
    }

    pub fn handle_key_release(&mut self, event: &mut xlib::XKeyEvent) {
        if event.state > 0 {
            let mut sym: xlib::KeySym = 0;
            let status: *mut xlib::XComposeStatus = ptr::null_mut();
            unsafe{
                xlib::XLookupString(event, ptr::null_mut(), 0, &mut sym, status);
            }
            let b = handler::KeyBind {
                key: sym,
                mask: event.state,
            };
            debug!("key {} {}", event.state, sym);
            // let mut h: Box<handler::Handler>;
            match self.config.bindsyms.get_mut(&b) {
                Some(handler) => {
                    handler.handle(&mut self.workspaces, self.context, self.screen_num);
                }
                None => {
                    println!("no bind");
                }
            }
        }
    }

    pub fn handle_configure_request(&mut self, event: &xlib::XConfigureRequestEvent) {
        let mut change = 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
        };
        debug!("config x: {}, y: {}, width: {}, height: {}",
               change.x, change.y, change.width, change.height);
        libx::configure_window(self.context, event.window, event.value_mask as u32, change);
    }

    pub fn handle_focus_in(&mut self, event: &xlib::XFocusChangeEvent) {
        libx::set_input_focus(self.context, event.window);
        let (window, _) = libx::get_input_focus(self.context);
        println!("window {}", window);
      }

    pub fn handle_enter(&mut self, event: &xlib::XCrossingEvent){
        if event.focus == 0 {
            libx::set_input_focus(self.context, event.window);
        }
    }

    pub fn handle(&mut self, e: xlib::XEvent) {
        let t = e.get_type();
        match t {
            xlib::CreateNotify => {
                let event: xlib::XCreateWindowEvent = From::from(e);
                debug!("create notify {}", event.window);
                self.handle_create(&event);
            }
            xlib::DestroyNotify => {
                let event: xlib::XDestroyWindowEvent = From::from(e);
                debug!("destroy notify {}", event.window);
                self.handle_destroy(&event);
            }
            xlib::MapNotify => {
                let event: xlib::XMapEvent = From::from(e);
                debug!("map notify {}", event.window);
            }
            xlib::UnmapNotify => {
                let event: xlib::XUnmapEvent = From::from(e);
                debug!("unmap notify {}", event.window);
            }
            xlib::MapRequest => {
                let event: xlib::XMapRequestEvent = From::from(e);
                debug!("map request {}", event.window);
                self.handle_map_request(&event);
            }
            xlib::ClientMessage => {
                debug!("client message");
                // let event = cast_event::<xlib::XClientMessageEvent>(&e);
                let event: xlib::XClientMessageEvent = From::from(e);
                self.handle_client_message(&event);
            }
            xlib::KeyRelease => {
                debug!("key release");
                let mut event: xlib::XKeyEvent = From::from(e);
                self.handle_key_release(&mut event);
            }
            xlib::MotionNotify => {
                let mut event: xlib::XMotionEvent = From::from(e);
                debug!("button motion {}", event.window);
                self.handle_button_motion(&event);
            }
            xlib::ButtonRelease => {
                let mut event: xlib::XButtonEvent = From::from(e);
                debug!("button release {}", event.window);
            }
            xlib::ButtonPress => {
                let mut event: xlib::XButtonEvent = From::from(e);
                debug!("button press {}", event.window);
            }
            xlib::ConfigureNotify => {
                debug!("configure notify");
            }
            xlib::ConfigureRequest =>{
                let mut event: xlib::XConfigureRequestEvent = From::from(e);
                debug!("configure request {}", event.window);
                self.handle_configure_request(&event);
            }
            xlib::FocusIn => {
                let mut event: xlib::XFocusChangeEvent = From::from(e);
                debug!("focus in {}", event.window);
                self.handle_focus_in(&event);

            }
            xlib::FocusOut => {
                let mut event: xlib::XFocusChangeEvent = From::from(e);
                debug!("focus out {}", event.window);
            }

            xlib::EnterNotify => {
                let mut event: xlib::XCrossingEvent = From::from(e);
                debug!("enter window {}", event.window);
                self.handle_enter(&event);
            }
            _ => {
                debug!("unhandled event {}", t);
            }
        }
    }
    pub fn run(&mut self) {
        loop {
            //handle events here
            let mut e = libx::next_event(self.context);
            self.handle(e);
        }
    }

    pub fn init(&mut self) {
        let mask = xlib::SubstructureRedirectMask | xlib::SubstructureNotifyMask;
        let keymask = xlib::KeyPressMask | xlib::KeyReleaseMask | xlib::ButtonPressMask | xlib::ButtonReleaseMask;
        unsafe{
            // xlib::XSetErrorHandler(Some(error_handler));
            libx::select_input(self.context, self.root,
                               mask | keymask);
            libx::sync(self.context, 0);
        }
    }
}
<|endoftext|>


<commit_before>
use std::sync::Arc;

use rocksdb::DB;
use proto::raft_serverpb::StoreIdent;
use proto::metapb;
use raftserver::Result;
use super::keys;
use super::engine::Mutator;

// TODO: implement bootstrap later.
// 1. bootstrap store.
// 2. bootstrap region 1.

pub fn bootstrap_store(engine: Arc<DB>, cluster_id: u64, meta: metapb::Store) -> Result<()> {
    let mut ident = StoreIdent::new();
    ident.set_cluster_id(cluster_id);
    ident.set_node_id(meta.get_node().get_node_id());
    ident.set_store_id(meta.get_store_id());

    engine.put_msg(&keys::store_ident_key(), &ident)
}
<commit_msg>raftserver: support bootstrap.<commit_after>
use std::sync::Arc;

use rocksdb::{DB, WriteBatch};
use proto::raft_serverpb::StoreIdent;
use proto::metapb;
use raftserver::{Result, other};
use super::keys;
use super::engine::{Retriever, Mutator};

// How to construct cluster?
//
// Use bootstrap_cluster to bootstrap cluster first, this function will create
// node 1 and store 1 for this cluster.
// When we start store, we must first check whether the store is bootstrapped or not
// using is_store_bootstrapped, if not, we must call bootstrap_store to bootstrap it first.

pub const BOOTSTRAP_FIRST_NODE_ID: u64 = 1;
pub const BOOTSTRAP_FIRST_STORE_ID: u64 = 1;
pub const BOOTSTRAP_FIRST_REGION_ID: u64 = 1;
pub const BOOTSTRAP_FIRST_PEER_ID: u64 = 1;

pub fn is_store_bootstrapped(engine: Arc<DB>, cluster_id: u64) -> Result<bool> {
    let res = try!(engine.get_msg::<StoreIdent>(&keys::store_ident_key()));
    match res {
        None => Ok(false),
        Some(ident) => {
            if ident.get_cluster_id() != cluster_id {
                return Err(other(format!("store is bootstrapped for cluster {} already",
                                         ident.get_cluster_id())));
            }
            Ok(true)
        }
    }
}

// Bootstrap the store, the DB for this store must be empty and has no data.
pub fn bootstrap_store(engine: Arc<DB>,
                       cluster_id: u64,
                       node_id: u64,
                       store_id: u64)
                       -> Result<()> {
    let mut ident = StoreIdent::new();

    let mut count: u32 = 0;
    try!(engine.scan(keys::MIN_KEY,
                     keys::MAX_KEY,
                     &mut |_, _| -> Result<(bool)> {
                         count += 1;
                         Ok(false)
                     }));

    if count > 0 {
        return Err(other("store is not empty and has already had data."));
    }

    let ident_key = keys::store_ident_key();
    try!(engine.get_msg::<StoreIdent>(&ident_key).and_then(|res| {
        if res.is_some() {
            let res = res.unwrap();
            return Err(other(format!("store has already been bootstrapped to cluster {}",
                                     res.get_cluster_id())));
        }

        Ok(())
    }));

    ident.set_cluster_id(cluster_id);
    ident.set_node_id(node_id);
    ident.set_store_id(store_id);

    engine.put_msg(&ident_key, &ident)
}

// Bootstrap first region, the region id must be 1 and start/end key is
// min_key/max_key. The first peer id is 1 too.
fn bootstrap_region(engine: Arc<DB>) -> Result<()> {
    let mut region = metapb::Region::new();
    region.set_region_id(BOOTSTRAP_FIRST_NODE_ID);
    region.set_start_key(keys::MIN_KEY.to_vec());
    region.set_end_key(keys::MAX_KEY.to_vec());

    let mut peer = metapb::Peer::new();
    peer.set_node_id(BOOTSTRAP_FIRST_NODE_ID);
    peer.set_store_id(BOOTSTRAP_FIRST_STORE_ID);
    peer.set_peer_id(BOOTSTRAP_FIRST_PEER_ID);

    let batch = WriteBatch::new();
    try!(batch.put_msg(&keys::region_info_key(region.get_start_key()), &region));

    // meta2 key for this region is \x03\0xff
    let meta2_key = keys::region_route_meta_key(keys::MAX_KEY);
    try!(batch.put_msg(&meta2_key, &region));

    // meta1 key for meta2 is \0x02\0xff
    let meta1_key = keys::region_route_meta_key(&meta2_key);
    try!(batch.put_msg(&meta1_key, &region));

    try!(engine.write(batch));

    Ok(())
}

// Bootstrap cluster, we must bootstrap the first store with node/store id both are 1,
// and first region.
pub fn bootstrap_cluster(engine: Arc<DB>, cluster_id: u64) -> Result<()> {
    try!(bootstrap_store(engine.clone(),
                         cluster_id,
                         BOOTSTRAP_FIRST_NODE_ID,
                         BOOTSTRAP_FIRST_STORE_ID));
    try!(bootstrap_region(engine.clone()));
    Ok(())
}
<|endoftext|>


<commit_before>pub fn find() -> Option<u32> {
    const LOWER: u32 = 1000/3;
    const UPPER: u32 = 1000/2;

    for c in LOWER..UPPER {
        for b in c/2..c {
            for a in 1..b {
                if a*a + b*b != c*c {
                    continue;
                }

                if a + b + c == 1000 {
                    return Some(a*b*c);
                }
            }
        }
    }

    None
}
<commit_msg>Use const instead of magic number<commit_after>pub fn find() -> Option<u32> {
    const VALUE: u32 = 1000;
    const LOWER: u32 = VALUE / 3;
    const UPPER: u32 = VALUE / 2;

    for c in LOWER..UPPER {
        for b in c / 2..c {
            for a in 1..b {
                if a * a + b * b != c * c {
                    continue;
                }

                if a + b + c == VALUE {
                    return Some(a * b * c);
                }
            }
        }
    }

    None
}
<|endoftext|>


<commit_before>use crate::*;
use rustc_target::abi::{Align, Size};

/// Implementation of the SYS_futex syscall.
pub fn futex<'tcx>(
    this: &mut MiriEvalContext<'_, 'tcx>,
    args: &[OpTy<'tcx, Tag>],
    dest: PlaceTy<'tcx, Tag>,
) -> InterpResult<'tcx> {
    // The amount of arguments used depends on the type of futex operation.
    // The full futex syscall takes six arguments (excluding the syscall
    // number), which is also the maximum amount of arguments a linux syscall
    // can take on most architectures.
    // However, not all futex operations use all six arguments. The unused ones
    // may or may not be left out from the `syscall()` call.
    // Therefore we don't use `check_arg_count` here, but only check for the
    // number of arguments to fall within a range.
    if !(4..=7).contains(&args.len()) {
        throw_ub_format!("incorrect number of arguments for futex syscall: got {}, expected between 4 and 7 (inclusive)", args.len());
    }

    // The first three arguments (after the syscall number itself) are the same to all futex operations:
    //     (int *addr, int op, int val).
    // Although note that the first one is often passed as a different pointer type, e.g. `*const AtomicU32` or `*mut u32`.
    let addr = this.deref_operand(args[1])?;
    let op = this.read_scalar(args[2])?.to_i32()?;
    let val = this.read_scalar(args[3])?.to_i32()?;

    // The raw pointer value is used to identify the mutex.
    // Not all mutex operations actually read from this address or even require this address to exist.
    let futex_ptr = addr.ptr.assert_ptr();

    let thread = this.get_active_thread();

    let futex_private = this.eval_libc_i32("FUTEX_PRIVATE_FLAG")?;
    let futex_wait = this.eval_libc_i32("FUTEX_WAIT")?;
    let futex_wake = this.eval_libc_i32("FUTEX_WAKE")?;

    // FUTEX_PRIVATE enables an optimization that stops it from working across processes.
    // Miri doesn't support that anyway, so we ignore that flag.
    match op & !futex_private {
        // FUTEX_WAIT: (int *addr, int op = FUTEX_WAIT, int val, const timespec *timeout)
        // Blocks the thread if *addr still equals val. Wakes up when FUTEX_WAKE is called on the same address,
        // or *timeout expires. `timeout == null` for an infinite timeout.
        op if op == futex_wait => {
            if args.len() < 5 {
                throw_ub_format!("incorrect number of arguments for FUTEX_WAIT syscall: got {}, expected at least 5", args.len());
            }
            let timeout = this.read_scalar(args[4])?.check_init()?;
            if !this.is_null(timeout)? {
                // FIXME: Implement timeouts. The condvar waiting code is probably a good example to start with.
                // Note that a triggered timeout should have this syscall return with -1 and errno set to ETIMEOUT.
                throw_ub_format!("miri does not support timeouts for futex operations");
            }
            // Check the pointer for alignment. Atomic operations are only available for fully aligned values.
            this.memory.check_ptr_access(addr.ptr.into(), Size::from_bytes(4), Align::from_bytes(4).unwrap())?;
            // Read an `i32` through the pointer, regardless of any wrapper types (e.g. `AtomicI32`).
            let futex_val = this.read_scalar(addr.offset(Size::ZERO, MemPlaceMeta::None, this.machine.layouts.i32, this)?.into())?.to_i32()?;
            if val == futex_val {
                // The value still matches, so we block the trait make it wait for FUTEX_WAKE.
                this.block_thread(thread);
                this.futex_wait(futex_ptr, thread);
                // Succesfully waking up from FUTEX_WAIT always returns zero.
                this.write_scalar(Scalar::from_i32(0), dest)?;
            } else {
                // The futex value doesn't match the expected value, so we return failure
                // right away without sleeping: -1 and errno set to EAGAIN.
                let eagain = this.eval_libc("EAGAIN")?;
                this.set_last_error(eagain)?;
                this.write_scalar(Scalar::from_i32(-1), dest)?;
            }
        }
        // FUTEX_WAKE: (int *addr, int op = FUTEX_WAKE, int val)
        // Wakes at most `val` threads waiting on the futex at `addr`.
        // Returns the amount of threads woken up.
        // Does not access the futex value at *addr.
        op if op == futex_wake => {
            let mut n = 0;
            for _ in 0..val {
                if let Some(thread) = this.futex_wake(futex_ptr) {
                    this.unblock_thread(thread);
                    n += 1;
                } else {
                    break;
                }
            }
            this.write_scalar(Scalar::from_i32(n), dest)?;
        }
        op => throw_unsup_format!("miri does not support SYS_futex operation {}", op),
    }

    Ok(())
}
<commit_msg>Add note about arguments in futex implementation.<commit_after>use crate::*;
use rustc_target::abi::{Align, Size};

/// Implementation of the SYS_futex syscall.
pub fn futex<'tcx>(
    this: &mut MiriEvalContext<'_, 'tcx>,
    args: &[OpTy<'tcx, Tag>],
    dest: PlaceTy<'tcx, Tag>,
) -> InterpResult<'tcx> {
    // The amount of arguments used depends on the type of futex operation.
    // The full futex syscall takes six arguments (excluding the syscall
    // number), which is also the maximum amount of arguments a linux syscall
    // can take on most architectures.
    // However, not all futex operations use all six arguments. The unused ones
    // may or may not be left out from the `syscall()` call.
    // Therefore we don't use `check_arg_count` here, but only check for the
    // number of arguments to fall within a range.
    if !(4..=7).contains(&args.len()) {
        throw_ub_format!("incorrect number of arguments for futex syscall: got {}, expected between 4 and 7 (inclusive)", args.len());
    }

    // The first three arguments (after the syscall number itself) are the same to all futex operations:
    //     (int *addr, int op, int val).
    // We checked above that these definitely exist.
    // Although note that the first one is often passed as a different pointer type, e.g. `*const AtomicU32` or `*mut u32`.
    let addr = this.deref_operand(args[1])?;
    let op = this.read_scalar(args[2])?.to_i32()?;
    let val = this.read_scalar(args[3])?.to_i32()?;

    // The raw pointer value is used to identify the mutex.
    // Not all mutex operations actually read from this address or even require this address to exist.
    let futex_ptr = addr.ptr.assert_ptr();

    let thread = this.get_active_thread();

    let futex_private = this.eval_libc_i32("FUTEX_PRIVATE_FLAG")?;
    let futex_wait = this.eval_libc_i32("FUTEX_WAIT")?;
    let futex_wake = this.eval_libc_i32("FUTEX_WAKE")?;

    // FUTEX_PRIVATE enables an optimization that stops it from working across processes.
    // Miri doesn't support that anyway, so we ignore that flag.
    match op & !futex_private {
        // FUTEX_WAIT: (int *addr, int op = FUTEX_WAIT, int val, const timespec *timeout)
        // Blocks the thread if *addr still equals val. Wakes up when FUTEX_WAKE is called on the same address,
        // or *timeout expires. `timeout == null` for an infinite timeout.
        op if op == futex_wait => {
            if args.len() < 5 {
                throw_ub_format!("incorrect number of arguments for FUTEX_WAIT syscall: got {}, expected at least 5", args.len());
            }
            let timeout = this.read_scalar(args[4])?.check_init()?;
            if !this.is_null(timeout)? {
                // FIXME: Implement timeouts. The condvar waiting code is probably a good example to start with.
                // Note that a triggered timeout should have this syscall return with -1 and errno set to ETIMEOUT.
                throw_ub_format!("miri does not support timeouts for futex operations");
            }
            // Check the pointer for alignment. Atomic operations are only available for fully aligned values.
            this.memory.check_ptr_access(addr.ptr.into(), Size::from_bytes(4), Align::from_bytes(4).unwrap())?;
            // Read an `i32` through the pointer, regardless of any wrapper types (e.g. `AtomicI32`).
            let futex_val = this.read_scalar(addr.offset(Size::ZERO, MemPlaceMeta::None, this.machine.layouts.i32, this)?.into())?.to_i32()?;
            if val == futex_val {
                // The value still matches, so we block the trait make it wait for FUTEX_WAKE.
                this.block_thread(thread);
                this.futex_wait(futex_ptr, thread);
                // Succesfully waking up from FUTEX_WAIT always returns zero.
                this.write_scalar(Scalar::from_i32(0), dest)?;
            } else {
                // The futex value doesn't match the expected value, so we return failure
                // right away without sleeping: -1 and errno set to EAGAIN.
                let eagain = this.eval_libc("EAGAIN")?;
                this.set_last_error(eagain)?;
                this.write_scalar(Scalar::from_i32(-1), dest)?;
            }
        }
        // FUTEX_WAKE: (int *addr, int op = FUTEX_WAKE, int val)
        // Wakes at most `val` threads waiting on the futex at `addr`.
        // Returns the amount of threads woken up.
        // Does not access the futex value at *addr.
        op if op == futex_wake => {
            let mut n = 0;
            for _ in 0..val {
                if let Some(thread) = this.futex_wake(futex_ptr) {
                    this.unblock_thread(thread);
                    n += 1;
                } else {
                    break;
                }
            }
            this.write_scalar(Scalar::from_i32(n), dest)?;
        }
        op => throw_unsup_format!("miri does not support SYS_futex operation {}", op),
    }

    Ok(())
}
<|endoftext|>


<commit_before>// xfail-test
use std;
import std::comm;
import std::task;

fn main() {
    let po = comm::port();

    // Spawn 10 tasks each sending us back one int.
    let i = 10;
    while (i > 0) {
        log i;
        task::spawn(bind child(i, comm::chan(po)));
        i = i - 1;
    }

    // Spawned tasks are likely killed before they get a chance to send
    // anything back, so we deadlock here.

    i = 10;
    let value = 0;
    while (i > 0) {
        log i;
        value = comm::recv(po);
        i = i - 1;
    }

    log "main thread exiting";
}

fn child(x: int, ch: comm::chan<int>) {
    log x;
    comm::send(ch, x);
}
<commit_msg>Actually un-xfail task-comm-14<commit_after>use std;
import std::comm;
import std::task;

fn main() {
    let po = comm::port();

    // Spawn 10 tasks each sending us back one int.
    let i = 10;
    while (i > 0) {
        log i;
        task::spawn(bind child(i, comm::chan(po)));
        i = i - 1;
    }

    // Spawned tasks are likely killed before they get a chance to send
    // anything back, so we deadlock here.

    i = 10;
    let value = 0;
    while (i > 0) {
        log i;
        value = comm::recv(po);
        i = i - 1;
    }

    log "main thread exiting";
}

fn child(x: int, ch: comm::chan<int>) {
    log x;
    comm::send(ch, x);
}
<|endoftext|>


<commit_before>use std::fs;
use std::fs::File;
use std::io;
use std::io::Read;
use std::path::Path;
use std::path::PathBuf;

use crate::authentication::Credentials;
use crate::spotify_id::FileId;
use crate::volume::Volume;

#[derive(Clone)]
pub struct Cache {
    audio_root: PathBuf,
    system_root: PathBuf,
    use_audio_cache: bool,
}

fn mkdir_existing(path: &Path) -> io::Result<()> {
    fs::create_dir(path).or_else(|err| {
        if err.kind() == io::ErrorKind::AlreadyExists {
            Ok(())
        } else {
            Err(err)
        }
    })
}

impl Cache {
    pub fn new(audio_location: PathBuf, system_location: PathBuf, use_audio_cache: bool) -> Cache {
        mkdir_existing(&audio_location).unwrap();
        mkdir_existing(&audio_location.join("files")).unwrap();
        mkdir_existing(&system_location).unwrap();

        Cache {
            audio_root: audio_location,
            system_root: system_location,
            use_audio_cache: use_audio_cache,
        }
    }
}

impl Cache {
    fn credentials_path(&self) -> PathBuf {
        self.system_root.join("credentials.json")
    }

    pub fn credentials(&self) -> Option<Credentials> {
        let path = self.credentials_path();
        Credentials::from_file(path)
    }

    pub fn save_credentials(&self, cred: &Credentials) {
        let path = self.credentials_path();
        cred.save_to_file(&path);
    }
}

// cache volume to system_root/volume
impl Cache {
    fn volume_path(&self) -> PathBuf {
        self.system_root.join("volume")
    }

    pub fn volume(&self) -> Option<u16> {
        let path = self.volume_path();
        Volume::from_file(path)
    }

    pub fn save_volume(&self, volume: Volume) {
        let path = self.volume_path();
        volume.save_to_file(&path);
    }
}

impl Cache {
    fn file_path(&self, file: FileId) -> PathBuf {
        let name = file.to_base16();
        self.audio_root
            .join("files")
            .join(&name[0..2])
            .join(&name[2..])
    }

    pub fn file(&self, file: FileId) -> Option<File> {
        File::open(self.file_path(file)).ok()
    }

    pub fn save_file(&self, file: FileId, contents: &mut dyn Read) {
        if self.use_audio_cache {
            let path = self.file_path(file);

            mkdir_existing(path.parent().unwrap()).unwrap();

            let mut cache_file = File::create(path).unwrap();
            ::std::io::copy(contents, &mut cache_file).unwrap();
        }
    }
}
<commit_msg>Don't create directories for the audio cache if it disabled<commit_after>use std::fs;
use std::fs::File;
use std::io;
use std::io::Read;
use std::path::Path;
use std::path::PathBuf;

use crate::authentication::Credentials;
use crate::spotify_id::FileId;
use crate::volume::Volume;

#[derive(Clone)]
pub struct Cache {
    audio_root: PathBuf,
    system_root: PathBuf,
    use_audio_cache: bool,
}

fn mkdir_existing(path: &Path) -> io::Result<()> {
    fs::create_dir(path).or_else(|err| {
        if err.kind() == io::ErrorKind::AlreadyExists {
            Ok(())
        } else {
            Err(err)
        }
    })
}

impl Cache {
    pub fn new(audio_location: PathBuf, system_location: PathBuf, use_audio_cache: bool) -> Cache {
        if use_audio_cache == true {
            mkdir_existing(&audio_location).unwrap();
            mkdir_existing(&audio_location.join("files")).unwrap();
        }
        mkdir_existing(&system_location).unwrap();

        Cache {
            audio_root: audio_location,
            system_root: system_location,
            use_audio_cache: use_audio_cache,
        }
    }
}

impl Cache {
    fn credentials_path(&self) -> PathBuf {
        self.system_root.join("credentials.json")
    }

    pub fn credentials(&self) -> Option<Credentials> {
        let path = self.credentials_path();
        Credentials::from_file(path)
    }

    pub fn save_credentials(&self, cred: &Credentials) {
        let path = self.credentials_path();
        cred.save_to_file(&path);
    }
}

// cache volume to system_root/volume
impl Cache {
    fn volume_path(&self) -> PathBuf {
        self.system_root.join("volume")
    }

    pub fn volume(&self) -> Option<u16> {
        let path = self.volume_path();
        Volume::from_file(path)
    }

    pub fn save_volume(&self, volume: Volume) {
        let path = self.volume_path();
        volume.save_to_file(&path);
    }
}

impl Cache {
    fn file_path(&self, file: FileId) -> PathBuf {
        let name = file.to_base16();
        self.audio_root
            .join("files")
            .join(&name[0..2])
            .join(&name[2..])
    }

    pub fn file(&self, file: FileId) -> Option<File> {
        File::open(self.file_path(file)).ok()
    }

    pub fn save_file(&self, file: FileId, contents: &mut dyn Read) {
        if self.use_audio_cache {
            let path = self.file_path(file);

            mkdir_existing(path.parent().unwrap()).unwrap();

            let mut cache_file = File::create(path).unwrap();
            ::std::io::copy(contents, &mut cache_file).unwrap();
        }
    }
}
<|endoftext|>


<commit_before>extern crate env_logger;

extern crate tokio_core;
extern crate futures;
extern crate tokio_solicit;

use std::str;
use std::io::{self};

use futures::{Future, Stream};
use futures::future::{self};
use tokio_core::reactor::{Core};

use tokio_solicit::client::H2Client;

fn main() {
    env_logger::init().expect("logger init is required");

    let mut core = Core::new().expect("event loop required");
    let handle = core.handle();

    let addr = "127.0.0.1:8080".parse().expect("valid IP address");

    println!("Socket address - {:?}", addr);

    let future_client = H2Client::cleartext_connect("localhost", &addr, &handle);

    let future_response = future_client.and_then(|mut client| {
        println!("Connection established.");

        // For the first request, we simply want the full body, without streaming individual body
        // chunks...
        let get = client.get(b"/get").into_full_body_response();
        let post = client.post(b"/post", b"Hello, world!".to_vec());

        // ...for the other, we accumulate the body "manually" in order to do some more
        // processing for each chunk (for demo purposes). Also, discards the headers.
        let post = post.and_then(|(_headers, body)| {
            body.fold(Vec::<u8>::new(), |mut vec, chunk| {
                println!("receiving a new chunk of size {}", chunk.body.len());

                vec.extend(chunk.body.into_iter());
                future::ok::<_, io::Error>(vec)
            })
        });

        // Finally, yield a future that resolves once both requests are complete (and both bodies
        // are available).
        Future::join(get, post)
    }).map(|(get_response, post_response_body)| {
        // Convert the bodies to a UTF-8 string
        let get_res: String = str::from_utf8(&get_response.body).unwrap().into();
        let post_res: String = str::from_utf8(&post_response_body).unwrap().into();

        // ...and yield a pair of bodies converted to a string.
        (get_res, post_res)
    });

    let res = core.run(future_response).expect("responses!");

    println!("{:?}", res);

    // An additional demo showing how to perform a streaming _request_ (i.e. the body of the
    // request is streamed out to the server).
    do_streaming_request(&mut core);
}

fn do_streaming_request(core: &mut Core) {
    use std::iter;
    use tokio_solicit::client::HttpRequestBody;
    use futures::Sink;

    let handle = core.handle();
    let addr = "127.0.0.1:8080".parse().expect("valid IP address");
    let future_client = H2Client::cleartext_connect("localhost", &addr, &handle);

    let future_response = future_client.and_then(|mut client| {
        let (post, tx) = client.streaming_request(b"POST", b"/post", iter::empty());
        tx
            .send(Ok(HttpRequestBody::new(b"HELLO ".to_vec())))
            .and_then(|tx| tx.send(Ok(HttpRequestBody::new(b" WORLD".to_vec()))))
            .and_then(|tx| tx.send(Ok(HttpRequestBody::new(b"!".to_vec()))))
            .map_err(|_err| io::Error::from(io::ErrorKind::BrokenPipe))
            .and_then(|_tx| post.into_full_body_response())
    });

    let res = core.run(future_response).expect("response");
    println!("{:?}", res);
}
<commit_msg>Example: Factor out the cleartext example into a function<commit_after>extern crate env_logger;

extern crate tokio_core;
extern crate futures;
extern crate tokio_solicit;

use std::str;
use std::io::{self};

use futures::{Future, Stream};
use futures::future::{self};
use tokio_core::reactor::{Core};

use tokio_solicit::client::H2Client;

// Shows the usage of `H2Client` when establishing an HTTP/2 connection over cleartext TCP.
// Also demonstrates how to stream the body of the response (i.e. get response body chunks as soon
// as they are received on a `futures::Stream`.
fn cleartext_example() {
    let mut core = Core::new().expect("event loop required");
    let handle = core.handle();

    let addr = "127.0.0.1:8080".parse().expect("valid IP address");

    let future_client = H2Client::cleartext_connect("localhost", &addr, &handle);

    let future_response = future_client.and_then(|mut client| {
        println!("Connection established.");

        // For the first request, we simply want the full body, without streaming individual body
        // chunks...
        let get = client.get(b"/get").into_full_body_response();
        let post = client.post(b"/post", b"Hello, world!".to_vec());

        // ...for the other, we accumulate the body "manually" in order to do some more
        // processing for each chunk (for demo purposes). Also, discards the headers.
        let post = post.and_then(|(_headers, body)| {
            body.fold(Vec::<u8>::new(), |mut vec, chunk| {
                println!("receiving a new chunk of size {}", chunk.body.len());

                vec.extend(chunk.body.into_iter());
                future::ok::<_, io::Error>(vec)
            })
        });

        // Finally, yield a future that resolves once both requests are complete (and both bodies
        // are available).
        Future::join(get, post)
    }).map(|(get_response, post_response_body)| {
        // Convert the bodies to a UTF-8 string
        let get_res: String = str::from_utf8(&get_response.body).unwrap().into();
        let post_res: String = str::from_utf8(&post_response_body).unwrap().into();

        // ...and yield a pair of bodies converted to a string.
        (get_res, post_res)
    });

    let res = core.run(future_response).expect("responses!");

    println!("{:?}", res);
}

fn main() {
    env_logger::init().expect("logger init is required");

    // Establish an http/2 connection (over cleartext TCP), issue a couple of requests, and
    // stream the body of the response of one of them. Wait until both are ready and then
    // print the bodies.
    cleartext_example();

    // An additional demo showing how to perform a streaming _request_ (i.e. the body of the
    // request is streamed out to the server).
    do_streaming_request();
}

fn do_streaming_request() {
    use std::iter;
    use tokio_solicit::client::HttpRequestBody;
    use futures::Sink;

    let mut core = Core::new().expect("event loop required");
    let handle = core.handle();
    let addr = "127.0.0.1:8080".parse().expect("valid IP address");
    let future_client = H2Client::cleartext_connect("localhost", &addr, &handle);

    let future_response = future_client.and_then(|mut client| {
        let (post, tx) = client.streaming_request(b"POST", b"/post", iter::empty());
        tx
            .send(Ok(HttpRequestBody::new(b"HELLO ".to_vec())))
            .and_then(|tx| tx.send(Ok(HttpRequestBody::new(b" WORLD".to_vec()))))
            .and_then(|tx| tx.send(Ok(HttpRequestBody::new(b"!".to_vec()))))
            .map_err(|_err| io::Error::from(io::ErrorKind::BrokenPipe))
            .and_then(|_tx| post.into_full_body_response())
    });

    let res = core.run(future_response).expect("response");
    println!("{:?}", res);
}
<|endoftext|>


<commit_before>#![allow(clippy::redundant_clone)]
#![warn(clippy::manual_non_exhaustive)]

use std::ops::Deref;

mod enums {
    enum E {
        A,
        B,
        #[doc(hidden)]
        _C,
    }

    // user forgot to remove the marker
    #[non_exhaustive]
    enum Ep {
        A,
        B,
        #[doc(hidden)]
        _C,
    }
}

fn option_as_ref_deref() {
    let mut opt = Some(String::from("123"));

    let _ = opt.as_ref().map(String::as_str);
    let _ = opt.as_ref().map(|x| x.as_str());
    let _ = opt.as_mut().map(String::as_mut_str);
    let _ = opt.as_mut().map(|x| x.as_mut_str());
}

fn match_like_matches() {
    let _y = matches!(Some(5), Some(0));
}

fn match_same_arms() {
    match (1, 2, 3) {
        (1, .., 3) => 42,
        (.., 3) => 42, //~ ERROR match arms have same body
        _ => 0,
    };
}

fn match_same_arms2() {
    let _ = match Some(42) {
        Some(_) => 24,
        None => 24, //~ ERROR match arms have same body
    };
}

fn manual_strip_msrv() {
    let s = "hello, world!";
    if s.starts_with("hello, ") {
        assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!");
    }
}

fn main() {
    option_as_ref_deref();
    match_like_matches();
    match_same_arms();
    match_same_arms2();
    manual_strip_msrv();
}
<commit_msg>Addressed PR coments<commit_after>#![allow(clippy::redundant_clone)]
#![warn(clippy::manual_non_exhaustive)]

use std::ops::Deref;

mod enums {
    enum E {
        A,
        B,
        #[doc(hidden)]
        _C,
    }

    // user forgot to remove the marker
    #[non_exhaustive]
    enum Ep {
        A,
        B,
        #[doc(hidden)]
        _C,
    }
}

fn option_as_ref_deref() {
    let mut opt = Some(String::from("123"));

    let _ = opt.as_ref().map(String::as_str);
    let _ = opt.as_ref().map(|x| x.as_str());
    let _ = opt.as_mut().map(String::as_mut_str);
    let _ = opt.as_mut().map(|x| x.as_mut_str());
}

fn match_like_matches() {
    let _y = match Some(5) {
        Some(0) => true,
        _ => false,
    };
}

fn match_same_arms() {
    match (1, 2, 3) {
        (1, .., 3) => 42,
        (.., 3) => 42, //~ ERROR match arms have same body
        _ => 0,
    };
}

fn match_same_arms2() {
    let _ = match Some(42) {
        Some(_) => 24,
        None => 24, //~ ERROR match arms have same body
    };
}

fn manual_strip_msrv() {
    let s = "hello, world!";
    if s.starts_with("hello, ") {
        assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!");
    }
}

fn main() {
    option_as_ref_deref();
    match_like_matches();
    match_same_arms();
    match_same_arms2();
    manual_strip_msrv();
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate clap;
extern crate dialoguer;
extern crate duct;
#[macro_use]
extern crate error_chain;
extern crate serde;
extern crate serde_json;
extern crate snapshot;
extern crate walkdir;

use std::ffi::OsStr;
use std::fs::File;
use std::io::BufReader;

use clap::{Arg, SubCommand};
use dialoguer::{Checkboxes, Select};
use duct::cmd;
use snapshot::SnapFileContents;
use walkdir::WalkDir;

error_chain!{
    types {
        Error, ErrorKind, ResultExt, SnapResult;
    }

    foreign_links {
        Io(::std::io::Error);
    }
}

quick_main!(run);

fn run() -> SnapResult<()> {
    let input = app_from_crate!()
        .subcommand(
            SubCommand::with_name("update")
                .about("Update snapshots.")
                .arg(Arg::with_name("all").short("a").long("all").help(
                    "Unconditionally update all snapshots, including unrecorded ones.",
                )),
        )
        .get_matches();

    if let Some(update_matches) = input.subcommand_matches("update") {
        if update_matches.is_present("all") {
            let output = cmd("cargo", &["test"])
                .env("UPDATE_SNAPSHOTS", "1")
                .stdout_capture()
                .stderr_capture()
                .run()
                .chain_err(|| "unable to execute cargo")?;

            if !output.status.success() {
                // TODO(dikaiosune) print what failed
                bail!("unable to update all snapshots!");
            }
        } else {
            interactive_process()?;
        }
        println!("\nAll updates processed!");
    } else {
        panic!("unsupported command");
    }

    Ok(())
}

fn interactive_process() -> SnapResult<()> {
    let test_function_names = find_existing_snapshot_test_names()?;
    let mut failed_tests = Vec::new();

    println!("Checking for out of date snapshot tests...");
    for test_fn in &test_function_names {
        if !test_fn.success()? {
            failed_tests.push(test_fn);
        }
    }

    if failed_tests.is_empty() {
        println!("\nNo snapshot tests require an update!");
        ::std::process::exit(0);
    } else {
        println!("\nPlease select which snapshot tests should be updated:");
        println!("  <Space> to select, <Enter> to submit\n");

        let mut menu = Checkboxes::new();
        for failed in &failed_tests {
            menu.item(&failed.0);
        }
        let all_to_update = menu.interact().expect("error accepting user selections");

        for fn_idx in all_to_update {
            let fn_to_update = &failed_tests[fn_idx];
            println!("Updating {}...", &fn_to_update.0);

            // attempt to update the snapshot in a loop, allowing user to change code in bt runs
            let mut run_test = true;
            while run_test {
                let run_output = cmd("cargo", &["test", &fn_to_update.0])
                    .env("UPDATE_SNAPSHOTS", "1")
                    .stdout_capture()
                    .stderr_capture()
                    .run()
                    .chain_err(|| "unable to execute cargo")?;

                if run_output.status.success() {
                    run_test = false;
                } else {
                    println!("\nUpdating {} failed! What would you like to do?",
                             &fn_to_update.0);

                    match capture_failure_selection()? {
                        TestFailureSelection::Retry => continue,
                        TestFailureSelection::Skip => break,
                        TestFailureSelection::Abort => {
                            println!("\nExiting...");
                            ::std::process::exit(1);
                        }
                    }
                }
            }
        }

        Ok(())
    }
}

struct FnName(String);

impl FnName {
    // TODO this should let the user see why the test failed, or warn them if it wasn't from
    // snapshot failure
    fn success(&self) -> SnapResult<bool> {
        Ok(cmd("cargo", &["test", &self.0])
               .run()
               .chain_err(|| "unable to execute cargo")?
               .status
               .success())
    }
}

fn find_existing_snapshot_test_names() -> SnapResult<Vec<FnName>> {
    let cwd = ::std::env::current_dir()
        .chain_err(|| "unable to read cwd")?;

    let mut existing: Vec<SnapFileContents> = Vec::new();

    let snap_extension = OsStr::new("snap");
    for walk_result in WalkDir::new(cwd) {
        let entry = walk_result
            .chain_err(|| "unable to traverse project directory")?;

        if entry.path().extension() == Some(snap_extension) {
            let rdr = BufReader::new(File::open(entry.path())
                                         .chain_err(|| "unable to open snapshot file")?);
            let contents = serde_json::from_reader(rdr)
                .chain_err(|| "unable to parse snapshot file")?;
            existing.push(contents);
        }
    }

    let mut test_function_names = Vec::new();
    for snap_file in existing {
        for fun in snap_file.keys() {
            // now we need to strip crate name from the string
            let mut test_fn_chunks = fun.splitn(2, "::");

            match test_fn_chunks.next() {
                Some(_) => (),
                None => bail!("malformed test fn name: empty"),
            }

            let real_test_fn = match test_fn_chunks.next() {
                Some(n) => n,
                None => bail!("malformed test fn name: only had crate name"),
            };

            test_function_names.push(FnName(real_test_fn.to_owned()));
        }
    }
    Ok(test_function_names)
}

enum TestFailureSelection {
    Retry,
    Skip,
    Abort,
}

fn capture_failure_selection() -> SnapResult<TestFailureSelection> {
    let options = ["Retry", "Skip", "Abort"];

    let selection = Select::new()
        .items(&options)
        .interact()
        .chain_err(|| "unable to retrieve user input")?;

    if options[selection] == "Retry" {
        Ok(TestFailureSelection::Retry)
    } else if options[selection] == "Skip" {
        Ok(TestFailureSelection::Skip)
    } else if options[selection] == "Abort" {
        Ok(TestFailureSelection::Abort)
    } else {
        bail!("invalid menu selection")
    }
}
<commit_msg>grab a towel<commit_after>#[macro_use]
extern crate clap;
extern crate dialoguer;
extern crate duct;
#[macro_use]
extern crate error_chain;
extern crate serde;
extern crate serde_json;
extern crate snapshot;
extern crate walkdir;

use std::ffi::OsStr;
use std::fs::File;
use std::io::BufReader;

use clap::{Arg, SubCommand};
use dialoguer::{Checkboxes, Select};
use duct::cmd;
use snapshot::SnapFileContents;
use walkdir::WalkDir;

error_chain!{
    types {
        Error, ErrorKind, ResultExt, SnapResult;
    }

    foreign_links {
        Io(::std::io::Error);
    }
}

quick_main!(run);

fn run() -> SnapResult<()> {
    let input = app_from_crate!()
        .subcommand(
            SubCommand::with_name("update")
                .about("Update snapshots.")
                .arg(Arg::with_name("all").short("a").long("all").help(
                    "Unconditionally update all snapshots, including unrecorded ones.",
                )),
        )
        .get_matches();

    if let Some(update_matches) = input.subcommand_matches("update") {
        if update_matches.is_present("all") {
            let output = cmd("cargo", &["test"])
                .env("UPDATE_SNAPSHOTS", "1")
                .stdout_capture()
                .stderr_capture()
                .run()
                .chain_err(|| "unable to execute cargo")?;

            if !output.status.success() {
                // TODO(dikaiosune) print what failed
                bail!("unable to update all snapshots!");
            }
        } else {
            interactive_process()?;
        }
        println!("\nAll updates processed!");
    } else {
        panic!("unsupported command");
    }

    Ok(())
}

fn interactive_process() -> SnapResult<()> {
    let test_function_names = find_existing_snapshot_test_names()?;
    let mut failed_tests = Vec::new();

    println!("Checking for out of date snapshot tests...");
    for test_fn in &test_function_names {
        if !test_fn.success()? {
            failed_tests.push(test_fn);
        }
    }

    if failed_tests.is_empty() {
        println!("\nNo snapshot tests require an update!");
        ::std::process::exit(0);
    } else {
        println!("\nPlease select which snapshot tests should be updated:");
        println!("  <Space> to select, <Enter> to submit\n");

        let mut menu = Checkboxes::new();
        for failed in &failed_tests {
            menu.item(&failed.0);
        }

        let all_to_update = menu.interact()
            .chain_err(|| "error accepting user selections")?;

        for fn_idx in all_to_update {
            let fn_to_update = &failed_tests[fn_idx];
            println!("Updating {}...", &fn_to_update.0);

            // attempt to update the snapshot in a loop, allowing user to change code in bt runs
            let mut run_test = true;
            while run_test {
                let run_output = cmd("cargo", &["test", &fn_to_update.0])
                    .env("UPDATE_SNAPSHOTS", "1")
                    .stdout_capture()
                    .stderr_capture()
                    .run()
                    .chain_err(|| "unable to execute cargo")?;

                if run_output.status.success() {
                    run_test = false;
                } else {
                    println!("\nUpdating {} failed! What would you like to do?",
                             &fn_to_update.0);

                    match capture_failure_selection()? {
                        TestFailureSelection::Retry => continue,
                        TestFailureSelection::Skip => break,
                        TestFailureSelection::Abort => {
                            println!("\nExiting...");
                            ::std::process::exit(1);
                        }
                    }
                }
            }
        }

        Ok(())
    }
}

struct FnName(String);

impl FnName {
    // TODO this should let the user see why the test failed, or warn them if it wasn't from
    // snapshot failure
    fn success(&self) -> SnapResult<bool> {
        Ok(cmd("cargo", &["test", &self.0])
               .run()
               .chain_err(|| "unable to execute cargo")?
               .status
               .success())
    }
}

fn find_existing_snapshot_test_names() -> SnapResult<Vec<FnName>> {
    let cwd = ::std::env::current_dir()
        .chain_err(|| "unable to read cwd")?;

    let mut existing: Vec<SnapFileContents> = Vec::new();

    let snap_extension = OsStr::new("snap");
    for walk_result in WalkDir::new(cwd) {
        let entry = walk_result
            .chain_err(|| "unable to traverse project directory")?;

        if entry.path().extension() == Some(snap_extension) {
            let rdr = BufReader::new(File::open(entry.path())
                                         .chain_err(|| "unable to open snapshot file")?);
            let contents = serde_json::from_reader(rdr)
                .chain_err(|| "unable to parse snapshot file")?;
            existing.push(contents);
        }
    }

    let mut test_function_names = Vec::new();
    for snap_file in existing {
        for fun in snap_file.keys() {
            // now we need to strip crate name from the string
            let mut test_fn_chunks = fun.splitn(2, "::");

            match test_fn_chunks.next() {
                Some(_) => (),
                None => bail!("malformed test fn name: empty"),
            }

            let real_test_fn = match test_fn_chunks.next() {
                Some(n) => n,
                None => bail!("malformed test fn name: only had crate name"),
            };

            test_function_names.push(FnName(real_test_fn.to_owned()));
        }
    }
    Ok(test_function_names)
}

enum TestFailureSelection {
    Retry,
    Skip,
    Abort,
}

fn capture_failure_selection() -> SnapResult<TestFailureSelection> {
    let options = ["Retry", "Skip", "Abort"];

    let selection = Select::new()
        .items(&options)
        .interact()
        .chain_err(|| "unable to retrieve user input")?;

    if options[selection] == "Retry" {
        Ok(TestFailureSelection::Retry)
    } else if options[selection] == "Skip" {
        Ok(TestFailureSelection::Skip)
    } else if options[selection] == "Abort" {
        Ok(TestFailureSelection::Abort)
    } else {
        bail!("invalid menu selection")
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2018, Cloudflare, Inc.
// Copyright (C) 2018, Alessandro Ghedini
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#[macro_use]
extern crate log;

use std::net;

use std::collections::hash_map;
use std::collections::HashMap;

use ring::rand::*;

const LOCAL_CONN_ID_LEN: usize = 16;

const MAX_DATAGRAM_SIZE: usize = 1452;

const USAGE: &str = "Usage: server [options]

Options:
  -h --help         Show this screen.
  --listen <addr>   Listen on the given IP:port [default: 127.0.0.1:4433]
  --cert <file>     TLS certificate path [default: examples/cert.crt]
  --key <file>      TLS certificate key path [default: examples/cert.key]
  --root <dir>      Root directory [default: examples/root/]
  --name <str>      Name of the server [default: quic.tech]
";

fn main() {
    let mut buf = [0; 65535];
    let mut out = [0; MAX_DATAGRAM_SIZE];

    env_logger::init();

    let args = docopt::Docopt::new(USAGE)
                      .and_then(|dopt| dopt.parse())
                      .unwrap_or_else(|e| e.exit());

    let socket = net::UdpSocket::bind(args.get_str("--listen")).unwrap();

    let poll = mio::Poll::new().unwrap();
    let mut events = mio::Events::with_capacity(1024);

    let socket = mio::net::UdpSocket::from_socket(socket).unwrap();
    poll.register(&socket, mio::Token(0),
                  mio::Ready::readable(),
                  mio::PollOpt::edge()).unwrap();

    let mut connections: HashMap<net::SocketAddr, Box<quiche::Connection>> =
        HashMap::new();

    let mut config = quiche::Config::new(quiche::VERSION_DRAFT17).unwrap();

    config.load_cert_chain_from_pem_file(args.get_str("--cert")).unwrap();
    config.load_priv_key_from_pem_file(args.get_str("--key")).unwrap();

    config.set_idle_timeout(30);
    config.set_max_packet_size(MAX_DATAGRAM_SIZE as u64);
    config.set_initial_max_data(10_000_000);
    config.set_initial_max_stream_data_bidi_local(1_000_000);
    config.set_initial_max_stream_data_bidi_remote(1_000_000);
    config.set_initial_max_streams_bidi(100);
    config.set_initial_max_streams_uni(5);
    config.set_disable_migration(true);

    loop {
        // TODO: use event loop that properly supports timers
        let timeout = connections.values()
                                 .filter_map(|c| c.timeout())
                                 .min();

        poll.poll(&mut events, timeout).unwrap();

        'read: loop {
            if events.is_empty() {
                debug!("timed out");

                connections.values_mut().for_each(|c| c.on_timeout());

                break 'read;
            }

            let (len, src) = match socket.recv_from(&mut buf) {
                Ok(v) => v,

                Err(e) => {
                    if e.kind() == std::io::ErrorKind::WouldBlock {
                        debug!("recv() would block");
                        break 'read;
                    }

                    panic!("recv() failed: {:?}", e);
                },
            };

            debug!("got {} bytes", len);

            let buf = &mut buf[..len];

            let hdr = match quiche::Header::from_slice(buf, LOCAL_CONN_ID_LEN) {
                Ok(v) => v,

                Err(e) => {
                    error!("Parsing packet header failed: {:?}", e);
                    continue
                }
            };

            if hdr.ty == quiche::Type::VersionNegotiation {
                error!("Version negotiation invalid on the server");
                continue;
            }

            let conn = match connections.entry(src) {
                hash_map::Entry::Vacant(v) => {
                    if hdr.ty != quiche::Type::Initial {
                        error!("Packet is not Initial");
                        continue;
                    }

                    if hdr.version != quiche::VERSION_DRAFT17 {
                        warn!("Doing version negotiation");

                        let len = quiche::negotiate_version(&hdr.scid,
                                                            &hdr.dcid,
                                                            &mut out).unwrap();
                        let out = &out[..len];

                        socket.send_to(out, &src).unwrap();
                        continue;
                    }

                    let mut scid: [u8; LOCAL_CONN_ID_LEN] = [0; LOCAL_CONN_ID_LEN];
                    SystemRandom::new().fill(&mut scid[..]).unwrap();

                    // Token is always present in Initial packets.
                    let token = hdr.token.as_ref().unwrap();

                    if token.is_empty() {
                        warn!("Doing stateless retry");

                        let new_token = mint_token(&hdr, &src);

                        let len = quiche::retry(&hdr.scid, &hdr.dcid, &scid,
                                                &new_token, &mut out).unwrap();
                        let out = &out[..len];

                        socket.send_to(out, &src).unwrap();
                        continue;
                    }

                    let odcid = validate_token(&src, token);

                    if odcid == None {
                        error!("Invalid address validation token");
                        continue;
                    }

                    debug!("New connection: dcid={} scid={} lcid={}",
                           hex_dump(&hdr.dcid),
                           hex_dump(&hdr.scid),
                           hex_dump(&scid));

                    let conn = quiche::accept(&scid, odcid, &mut config).unwrap();

                    v.insert(conn)
                },

                hash_map::Entry::Occupied(v) => v.into_mut(),
            };

            // Process potentially coalesced packets.
            let read = match conn.recv(buf) {
                Ok(v)  => v,

                Err(quiche::Error::Done) => {
                    debug!("{} done reading", conn.trace_id());
                    break;
                },

                Err(e) => {
                    error!("{} recv failed: {:?}", conn.trace_id(), e);
                    conn.close(false, e.to_wire(), b"fail").unwrap();
                    break 'read;
                },
            };

            debug!("{} processed {} bytes", conn.trace_id(), read);

            let streams: Vec<u64> = conn.readable().collect();
            for s in streams {
                handle_stream(conn, s, args.get_str("--root"));
            }
        }

        for (src, conn) in &mut connections {
            loop {
                let write = match conn.send(&mut out) {
                    Ok(v) => v,

                    Err(quiche::Error::Done) => {
                        debug!("{} done writing", conn.trace_id());
                        break;
                    },

                    Err(e) => {
                        error!("{} send failed: {:?}", conn.trace_id(), e);
                        conn.close(false, e.to_wire(), b"fail").unwrap();
                        break;
                    },
                };

                // TODO: coalesce packets.
                socket.send_to(&out[..write], &src).unwrap();

                debug!("{} written {} bytes", conn.trace_id(), write);
            }
        }

        // Garbage collect closed connections.
        connections.retain(|_, ref mut c| {
            debug!("Collecting garbage");

            if c.is_closed() {
                info!("{} connection collected {:?}", c.trace_id(), c.stats());
            }

            !c.is_closed()
        });
    }
}

fn handle_stream(conn: &mut quiche::Connection, stream: u64, root: &str) {
    let stream_data = match conn.stream_recv(stream, std::usize::MAX) {
        Ok(v) => v,

        Err(quiche::Error::Done) => return,

        Err(e) => panic!("{} stream recv failed {:?}",
                         conn.trace_id(), e),
    };

    info!("{} stream {} has {} bytes (fin? {})", conn.trace_id(),
          stream, stream_data.len(), stream_data.fin());

    if stream_data.len() > 4 && &stream_data[..4] == b"GET " {
        let uri = &stream_data[4..stream_data.len()];
        let uri = String::from_utf8(uri.to_vec()).unwrap();
        let uri = String::from(uri.lines().next().unwrap());
        let uri = std::path::Path::new(&uri);
        let mut path = std::path::PathBuf::from(root);

        for c in uri.components() {
            if let std::path::Component::Normal(v) = c {
                path.push(v)
            }
        }

        info!("{} got GET request for {:?} on stream {}",
              conn.trace_id(), path, stream);

        let data = std::fs::read(path.as_path())
                    .unwrap_or_else(|_| Vec::from(String::from("Not Found!\r\n")));

        info!("{} sending response of size {} on stream {}",
              conn.trace_id(), data.len(), stream);

        if let Err(e) = conn.stream_send(stream, &data, true) {
            error!("{} stream send failed {:?}", conn.trace_id(), e);
        }
    }
}

fn mint_token(hdr: &quiche::Header, src: &net::SocketAddr) -> Vec<u8> {
    let mut token = Vec::new();

    token.extend_from_slice(b"quiche");

    let addr = match src.ip() {
        std::net::IpAddr::V4(a) => a.octets().to_vec(),
        std::net::IpAddr::V6(a) => a.octets().to_vec(),
    };

    token.extend_from_slice(&addr);
    token.extend_from_slice(&hdr.dcid);

    token
}

fn validate_token<'a>(src: &net::SocketAddr, token: &'a [u8]) -> Option<&'a [u8]> {
    if token.len() < 6 {
        return None;
    }

    if &token[..6] != b"quiche" {
        return None;
    }

    let token = &token[6..];

    let addr = match src.ip() {
        std::net::IpAddr::V4(a) => a.octets().to_vec(),
        std::net::IpAddr::V6(a) => a.octets().to_vec(),
    };

    if token.len() < addr.len() || &token[..addr.len()] != addr.as_slice() {
        return None;
    }

    let token = &token[addr.len()..];

    Some(&token[..])
}

fn hex_dump(buf: &[u8]) -> String {
    let vec: Vec<String> = buf.iter()
                              .map(|b| format!("{:02x}", b))
                              .collect();

    vec.join("")
}
<commit_msg>server: index connections by connection ID instead of peer address<commit_after>// Copyright (C) 2018, Cloudflare, Inc.
// Copyright (C) 2018, Alessandro Ghedini
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#[macro_use]
extern crate log;

use std::net;

use std::collections::HashMap;

use ring::rand::*;

const LOCAL_CONN_ID_LEN: usize = 16;

const MAX_DATAGRAM_SIZE: usize = 1452;

const USAGE: &str = "Usage: server [options]

Options:
  -h --help         Show this screen.
  --listen <addr>   Listen on the given IP:port [default: 127.0.0.1:4433]
  --cert <file>     TLS certificate path [default: examples/cert.crt]
  --key <file>      TLS certificate key path [default: examples/cert.key]
  --root <dir>      Root directory [default: examples/root/]
  --name <str>      Name of the server [default: quic.tech]
";

type ConnMap = HashMap<Vec<u8>, (net::SocketAddr, Box<quiche::Connection>)>;

fn main() {
    let mut buf = [0; 65535];
    let mut out = [0; MAX_DATAGRAM_SIZE];

    env_logger::init();

    let args = docopt::Docopt::new(USAGE)
                      .and_then(|dopt| dopt.parse())
                      .unwrap_or_else(|e| e.exit());

    let socket = net::UdpSocket::bind(args.get_str("--listen")).unwrap();

    let poll = mio::Poll::new().unwrap();
    let mut events = mio::Events::with_capacity(1024);

    let socket = mio::net::UdpSocket::from_socket(socket).unwrap();
    poll.register(&socket, mio::Token(0),
                  mio::Ready::readable(),
                  mio::PollOpt::edge()).unwrap();

    let mut connections = ConnMap::new();

    let mut config = quiche::Config::new(quiche::VERSION_DRAFT17).unwrap();

    config.load_cert_chain_from_pem_file(args.get_str("--cert")).unwrap();
    config.load_priv_key_from_pem_file(args.get_str("--key")).unwrap();

    config.set_idle_timeout(30);
    config.set_max_packet_size(MAX_DATAGRAM_SIZE as u64);
    config.set_initial_max_data(10_000_000);
    config.set_initial_max_stream_data_bidi_local(1_000_000);
    config.set_initial_max_stream_data_bidi_remote(1_000_000);
    config.set_initial_max_streams_bidi(100);
    config.set_initial_max_streams_uni(5);
    config.set_disable_migration(true);

    loop {
        // TODO: use event loop that properly supports timers
        let timeout = connections.values()
                                 .filter_map(|(_, c)| c.timeout())
                                 .min();

        poll.poll(&mut events, timeout).unwrap();

        'read: loop {
            if events.is_empty() {
                debug!("timed out");

                connections.values_mut().for_each(|(_, c)| c.on_timeout());

                break 'read;
            }

            let (len, src) = match socket.recv_from(&mut buf) {
                Ok(v) => v,

                Err(e) => {
                    if e.kind() == std::io::ErrorKind::WouldBlock {
                        debug!("recv() would block");
                        break 'read;
                    }

                    panic!("recv() failed: {:?}", e);
                },
            };

            debug!("got {} bytes", len);

            let buf = &mut buf[..len];

            let hdr = match quiche::Header::from_slice(buf, LOCAL_CONN_ID_LEN) {
                Ok(v) => v,

                Err(e) => {
                    error!("Parsing packet header failed: {:?}", e);
                    continue
                }
            };

            if hdr.ty == quiche::Type::VersionNegotiation {
                error!("Version negotiation invalid on the server");
                continue;
            }

            let (_, conn) = if !connections.contains_key(&hdr.dcid) {
                if hdr.ty != quiche::Type::Initial {
                    error!("Packet is not Initial");
                    continue;
                }

                if hdr.version != quiche::VERSION_DRAFT17 {
                    warn!("Doing version negotiation");

                    let len = quiche::negotiate_version(&hdr.scid,
                                                        &hdr.dcid,
                                                        &mut out).unwrap();
                    let out = &out[..len];

                    socket.send_to(out, &src).unwrap();
                    continue;
                }

                let mut scid: [u8; LOCAL_CONN_ID_LEN] = [0; LOCAL_CONN_ID_LEN];
                SystemRandom::new().fill(&mut scid[..]).unwrap();

                // Token is always present in Initial packets.
                let token = hdr.token.as_ref().unwrap();

                if token.is_empty() {
                    warn!("Doing stateless retry");

                    let new_token = mint_token(&hdr, &src);

                    let len = quiche::retry(&hdr.scid, &hdr.dcid, &scid,
                                            &new_token, &mut out).unwrap();
                    let out = &out[..len];

                    socket.send_to(out, &src).unwrap();
                    continue;
                }

                let odcid = validate_token(&src, token);

                if odcid == None {
                    error!("Invalid address validation token");
                    continue;
                }

                debug!("New connection: dcid={} scid={} lcid={}",
                       hex_dump(&hdr.dcid),
                       hex_dump(&hdr.scid),
                       hex_dump(&scid));

                let conn = quiche::accept(&scid, odcid, &mut config).unwrap();

                connections.insert(scid.to_vec(), (src, conn));

                connections.get_mut(&scid[..]).unwrap()
            } else {
                connections.get_mut(&hdr.dcid).unwrap()
            };

            // Process potentially coalesced packets.
            let read = match conn.recv(buf) {
                Ok(v)  => v,

                Err(quiche::Error::Done) => {
                    debug!("{} done reading", conn.trace_id());
                    break;
                },

                Err(e) => {
                    error!("{} recv failed: {:?}", conn.trace_id(), e);
                    conn.close(false, e.to_wire(), b"fail").unwrap();
                    break 'read;
                },
            };

            debug!("{} processed {} bytes", conn.trace_id(), read);

            let streams: Vec<u64> = conn.readable().collect();
            for s in streams {
                handle_stream(conn, s, args.get_str("--root"));
            }
        }

        for (peer, conn) in connections.values_mut() {
            loop {
                let write = match conn.send(&mut out) {
                    Ok(v) => v,

                    Err(quiche::Error::Done) => {
                        debug!("{} done writing", conn.trace_id());
                        break;
                    },

                    Err(e) => {
                        error!("{} send failed: {:?}", conn.trace_id(), e);
                        conn.close(false, e.to_wire(), b"fail").unwrap();
                        break;
                    },
                };

                // TODO: coalesce packets.
                socket.send_to(&out[..write], &peer).unwrap();

                debug!("{} written {} bytes", conn.trace_id(), write);
            }
        }

        // Garbage collect closed connections.
        connections.retain(|_, (_, ref mut c)| {
            debug!("Collecting garbage");

            if c.is_closed() {
                info!("{} connection collected {:?}", c.trace_id(), c.stats());
            }

            !c.is_closed()
        });
    }
}

fn handle_stream(conn: &mut quiche::Connection, stream: u64, root: &str) {
    let stream_data = match conn.stream_recv(stream, std::usize::MAX) {
        Ok(v) => v,

        Err(quiche::Error::Done) => return,

        Err(e) => panic!("{} stream recv failed {:?}",
                         conn.trace_id(), e),
    };

    info!("{} stream {} has {} bytes (fin? {})", conn.trace_id(),
          stream, stream_data.len(), stream_data.fin());

    if stream_data.len() > 4 && &stream_data[..4] == b"GET " {
        let uri = &stream_data[4..stream_data.len()];
        let uri = String::from_utf8(uri.to_vec()).unwrap();
        let uri = String::from(uri.lines().next().unwrap());
        let uri = std::path::Path::new(&uri);
        let mut path = std::path::PathBuf::from(root);

        for c in uri.components() {
            if let std::path::Component::Normal(v) = c {
                path.push(v)
            }
        }

        info!("{} got GET request for {:?} on stream {}",
              conn.trace_id(), path, stream);

        let data = std::fs::read(path.as_path())
                    .unwrap_or_else(|_| Vec::from(String::from("Not Found!\r\n")));

        info!("{} sending response of size {} on stream {}",
              conn.trace_id(), data.len(), stream);

        if let Err(e) = conn.stream_send(stream, &data, true) {
            error!("{} stream send failed {:?}", conn.trace_id(), e);
        }
    }
}

fn mint_token(hdr: &quiche::Header, src: &net::SocketAddr) -> Vec<u8> {
    let mut token = Vec::new();

    token.extend_from_slice(b"quiche");

    let addr = match src.ip() {
        std::net::IpAddr::V4(a) => a.octets().to_vec(),
        std::net::IpAddr::V6(a) => a.octets().to_vec(),
    };

    token.extend_from_slice(&addr);
    token.extend_from_slice(&hdr.dcid);

    token
}

fn validate_token<'a>(src: &net::SocketAddr, token: &'a [u8]) -> Option<&'a [u8]> {
    if token.len() < 6 {
        return None;
    }

    if &token[..6] != b"quiche" {
        return None;
    }

    let token = &token[6..];

    let addr = match src.ip() {
        std::net::IpAddr::V4(a) => a.octets().to_vec(),
        std::net::IpAddr::V6(a) => a.octets().to_vec(),
    };

    if token.len() < addr.len() || &token[..addr.len()] != addr.as_slice() {
        return None;
    }

    let token = &token[addr.len()..];

    Some(&token[..])
}

fn hex_dump(buf: &[u8]) -> String {
    let vec: Vec<String> = buf.iter()
                              .map(|b| format!("{:02x}", b))
                              .collect();

    vec.join("")
}
<|endoftext|>


<commit_before>#![feature(phase)]

#[phase(plugin)]
extern crate rustless;
extern crate rustless;

extern crate iron;
extern crate url;
extern crate serialize;
extern crate valico;
extern crate cookie;

use iron::{Iron, Chain, ChainBuilder};
use cookie::Cookie;

use valico::Builder as Valico;
use rustless::server::status;
use rustless::errors::{Error, ErrorRefExt};
use rustless::batteries::cookie::CookieExt;
use rustless::{
    Application, Api, Client, Nesting, Versioning,
    Response
};

#[deriving(Show)]
pub struct UnauthorizedError;

impl Error for UnauthorizedError {
    fn name(&self) -> &'static str {
        return "UnauthorizedError";
    }
}

fn main() {

    let app = Application::new(Api::build(|api| {
        api.prefix("api");
        api.version("v1", Versioning::Path);

        format_error!(api, UnauthorizedError, |_err, _media| {
            Some(Response::from_string(status::Unauthorized, "Please provide correct `token` parameter".to_string()))
        });

        api.namespace("admin", |admin_ns| {

            admin_ns.params(|params| {
                params.req_typed("token", Valico::string())
            });

            // Using after_validation callback to check token
            admin_ns.after_validation(callback!(|_client, params| {

                match params.get(&"token".to_string()) {
                    // We can unwrap() safely because token in validated already
                    Some(token) => if token.as_string().unwrap().as_slice() == "password1" { return Ok(()) },
                    None => ()
                }

                // Fire error from callback is token is wrong
                return Err(box UnauthorizedError as Box<Error>)

            }));

            // This `/api/admin/server_status` endpoint is secure now
            admin_ns.get("server_status", |endpoint| {
                edp_handler!(endpoint, |client, _params| {
                    {
                        let cookies = client.request.cookies();
                        let signed_cookies = cookies.signed();

                        let mut user_cookie = Cookie::new("session".to_string(), "verified".to_string());
                        signed_cookies.add(user_cookie);
                    }

                    client.text("Everything is OK".to_string())
                })
            });
        })
    }));

    let mut chain = ChainBuilder::new(app);
    chain.link(::rustless::batteries::cookie::new("secretsecretsecretsecretsecretsecretsecret".as_bytes()));

    Iron::new(chain).listen("localhost:4000").unwrap();
    println!("On 4000");

}<commit_msg>docs: fix string in example<commit_after>#![feature(phase)]

#[phase(plugin)]
extern crate rustless;
extern crate rustless;

extern crate iron;
extern crate url;
extern crate serialize;
extern crate valico;
extern crate cookie;

use iron::{Iron, Chain, ChainBuilder};
use cookie::Cookie;

use valico::Builder as Valico;
use rustless::server::status;
use rustless::errors::{Error, ErrorRefExt};
use rustless::batteries::cookie::CookieExt;
use rustless::{
    Application, Api, Client, Nesting, Versioning,
    Response
};

#[deriving(Show)]
pub struct UnauthorizedError;

impl Error for UnauthorizedError {
    fn name(&self) -> &'static str {
        return "UnauthorizedError";
    }
}

fn main() {

    let app = Application::new(Api::build(|api| {
        api.prefix("api");
        api.version("v1", Versioning::Path);

        format_error!(api, UnauthorizedError, |_err, _media| {
            Some(Response::from_string(status::Unauthorized, "Please provide correct `token` parameter".to_string()))
        });

        api.namespace("admin", |admin_ns| {

            admin_ns.params(|params| {
                params.req_typed("token", Valico::string())
            });

            // Using after_validation callback to check token
            admin_ns.after_validation(callback!(|_client, params| {

                match params.get("token") {
                    // We can unwrap() safely because token in validated already
                    Some(token) => if token.as_string().unwrap().as_slice() == "password1" { return Ok(()) },
                    None => ()
                }

                // Fire error from callback is token is wrong
                return Err(box UnauthorizedError as Box<Error>)

            }));

            // This `/api/admin/server_status` endpoint is secure now
            admin_ns.get("server_status", |endpoint| {
                edp_handler!(endpoint, |client, _params| {
                    {
                        let cookies = client.request.cookies();
                        let signed_cookies = cookies.signed();

                        let mut user_cookie = Cookie::new("session".to_string(), "verified".to_string());
                        signed_cookies.add(user_cookie);
                    }

                    client.text("Everything is OK".to_string())
                })
            });
        })
    }));

    let mut chain = ChainBuilder::new(app);
    chain.link(::rustless::batteries::cookie::new("secretsecretsecretsecretsecretsecretsecret".as_bytes()));

    Iron::new(chain).listen("localhost:4000").unwrap();
    println!("On 4000");

}<|endoftext|>