<commit_before>use std::collections::HashMap;
use std::sync::{Arc,RwLock,Mutex,mpsc};

use super::libcoinche::{bid,cards,pos,game};

pub enum ServerError {
    BadPlayerId,
    PlayInAuction,
    BidInGame,
    Bid(bid::BidError),
    Play(game::PlayError),
}

pub enum Action {
    Bid(bid::Contract),
    Coinche,
    Pass,
    Play(cards::Card),
}

#[derive(Clone)]
pub enum PlayerEvent {
    Bidded(bid::Contract),
    Coinched,
    Passed,
    CardPlayed(cards::Card),
}

// Player just joined a new party. He's given a player id, and his position.
pub struct NewPartyInfo {
    pub player_id: u32,
    pub player_pos: pos::PlayerPos,
}

// Represents an event that can happen during the game.
#[derive(Clone)]
pub enum EventType {
    // The party is cancelled. Contains an optional explanation.
    PartyCancelled(String),

    // A player did something!
    PlayerEvent(pos::PlayerPos, PlayerEvent),

    // Bid over: contains the contract and the author
    BidOver(pos::PlayerPos, bid::Contract),
    // The bid was cancelled, probably because no one bidded anything.
    // A new game is probably on its way.
    BidCancelled,

    // Trick over: contains the winner
    TrickOver(pos::PlayerPos),

    // New game: contains the first player, and the player's hand
    NewGame(pos::PlayerPos, [cards::Hand;4]),

    // Game over: contains scores
    GameOver([i32;2], pos::Team, [i32;2]),
}

pub struct Event {
    pub event: EventType,
    pub id: usize,
}

pub struct Order {
    pub author: pos::PlayerPos,
    pub action: Action
}

pub struct Server {
    party_list: RwLock<PartyList>,

    waiting_list: Mutex<Vec<mpsc::Sender<NewPartyInfo>>>,
}

pub enum Game {
    Bidding(bid::Auction),
    Playing(game::GameState),
}

pub struct Party {
    game: Game,
    events: Vec<EventType>,
    observers: Vec<mpsc::Sender<Event>>,
}

fn new_party(first: pos::PlayerPos) -> Party {
    Party {
        game: Game::Bidding(bid::new_auction(first)),
        events: Vec::new(),
        observers: Vec::new(),
    }
}

pub struct PlayerInfo {
    pub party: Arc<RwLock<Party>>,
    pub pos: pos::PlayerPos,
}

pub struct PartyList {
    pub player_map: HashMap<u32,PlayerInfo>,
}

impl PartyList {
    fn make_ids(&self) -> [u32; 4] {
        // Expect self.player_map to be locked
        [0,1,2,3]
    }
}

enum WaitResult {
    Ready(Event),
    Waiting(mpsc::Receiver<Event>),
}

enum JoinResult {
    Ready(NewPartyInfo),
    Waiting(mpsc::Receiver<NewPartyInfo>),
}

impl Server {
    pub fn join(&self) -> Option<NewPartyInfo> {
        match self.get_join_result() {
            JoinResult::Ready(info) => Some(info),
            JoinResult::Waiting(rx) => Some(rx.recv().unwrap()),
        }
    }

    fn get_join_result(&self) -> JoinResult {
        let mut waiters = self.waiting_list.lock().unwrap();
        if waiters.len() >= 3 {
            // It's a PARTEY!
            let info = self.make_party([
                                       waiters.pop().unwrap(),
                                       waiters.pop().unwrap(),
                                       waiters.pop().unwrap(),
            ]);
            return JoinResult::Ready(info);
        } else {
            let (tx,rx) = mpsc::channel();
            waiters.push(tx);
            return JoinResult::Waiting(rx);
        }
    }

    fn make_party(&self, others: [mpsc::Sender<NewPartyInfo>; 3]) -> NewPartyInfo {
        let mut list = self.party_list.write().unwrap();

        // Generate 4 new IDS
        let ids = list.make_ids();

        let party = Arc::new(RwLock::new(new_party(pos::P0)));
        // Kickstart it with a new game!

        // Prepare the players info
        for i in 0..4 {
            list.player_map.insert(ids[i], PlayerInfo {
                party: party.clone(),
                pos: pos::PlayerPos(i),
            });
        }

        // Tell everyone. They'll love it.
        for i in 0..3 {
            others[i].send(NewPartyInfo{
                player_id: ids[i],
                player_pos: pos::PlayerPos(i),
            }).unwrap();
        }

        // Even you, weird 4th dude.
        NewPartyInfo{
            player_id: ids[3],
            player_pos: pos::P3,
        }
    }

    // Play a card in the current game
    pub fn play_card(&self, player_id: u32, card: cards::Card) -> Result<Event,ServerError> {
        let list = self.party_list.read().unwrap();

        if !list.player_map.contains_key(&player_id) {
            // Bad player id!

            return Err(ServerError::BadPlayerId);
        }

        let info = list.player_map.get(&player_id).unwrap();

        let mut party = info.party.write().unwrap();

        match &mut party.game {
            &mut Game::Bidding(_) => {
                // Bad time for a card play!
                return Err(ServerError::PlayInAuction);
            },
            &mut Game::Playing(ref mut game) => {
                match game.play_card(info.pos, card) {
                    Ok(result) => {
                        // Ok, propagate the event
                    },
                    Err(err) => {
                        // Nothing to see here
                        return Err(ServerError::Play(err));
                    },
                }
            },
        }

        // Dummy event before handling the real case
        Ok(Event{
            event: EventType::BidCancelled,
            id:0
        })
    }

    // Waits until the given event_id happens
    pub fn wait(&self, player_id: u32, event_id: usize) -> Result<Event,ServerError> {
        let res = self.get_wait_result(player_id, event_id);

        let event = match res {
            None => return Err(ServerError::BadPlayerId),
            Some(WaitResult::Ready(event)) => event,
            Some(WaitResult::Waiting(rx)) => rx.recv().unwrap(),
        };

        Ok(event)
    }

    // Check if the event ID is already available. If not, returns a channel that will produce it one
    // day, so that we don't keep the locks while waiting.
    fn get_wait_result(&self, player_id: u32, event_id: usize) -> Option<WaitResult> {
        let list = self.party_list.read().unwrap();
        if !list.player_map.contains_key(&player_id) {
            return None;
        }

        let info = list.player_map.get(&player_id).unwrap();
        let mut party = info.party.write().unwrap();

        if party.events.len() > event_id {
            return Some(WaitResult::Ready(Event {
                event: party.events[event_id].clone(),
                id: event_id,
            }));
        } else if event_id > party.events.len() {
            // We are too ambitious! One event at a time!
            return None;
        }

        let (tx, rx) = mpsc::channel();
        party.observers.push(tx);

        Some(WaitResult::Waiting(rx))
    }

}

<commit_msg>Proper make_ids implementation<commit_after>extern crate rand;

use self::rand::{thread_rng,Rng};

use std::collections::HashMap;
use std::sync::{Arc,RwLock,Mutex,mpsc};

use super::libcoinche::{bid,cards,pos,game};

pub enum ServerError {
    BadPlayerId,
    PlayInAuction,
    BidInGame,
    Bid(bid::BidError),
    Play(game::PlayError),
}

pub enum Action {
    Bid(bid::Contract),
    Coinche,
    Pass,
    Play(cards::Card),
}

#[derive(Clone)]
pub enum PlayerEvent {
    Bidded(bid::Contract),
    Coinched,
    Passed,
    CardPlayed(cards::Card),
}

// Player just joined a new party. He's given a player id, and his position.
pub struct NewPartyInfo {
    pub player_id: u32,
    pub player_pos: pos::PlayerPos,
}

// Represents an event that can happen during the game.
#[derive(Clone)]
pub enum EventType {
    // The party is cancelled. Contains an optional explanation.
    PartyCancelled(String),

    // A player did something!
    PlayerEvent(pos::PlayerPos, PlayerEvent),

    // Bid over: contains the contract and the author
    BidOver(pos::PlayerPos, bid::Contract),
    // The bid was cancelled, probably because no one bidded anything.
    // A new game is probably on its way.
    BidCancelled,

    // Trick over: contains the winner
    TrickOver(pos::PlayerPos),

    // New game: contains the first player, and the player's hand
    NewGame(pos::PlayerPos, [cards::Hand;4]),

    // Game over: contains scores
    GameOver([i32;2], pos::Team, [i32;2]),
}

pub struct Event {
    pub event: EventType,
    pub id: usize,
}

pub struct Order {
    pub author: pos::PlayerPos,
    pub action: Action
}

pub struct Server {
    party_list: RwLock<PartyList>,

    waiting_list: Mutex<Vec<mpsc::Sender<NewPartyInfo>>>,
}

pub enum Game {
    Bidding(bid::Auction),
    Playing(game::GameState),
}

pub struct Party {
    game: Game,
    events: Vec<EventType>,
    observers: Vec<mpsc::Sender<Event>>,
}

fn new_party(first: pos::PlayerPos) -> Party {
    Party {
        game: Game::Bidding(bid::new_auction(first)),
        events: Vec::new(),
        observers: Vec::new(),
    }
}

pub struct PlayerInfo {
    pub party: Arc<RwLock<Party>>,
    pub pos: pos::PlayerPos,
}

pub struct PartyList {
    pub player_map: HashMap<u32,PlayerInfo>,
}

impl PartyList {
    fn make_ids(&self) -> [u32; 4] {
        // Expect self.player_map to be locked
        let mut result = [0;4];

        for i in 0..4 {
            loop {
                let id = thread_rng().next_u32();
                if self.player_map.contains_key(&id) {
                    continue;
                }
                let mut ok = true;
                for j in 0..i {
                    if result[j] == id {
                        ok = false;
                        break;
                    }
                }
                if !ok {
                    continue;
                }

                result[i] = id;
            }
        }

        result
    }
}

enum WaitResult {
    Ready(Event),
    Waiting(mpsc::Receiver<Event>),
}

enum JoinResult {
    Ready(NewPartyInfo),
    Waiting(mpsc::Receiver<NewPartyInfo>),
}

impl Server {
    pub fn join(&self) -> Option<NewPartyInfo> {
        match self.get_join_result() {
            JoinResult::Ready(info) => Some(info),
            JoinResult::Waiting(rx) => Some(rx.recv().unwrap()),
        }
    }

    fn get_join_result(&self) -> JoinResult {
        let mut waiters = self.waiting_list.lock().unwrap();
        if waiters.len() >= 3 {
            // It's a PARTEY!
            let info = self.make_party([
                                       waiters.pop().unwrap(),
                                       waiters.pop().unwrap(),
                                       waiters.pop().unwrap(),
            ]);
            return JoinResult::Ready(info);
        } else {
            let (tx,rx) = mpsc::channel();
            waiters.push(tx);
            return JoinResult::Waiting(rx);
        }
    }

    fn make_party(&self, others: [mpsc::Sender<NewPartyInfo>; 3]) -> NewPartyInfo {
        let mut list = self.party_list.write().unwrap();

        // Generate 4 new IDS
        let ids = list.make_ids();

        let party = Arc::new(RwLock::new(new_party(pos::P0)));
        // Kickstart it with a new game!

        // Prepare the players info
        for i in 0..4 {
            list.player_map.insert(ids[i], PlayerInfo {
                party: party.clone(),
                pos: pos::PlayerPos(i),
            });
        }

        // Tell everyone. They'll love it.
        for i in 0..3 {
            others[i].send(NewPartyInfo{
                player_id: ids[i],
                player_pos: pos::PlayerPos(i),
            }).unwrap();
        }

        // Even you, weird 4th dude.
        NewPartyInfo{
            player_id: ids[3],
            player_pos: pos::P3,
        }
    }

    // Play a card in the current game
    pub fn play_card(&self, player_id: u32, card: cards::Card) -> Result<Event,ServerError> {
        let list = self.party_list.read().unwrap();

        if !list.player_map.contains_key(&player_id) {
            // Bad player id!

            return Err(ServerError::BadPlayerId);
        }

        let info = list.player_map.get(&player_id).unwrap();

        let mut party = info.party.write().unwrap();

        match &mut party.game {
            &mut Game::Bidding(_) => {
                // Bad time for a card play!
                return Err(ServerError::PlayInAuction);
            },
            &mut Game::Playing(ref mut game) => {
                match game.play_card(info.pos, card) {
                    Ok(result) => {
                        // Ok, propagate the event
                    },
                    Err(err) => {
                        // Nothing to see here
                        return Err(ServerError::Play(err));
                    },
                }
            },
        }

        // Dummy event before handling the real case
        Ok(Event{
            event: EventType::BidCancelled,
            id:0
        })
    }

    // Waits until the given event_id happens
    pub fn wait(&self, player_id: u32, event_id: usize) -> Result<Event,ServerError> {
        let res = self.get_wait_result(player_id, event_id);

        let event = match res {
            None => return Err(ServerError::BadPlayerId),
            Some(WaitResult::Ready(event)) => event,
            Some(WaitResult::Waiting(rx)) => rx.recv().unwrap(),
        };

        Ok(event)
    }

    // Check if the event ID is already available. If not, returns a channel that will produce it one
    // day, so that we don't keep the locks while waiting.
    fn get_wait_result(&self, player_id: u32, event_id: usize) -> Option<WaitResult> {
        let list = self.party_list.read().unwrap();
        if !list.player_map.contains_key(&player_id) {
            return None;
        }

        let info = list.player_map.get(&player_id).unwrap();
        let mut party = info.party.write().unwrap();

        if party.events.len() > event_id {
            return Some(WaitResult::Ready(Event {
                event: party.events[event_id].clone(),
                id: event_id,
            }));
        } else if event_id > party.events.len() {
            // We are too ambitious! One event at a time!
            return None;
        }

        let (tx, rx) = mpsc::channel();
        party.observers.push(tx);

        Some(WaitResult::Waiting(rx))
    }

}

<|endoftext|>


<commit_before>use sandstorm::grain_capnp::{ui_view, ui_session};
use sandstorm::web_session_capnp::{web_session};

use std::collections::hash_map::HashMap;
use capnp::Error;
use capnp_rpc::{RpcSystem, twoparty, rpc_twoparty_capnp};
use gj::{EventLoop, Promise};
use sqlite3;

#[derive(Clone, Copy)]
pub struct UiViewImpl;

impl ui_view::Server for UiViewImpl {
    fn get_view_info(&mut self,
                     _params: ui_view::GetViewInfoParams,
                     _results: ui_view::GetViewInfoResults)
                     -> Promise<(), Error>
    {
        Promise::ok(())
    }

    fn new_session(&mut self,
                   _params: ui_view::NewSessionParams,
                   mut results: ui_view::NewSessionResults)
                   -> Promise<(), Error>
    {
        let client: web_session::Client = match WebSessionImpl::new() {
            Ok(session) => {
                web_session::ToClient::new(session).from_server::<::capnp_rpc::Server>()
            }
            Err(_e) => {
                return Promise::err(Error::failed(format!("failed to create web session")));
            }
        };
        // we need to do this dance to upcast.
        results.get().set_session(ui_session::Client { client : client.client});
        Promise::ok(())
    }
}

pub struct WebSessionImpl {
    db: sqlite3::Database,
}

unsafe impl Send for WebSessionImpl {}

impl WebSessionImpl {
    pub fn new() -> sqlite3::SqliteResult<WebSessionImpl> {
        let mut db = try!(sqlite3::open("/var/data.db"));
        db.set_busy_timeout(1000); // try for a least a second
        Ok(WebSessionImpl {
            db : db,
        })
    }
}

impl ui_session::Server for WebSessionImpl {

}

impl WebSessionImpl {

    fn is_word(&self, word : &str) -> sqlite3::SqliteResult<bool> {

        if ! word.chars().all(|c| c.is_alphanumeric()) { return Ok(false); }

        let mut cursor = try!(self.db.prepare(
            &format!("SELECT * FROM Words WHERE Word = \"{}\";", word),
            &None));

        return Ok(try!(cursor.step_row()).is_some());
    }

    fn validate_def(&self, word : &str, definition : &[&str]) -> sqlite3::SqliteResult<bool> {
        if definition.len() != word.len() { return Ok(false); }
        let mut idx = 0;
        for &d in definition.iter() {
            if !(try!(self.is_word(d)) && d.len() > 0 && d.as_bytes()[0] == word.as_bytes()[idx]) {
                return Ok(false);
            }

            idx += 1;
        }

        return Ok(true);
    }

    fn write_def(&mut self, word : &str, definition : &[&str]) -> sqlite3::SqliteResult<()> {

        let time : i64 = ::time::get_time().sec;
        let mut query = String::new();
        query.push_str(&format!("BEGIN; DELETE FROM Definitions WHERE Definee =\"{}\"; ", word));
        query.push_str("INSERT INTO Definitions(Definee, Idx, Definer) VALUES");
        let mut idx = 0usize;
        for &d in definition.iter() {
            if idx != 0 { query.push_str(","); }
            query.push_str(&format!("(\"{}\", {}, \"{}\")", word, idx, d));
            idx += 1;
        }
        query.push_str(";");
        query.push_str(&format!("DELETE FROM Log WHERE Word=\"{}\";", word));
        query.push_str(&format!("INSERT INTO Log(Word, Timestamp) VALUES(\"{}\",{});", word, time));
        query.push_str("COMMIT;");

        println!("query: {}", query);

        try!(self.db.exec(&query));

        return Ok(());
    }

    fn get_def(&self, word : &str) -> sqlite3::SqliteResult<String> {

        let mut cursor = try!(self.db.prepare(
            &format!("SELECT * FROM Definitions WHERE Definee = \"{}\";", word),
            &None));

        let mut map = HashMap::<isize, String>::new();

        loop {
            match try!(cursor.step_row()) {
                None => break,
                Some(row) => {
                    let definer = match row[&"Definer".to_string()] { sqlite3::BindArg::Text(ref t) => t.clone(), _ => panic!(), };
                    let idx = match row[&"Idx".to_string()] { sqlite3::BindArg::Integer(ref i) => i.clone(), _ => panic!(), };

                    map.insert(idx, definer);
                }
            }
        }

        if map.len() != word.len() {
            return Ok("
this word has no definition yet
".to_string());
        } else {

            let mut result = String::new();
            result.push_str("
");
            for idx in 0..(word.len() as isize) {
                let definer : &str = &map[&idx];
                result.push_str(&format!(" {word} ", word=definer));
            }
            result.push_str("
");
            return Ok(result);
        }
    }

    fn count_defs(&self) -> sqlite3::SqliteResult<(isize, isize, Vec<String>)> {
        let mut cursor = try!(self.db.prepare("SELECT COUNT(*) FROM Words;", &None));
        assert!(cursor.step() == sqlite3::ResultCode::SQLITE_ROW);
        let num_words = cursor.get_int(0);

        let mut cursor = try!(self.db.prepare("SELECT COUNT(*) FROM Definitions WHERE Idx = 0;", &None));
        assert!(cursor.step() == sqlite3::ResultCode::SQLITE_ROW);
        let defined_words = cursor.get_int(0);

        let mut recent_words = Vec::new();
        let mut cursor = try!(
            self.db.prepare("SELECT Word, Timestamp FROM Log ORDER BY Timestamp DESC LIMIT 5;", &None));
        loop {
            match try!(cursor.step_row()) {
                None => break,
                Some(row) => {
                    let word : String = match row[&"Word".to_string()] {sqlite3::BindArg::Text(ref t) => t.clone(), _ => panic!(),};
                    recent_words.push(word);
                }
            }
        }
        Ok((defined_words, num_words, recent_words))

    }

    fn construct_page_data(&mut self, path : Vec<String>, query: Option<String>) -> sqlite3::SqliteResult<PageData> {
        if path.len() == 1 && path[0] == "define" {

            let mut query_map = HashMap::<String, String>::new();
            match query {
                None => {}
                Some(q) => {
                    for (k, v) in ::url::form_urlencoded::parse(q.as_bytes()).into_owned() {
                        query_map.insert(k, v);
                    }
                }
            }

            let word : String = match query_map.get(&"word".to_string()) {
                Some(w) if try!(self.is_word(&w)) => {
                    w.clone()
                }
                _ => {
                    return Ok(PageData::Error("that's not a word".to_string()))
                }
            };
            match query_map.get(&"definition".to_string()) {
                None => {
                    let def_div = try!(self.get_def(&word));

                    return Ok(PageData::WordAndDef(word, def_div, None));
                }
                Some(def_query) => {

                    let definition : Vec<&str> = def_query.split(' ').collect();

                    if try!(self.validate_def(&word, &definition)) {

                        try!(self.write_def(&word, &definition));
                        let def_div = try!(self.get_def(&word));
                        return Ok(PageData::WordAndDef(word,
                                                       def_div,
                                                       None));
                    } else {
                        let def_div = try!(self.get_def(&word));
                        return Ok(PageData::WordAndDef(word, def_div, Some("invalid definition".to_string())))
                    }
                }
            }

        } else {
            let (num_defined, total, recent) = try!(self.count_defs());
            return Ok(PageData::HomePage(num_defined, total, recent));
        }
    }

}

const MAIN_CSS : &'static str =
    "body { font-family: Helvetica, Sans, Arial;
            font-size: medium;
             margin-left: auto;
             margin-right: auto;
             text-align: center;
     }
     div {
          padding-bottom: 10pt;
     }
    .word {
        text-align: center;
        font-size: 500%;
     }
     .err {
       font-size: 90%;
       color: #AA0000;
     }
     .title {
       text-align: center;
       font-size:500%;
     }
     ";

const HEADER : &'static str =
  r#"<title> acronymy </title><link rel="stylesheet" type="text/css" href="main.css" >
 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" >
  "#;

const LOOKUP_FORM : &'static str =
      r#"<form action="define" method="get">
          <input name="word" maxlength="100"/><button>find word</button></form>"#;

fn define_form(word :&str) -> String {
       format!("<form action=\"define\" method=\"get\">
               <input name=\"word\" value=\"{word}\" type=\"hidden\"/>
               <input name=\"definition\" maxlength=\"2000\"/>
                   <button>submit definition</button></form>", word=word)
}

enum PageData {
    Error(String),
    WordAndDef(String, String, Option<String>),
    HomePage(isize, isize, Vec<String>),
}

fn construct_html(page_data : PageData) -> String {
    let mut result = String::new();
    result.push_str(&format!("{}", HEADER));

    const HOME_LINK : &'static str = "home";
    match page_data {
        PageData::Error(e) => {
            result.push_str(&format!("
 {}
", e));
            result.push_str(LOOKUP_FORM);
            result.push_str(HOME_LINK);
        }
        PageData::WordAndDef(word, def_div, err) => {
            result.push_str(&format!("
{}
", word));
            result.push_str(&def_div);

            match err {
                None => {}
                Some(e) => {
                    result.push_str(&format!("
{}
", e));
                }
            }

            result.push_str(&define_form(&word));
            result.push_str(HOME_LINK);
        }
        PageData::HomePage(num_defined, total, recent) => {
            result.push_str("
Acronymy
");
            result.push_str("
A user-editable, acronym-only dictionary.
");
            result.push_str(&format!("
So far, we have defined {} out of {} words.
",
                                     num_defined, total));
            if recent.len() > 0 {
                result.push_str("
Recently modified words: ");
                let mut idx = 0usize;
                for w in recent.iter() {
                    if idx != 0 {
                        result.push_str(", ");
                    }
                    result.push_str(&format!("{word}", word=*w));
                    idx += 1;
                }
                result.push_str(".
");
            }
            result.push_str(LOOKUP_FORM);
        }
    }

    result.push_str("");
    result
}

impl web_session::Server for WebSessionImpl {
    fn get(&mut self,
           params: web_session::GetParams,
           mut results: web_session::GetResults)
        -> Promise<(), Error>
    {
        println!("GET");
        {
            let params = pry!(params.get());
            let results = results.get();
            let raw_path = format!("/{}", pry!(params.get_path()));
            let mut content = results.init_content();
            content.set_mime_type("text/html");

            // TODO: there's got to be a cleaner way to do this.
            let (path, query) = ::url::Url::parse("http://example.com").map(|base| {
                let query = base.query().map(|s| s.to_string());
                base.join(&raw_path).map(move |url| {
                    url.path_segments().map(move |segs| {
                        let seq_strings: Vec<String> = segs.map(|seg| seg.to_string()).collect();
                        (seq_strings, query)
                    }).unwrap_or((Vec::new(), None))
                })
            }).unwrap_or(Ok((Vec::new(), None))).unwrap_or((Vec::new(), None));

            println!("path = {}", raw_path);

            if raw_path == "/main.css" {
                content.get_body().set_bytes(MAIN_CSS.as_bytes())
            } else {
                let page_data = match self.construct_page_data(path, query) {
                    Err(e) => { PageData::Error(format!("database error: {:?} ({})", e, self.db.get_errmsg())) }
                    Ok(page_data) => { page_data }
                };
                content.get_body().set_bytes(construct_html(page_data).as_bytes());
            }
        }
        Promise::ok(())
    }
}

pub fn main() -> ::capnp::Result<()> {
    let args: Vec<String> = ::std::env::args().collect();
    if args.len() == 4 && args[1] == "--init" {
        println!("initializing...");
        let initdb_path = ::std::path::Path::new(&args[2]);
        let proddb_path = ::std::path::Path::new(&args[3]);
        println!("copying database from {} to {}", args[2], args[3]);
        try!(::std::fs::copy(initdb_path, proddb_path));
        println!("success!");
    }

    EventLoop::top_level(move |wait_scope| -> Result<(), Box<::std::error::Error>> {
        let mut event_port = try!(::gjio::EventPort::new());
        let network = event_port.get_network();

        // sandstorm launches us with a connection on file descriptor 3
	    let stream = try!(unsafe { network.wrap_raw_socket_descriptor(3) });

        let client = ui_view::ToClient::new(UiViewImpl).from_server::<::capnp_rpc::Server>();

        let network =
            twoparty::VatNetwork::new(stream.clone(), stream,
                                      rpc_twoparty_capnp::Side::Client, Default::default());

        let _rpc_system = RpcSystem::new(Box::new(network), Some(client.client));
        Promise::never_done().wait(wait_scope, &mut event_port)
    }).expect("top level error");
    Ok(())
}

<commit_msg>ask for the query at the correct place<commit_after>use sandstorm::grain_capnp::{ui_view, ui_session};
use sandstorm::web_session_capnp::{web_session};

use std::collections::hash_map::HashMap;
use capnp::Error;
use capnp_rpc::{RpcSystem, twoparty, rpc_twoparty_capnp};
use gj::{EventLoop, Promise};
use sqlite3;

#[derive(Clone, Copy)]
pub struct UiViewImpl;

impl ui_view::Server for UiViewImpl {
    fn get_view_info(&mut self,
                     _params: ui_view::GetViewInfoParams,
                     _results: ui_view::GetViewInfoResults)
                     -> Promise<(), Error>
    {
        Promise::ok(())
    }

    fn new_session(&mut self,
                   _params: ui_view::NewSessionParams,
                   mut results: ui_view::NewSessionResults)
                   -> Promise<(), Error>
    {
        let client: web_session::Client = match WebSessionImpl::new() {
            Ok(session) => {
                web_session::ToClient::new(session).from_server::<::capnp_rpc::Server>()
            }
            Err(_e) => {
                return Promise::err(Error::failed(format!("failed to create web session")));
            }
        };
        // we need to do this dance to upcast.
        results.get().set_session(ui_session::Client { client : client.client});
        Promise::ok(())
    }
}

pub struct WebSessionImpl {
    db: sqlite3::Database,
}

unsafe impl Send for WebSessionImpl {}

impl WebSessionImpl {
    pub fn new() -> sqlite3::SqliteResult<WebSessionImpl> {
        let mut db = try!(sqlite3::open("/var/data.db"));
        db.set_busy_timeout(1000); // try for a least a second
        Ok(WebSessionImpl {
            db : db,
        })
    }
}

impl ui_session::Server for WebSessionImpl {

}

impl WebSessionImpl {

    fn is_word(&self, word : &str) -> sqlite3::SqliteResult<bool> {

        if ! word.chars().all(|c| c.is_alphanumeric()) { return Ok(false); }

        let mut cursor = try!(self.db.prepare(
            &format!("SELECT * FROM Words WHERE Word = \"{}\";", word),
            &None));

        return Ok(try!(cursor.step_row()).is_some());
    }

    fn validate_def(&self, word : &str, definition : &[&str]) -> sqlite3::SqliteResult<bool> {
        if definition.len() != word.len() { return Ok(false); }
        let mut idx = 0;
        for &d in definition.iter() {
            if !(try!(self.is_word(d)) && d.len() > 0 && d.as_bytes()[0] == word.as_bytes()[idx]) {
                return Ok(false);
            }

            idx += 1;
        }

        return Ok(true);
    }

    fn write_def(&mut self, word : &str, definition : &[&str]) -> sqlite3::SqliteResult<()> {

        let time : i64 = ::time::get_time().sec;
        let mut query = String::new();
        query.push_str(&format!("BEGIN; DELETE FROM Definitions WHERE Definee =\"{}\"; ", word));
        query.push_str("INSERT INTO Definitions(Definee, Idx, Definer) VALUES");
        let mut idx = 0usize;
        for &d in definition.iter() {
            if idx != 0 { query.push_str(","); }
            query.push_str(&format!("(\"{}\", {}, \"{}\")", word, idx, d));
            idx += 1;
        }
        query.push_str(";");
        query.push_str(&format!("DELETE FROM Log WHERE Word=\"{}\";", word));
        query.push_str(&format!("INSERT INTO Log(Word, Timestamp) VALUES(\"{}\",{});", word, time));
        query.push_str("COMMIT;");

        println!("query: {}", query);

        try!(self.db.exec(&query));

        return Ok(());
    }

    fn get_def(&self, word : &str) -> sqlite3::SqliteResult<String> {

        let mut cursor = try!(self.db.prepare(
            &format!("SELECT * FROM Definitions WHERE Definee = \"{}\";", word),
            &None));

        let mut map = HashMap::<isize, String>::new();

        loop {
            match try!(cursor.step_row()) {
                None => break,
                Some(row) => {
                    let definer = match row[&"Definer".to_string()] { sqlite3::BindArg::Text(ref t) => t.clone(), _ => panic!(), };
                    let idx = match row[&"Idx".to_string()] { sqlite3::BindArg::Integer(ref i) => i.clone(), _ => panic!(), };

                    map.insert(idx, definer);
                }
            }
        }

        if map.len() != word.len() {
            return Ok("
this word has no definition yet
".to_string());
        } else {

            let mut result = String::new();
            result.push_str("
");
            for idx in 0..(word.len() as isize) {
                let definer : &str = &map[&idx];
                result.push_str(&format!(" {word} ", word=definer));
            }
            result.push_str("
");
            return Ok(result);
        }
    }

    fn count_defs(&self) -> sqlite3::SqliteResult<(isize, isize, Vec<String>)> {
        let mut cursor = try!(self.db.prepare("SELECT COUNT(*) FROM Words;", &None));
        assert!(cursor.step() == sqlite3::ResultCode::SQLITE_ROW);
        let num_words = cursor.get_int(0);

        let mut cursor = try!(self.db.prepare("SELECT COUNT(*) FROM Definitions WHERE Idx = 0;", &None));
        assert!(cursor.step() == sqlite3::ResultCode::SQLITE_ROW);
        let defined_words = cursor.get_int(0);

        let mut recent_words = Vec::new();
        let mut cursor = try!(
            self.db.prepare("SELECT Word, Timestamp FROM Log ORDER BY Timestamp DESC LIMIT 5;", &None));
        loop {
            match try!(cursor.step_row()) {
                None => break,
                Some(row) => {
                    let word : String = match row[&"Word".to_string()] {sqlite3::BindArg::Text(ref t) => t.clone(), _ => panic!(),};
                    recent_words.push(word);
                }
            }
        }
        Ok((defined_words, num_words, recent_words))

    }

    fn construct_page_data(&mut self, path : Vec<String>, query: Option<String>) -> sqlite3::SqliteResult<PageData> {
        if path.len() == 1 && path[0] == "define" {

            let mut query_map = HashMap::<String, String>::new();
            match query {
                None => {}
                Some(q) => {
                    for (k, v) in ::url::form_urlencoded::parse(q.as_bytes()).into_owned() {
                        query_map.insert(k, v);
                    }
                }
            }

            let word : String = match query_map.get(&"word".to_string()) {
                Some(w) if try!(self.is_word(&w)) => {
                    w.clone()
                }
                _ => {
                    return Ok(PageData::Error("that's not a word".to_string()))
                }
            };
            match query_map.get(&"definition".to_string()) {
                None => {
                    let def_div = try!(self.get_def(&word));

                    return Ok(PageData::WordAndDef(word, def_div, None));
                }
                Some(def_query) => {

                    let definition : Vec<&str> = def_query.split(' ').collect();

                    if try!(self.validate_def(&word, &definition)) {

                        try!(self.write_def(&word, &definition));
                        let def_div = try!(self.get_def(&word));
                        return Ok(PageData::WordAndDef(word,
                                                       def_div,
                                                       None));
                    } else {
                        let def_div = try!(self.get_def(&word));
                        return Ok(PageData::WordAndDef(word, def_div, Some("invalid definition".to_string())))
                    }
                }
            }

        } else {
            let (num_defined, total, recent) = try!(self.count_defs());
            return Ok(PageData::HomePage(num_defined, total, recent));
        }
    }

}

const MAIN_CSS : &'static str =
    "body { font-family: Helvetica, Sans, Arial;
            font-size: medium;
             margin-left: auto;
             margin-right: auto;
             text-align: center;
     }
     div {
          padding-bottom: 10pt;
     }
    .word {
        text-align: center;
        font-size: 500%;
     }
     .err {
       font-size: 90%;
       color: #AA0000;
     }
     .title {
       text-align: center;
       font-size:500%;
     }
     ";

const HEADER : &'static str =
  r#"<title> acronymy </title><link rel="stylesheet" type="text/css" href="main.css" >
 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" >
  "#;

const LOOKUP_FORM : &'static str =
      r#"<form action="define" method="get">
          <input name="word" maxlength="100"/><button>find word</button></form>"#;

fn define_form(word :&str) -> String {
       format!("<form action=\"define\" method=\"get\">
               <input name=\"word\" value=\"{word}\" type=\"hidden\"/>
               <input name=\"definition\" maxlength=\"2000\"/>
                   <button>submit definition</button></form>", word=word)
}

enum PageData {
    Error(String),
    WordAndDef(String, String, Option<String>),
    HomePage(isize, isize, Vec<String>),
}

fn construct_html(page_data : PageData) -> String {
    let mut result = String::new();
    result.push_str(&format!("{}", HEADER));

    const HOME_LINK : &'static str = "home";
    match page_data {
        PageData::Error(e) => {
            result.push_str(&format!("
 {}
", e));
            result.push_str(LOOKUP_FORM);
            result.push_str(HOME_LINK);
        }
        PageData::WordAndDef(word, def_div, err) => {
            result.push_str(&format!("
{}
", word));
            result.push_str(&def_div);

            match err {
                None => {}
                Some(e) => {
                    result.push_str(&format!("
{}
", e));
                }
            }

            result.push_str(&define_form(&word));
            result.push_str(HOME_LINK);
        }
        PageData::HomePage(num_defined, total, recent) => {
            result.push_str("
Acronymy
");
            result.push_str("
A user-editable, acronym-only dictionary.
");
            result.push_str(&format!("
So far, we have defined {} out of {} words.
",
                                     num_defined, total));
            if recent.len() > 0 {
                result.push_str("
Recently modified words: ");
                let mut idx = 0usize;
                for w in recent.iter() {
                    if idx != 0 {
                        result.push_str(", ");
                    }
                    result.push_str(&format!("{word}", word=*w));
                    idx += 1;
                }
                result.push_str(".
");
            }
            result.push_str(LOOKUP_FORM);
        }
    }

    result.push_str("");
    result
}

impl web_session::Server for WebSessionImpl {
    fn get(&mut self,
           params: web_session::GetParams,
           mut results: web_session::GetResults)
        -> Promise<(), Error>
    {
        println!("GET");
        {
            let params = pry!(params.get());
            let results = results.get();
            let raw_path = format!("/{}", pry!(params.get_path()));
            let mut content = results.init_content();
            content.set_mime_type("text/html");

            // TODO: there's got to be a cleaner way to do this.
            let (path, query) = ::url::Url::parse("http://example.com").map(|base| {
                base.join(&raw_path).map(|url| {
                    let query = url.query().map(|s| s.to_string());
                    url.path_segments().map(move |segs| {
                        let seq_strings: Vec<String> = segs.map(|seg| seg.to_string()).collect();
                        (seq_strings, query)
                    }).unwrap_or((Vec::new(), None))
                })
            }).unwrap_or(Ok((Vec::new(), None))).unwrap_or((Vec::new(), None));

            println!("path = {:?}, query = {:?}", path, query);

            if raw_path == "/main.css" {
                content.get_body().set_bytes(MAIN_CSS.as_bytes())
            } else {
                let page_data = match self.construct_page_data(path, query) {
                    Err(e) => { PageData::Error(format!("database error: {:?} ({})", e, self.db.get_errmsg())) }
                    Ok(page_data) => { page_data }
                };
                content.get_body().set_bytes(construct_html(page_data).as_bytes());
            }
        }
        Promise::ok(())
    }
}

pub fn main() -> ::capnp::Result<()> {
    let args: Vec<String> = ::std::env::args().collect();
    if args.len() == 4 && args[1] == "--init" {
        println!("initializing...");
        let initdb_path = ::std::path::Path::new(&args[2]);
        let proddb_path = ::std::path::Path::new(&args[3]);
        println!("copying database from {} to {}", args[2], args[3]);
        try!(::std::fs::copy(initdb_path, proddb_path));
        println!("success!");
    }

    EventLoop::top_level(move |wait_scope| -> Result<(), Box<::std::error::Error>> {
        let mut event_port = try!(::gjio::EventPort::new());
        let network = event_port.get_network();

        // sandstorm launches us with a connection on file descriptor 3
	    let stream = try!(unsafe { network.wrap_raw_socket_descriptor(3) });

        let client = ui_view::ToClient::new(UiViewImpl).from_server::<::capnp_rpc::Server>();

        let network =
            twoparty::VatNetwork::new(stream.clone(), stream,
                                      rpc_twoparty_capnp::Side::Client, Default::default());

        let _rpc_system = RpcSystem::new(Box::new(network), Some(client.client));
        Promise::never_done().wait(wait_scope, &mut event_port)
    }).expect("top level error");
    Ok(())
}

<|endoftext|>


<commit_before>//! # Socket code around `libc`
//!
//! ## Notes
//!
//! This module provides a low level one-to-one mapping between `libc` system call wrappers
//! with defaults specific to netlink sockets as well as a higher level API for simplification
//! of netlink code.

use std::io;
use std::os::unix::io::{AsRawFd,IntoRawFd,RawFd};
use std::marker::PhantomData;
use std::mem::{zeroed,size_of};
#[cfg(feature = "stream")]
use std::time::Duration;

use libc::{self,c_int,c_void};
#[cfg(feature = "evented")]
use mio::{self,Evented};
#[cfg(feature = "stream")]
use tokio::prelude::{Async,Stream};

use {Nl,MemRead,MemWrite,MAX_NL_LENGTH};
use err::NlError;
use ffi::{NlFamily,GenlId,CtrlCmd,CtrlAttr,CtrlAttrMcastGrp,NlmF};
use genlhdr::GenlHdr;
use nlhdr::{NlHdr,NlAttrHdr};

/// Handle for the socket file descriptor
#[cfg(feature = "stream")]
pub struct NlSocket<T, P> {
    fd: c_int,
    poll: mio::Poll,
    data_type: PhantomData<T>,
    data_payload: PhantomData<P>,
}

/// Handle for the socket file descriptor
#[cfg(not(feature = "stream"))]
pub struct NlSocket<T, P> {
    fd: c_int,
    data_type: PhantomData<T>,
    data_payload: PhantomData<P>,
}

impl<T, P> NlSocket<T, P> where T: Nl, P: Nl {
    /// Wrapper around `socket()` syscall filling in the netlink-specific information
    #[cfg(feature = "stream")]
    pub fn new(proto: NlFamily) -> Result<Self, io::Error> {
        let fd = match unsafe {
            libc::socket(libc::AF_NETLINK, libc::SOCK_RAW, proto.into())
        } {
            i if i >= 0 => Ok(i),
            _ => Err(io::Error::last_os_error()),
        }?;
        let poll = mio::Poll::new()?;
        let socket = NlSocket { fd, poll, data_type: PhantomData, data_payload: PhantomData };
        socket.register(&socket.poll, mio::Token(0), mio::Ready::readable(), mio::PollOpt::edge())?;
        Ok(socket)
    }

    /// Wrapper around `socket()` syscall filling in the netlink-specific information
    #[cfg(not(feature = "stream"))]
    pub fn new(proto: NlFamily) -> Result<Self, io::Error> {
        let fd = match unsafe {
            libc::socket(libc::AF_NETLINK, libc::SOCK_RAW, proto.into())
        } {
            i if i >= 0 => Ok(i),
            _ => Err(io::Error::last_os_error()),
        }?;
        Ok(NlSocket { fd, data_type: PhantomData, data_payload: PhantomData })
    }

    /// Use this function to bind to a netlink ID and subscribe to groups. See netlink(7)
    /// man pages for more information on netlink IDs and groups.
    pub fn bind(&mut self, pid: Option<u32>, groups: Option<u32>) -> Result<(), io::Error> {
        let mut nladdr = unsafe { zeroed::<libc::sockaddr_nl>() };
        nladdr.nl_family = libc::AF_NETLINK as u16;
        nladdr.nl_pid = pid.unwrap_or(0);
        nladdr.nl_groups = groups.unwrap_or(0);
        match unsafe {
            libc::bind(self.fd, &nladdr as *const _ as *const libc::sockaddr,
                       size_of::<libc::sockaddr_nl>() as u32)
        } {
            i if i >= 0 => Ok(()),
            _ => Err(io::Error::last_os_error()),
        }
    }

    /// Send message encoded as byte slice to the netlink ID specified in the netlink header
    /// (`neli::nlhdr::NlHdr`).
    pub fn send(&mut self, buf: MemRead, flags: i32) -> Result<isize, io::Error> {
        match unsafe {
            libc::send(self.fd, buf.as_slice() as *const _ as *const c_void, buf.len(), flags)
        } {
            i if i >= 0 => Ok(i),
            _ => Err(io::Error::last_os_error()),
        }
    }

    /// Convenience function to send an `NlHdr` struct
    pub fn send_nl(&mut self, msg: NlHdr<T, P>, buf_sz: Option<usize>) -> Result<(), NlError> {
        let mut mem = MemWrite::new_vec(buf_sz.or(Some(MAX_NL_LENGTH)));
        msg.serialize(&mut mem)?;
        self.send(mem.into(), 0)?;
        Ok(())
    }

    /// Receive message encoded as byte slice from the netlink socket.
    pub fn recv<'a>(&mut self, mut buf: MemWrite<'a>, flags: i32)
            -> Result<MemRead<'a>, io::Error> {
        match unsafe {
            libc::recv(self.fd, buf.as_mut_slice() as *mut _ as *mut c_void, buf.len(), flags)
        } {
            i if i >= 0 => Ok(buf.shrink(i as usize).into()),
            _ => Err(io::Error::last_os_error()),
        }
    }

    /// Convenience function to receive an `NlHdr` struct
    pub fn recv_nl(&mut self, buf_sz: Option<usize>) -> Result<NlHdr<T, P>, NlError> {
        let mem_write = MemWrite::new_vec(buf_sz.or(Some(MAX_NL_LENGTH)));
        let mut mem_read = self.recv(mem_write, 0)?;
        Ok(NlHdr::<T, P>::deserialize(&mut mem_read)?)
    }

    /// Equivalent of `socket` and `bind` calls.
    pub fn connect(proto: NlFamily, pid: Option<u32>, groups: Option<u32>)
                   -> Result<Self, io::Error> {
        let mut s = try!(NlSocket::new(proto));
        try!(s.bind(pid, groups));
        Ok(s)
    }
}

impl NlSocket<GenlId, GenlHdr<CtrlCmd>> {
    /// Create generic netlink resolution socket
    pub fn new_genl() -> Result<NlSocket<GenlId, GenlHdr<CtrlCmd>>, io::Error> {
        Self::connect(NlFamily::Generic, None, None)
    }

    fn get_genl_family(&mut self, family_name: &str)
            -> Result<NlHdr<GenlId, GenlHdr<CtrlCmd>>, NlError> {
        let attrs = vec![NlAttrHdr::new_str_payload(None, CtrlAttr::FamilyName, family_name)?];
        let genlhdr = GenlHdr::new(CtrlCmd::Getfamily, 2, attrs)?;
        let nlhdr = NlHdr::new(None, GenlId::Ctrl,
                               vec![NlmF::Request, NlmF::Ack], None, None, genlhdr);
        let mut mem_req = MemWrite::new_vec(Some(nlhdr.asize()));
        nlhdr.serialize(&mut mem_req)?;
        self.send(mem_req.into(), 0)?;

        let mem_resp = MemWrite::new_vec(Some(4096));
        let mut mem_resp_recv = self.recv(mem_resp, 0)?;
        Ok(NlHdr::<GenlId, GenlHdr<CtrlCmd>>::deserialize(&mut mem_resp_recv)?)
    }

    /// Convenience function for resolving a `&str` containing the multicast group name to a
    /// numeric netlink ID
    pub fn resolve_genl_family(&mut self, family_name: &str) -> Result<u16, NlError> {
        let nlhdr = self.get_genl_family(family_name)?;
        let mut handle = nlhdr.nl_payload.get_attr_handle::<CtrlAttr>();
        Ok(handle.get_payload_as::<u16>(CtrlAttr::FamilyId)?)
    }

    /// Convenience function for resolving a `&str` containing the multicast group name to a
    /// numeric netlink ID
    pub fn resolve_nl_mcast_group(&mut self, family_name: &str, mcast_name: &str)
            -> Result<u32, NlError> {
        let nlhdr = self.get_genl_family(family_name)?;
        let mut handle = nlhdr.nl_payload.get_attr_handle::<CtrlAttr>();
        let mut mcast_groups = handle.get_nested_attributes::<u16>(CtrlAttr::McastGroups)?;
        mcast_groups.parse_nested_attributes()?;
        let mut id = None;
        if let Some(iter) = mcast_groups.iter() {
            for attribute in iter {
                let attribute_len = attribute.nla_len;
                let mut handle = attribute.get_attr_handle();
                let string = handle.get_payload_with::<String>(CtrlAttrMcastGrp::Name,
                    Some(attribute_len as usize))?;
                if string.as_str() == mcast_name {
                    id = handle.get_payload_as::<u32>(CtrlAttrMcastGrp::Id).ok();
                }
            }
        }
        id.ok_or(NlError::new("Failed to resolve multicast group ID"))
    }
}

impl<T, P> AsRawFd for NlSocket<T, P> {
    fn as_raw_fd(&self) -> RawFd {
        self.fd
    }
}

impl<T, P> IntoRawFd for NlSocket<T, P> {
    fn into_raw_fd(self) -> RawFd {
        self.fd
    }
}

#[cfg(feature = "stream")]
impl<T, P> Stream for NlSocket<T, P> where T: Nl, P: Nl {
    type Item = NlHdr<T, P>;
    type Error = ();

    fn poll(&mut self) -> Result<Async<Option<Self::Item>>, Self::Error> {
        let mem = MemWrite::new_vec(Some(MAX_NL_LENGTH));
        let mut events = mio::Events::with_capacity(1);
        match self.poll.poll(&mut events, Some(Duration::from_secs(0))) {
            Ok(_) => (),
            Err(_) => return Err(()),
        };
        if let Some(event) = events.iter().nth(0) {
            if !event.readiness().is_readable() {
                return Ok(Async::NotReady);
            }
        }
        let mut mem_read = match self.recv(mem, 0) {
            Ok(mr) => mr,
            Err(_) => return Err(()),
        };
        if mem_read.as_slice().len() == 0 {
            return Ok(Async::Ready(None));
        }
        let hdr = match NlHdr::<T, P>::deserialize(&mut mem_read) {
            Ok(h) => h,
            Err(_) => return Err(()),
        };
        Ok(Async::Ready(Some(hdr)))
    }
}

#[cfg(feature = "evented")]
impl<T, P> Evented for NlSocket<T, P> {
    fn register(&self, poll: &mio::Poll, token: mio::Token, interest: mio::Ready,
                opts: mio::PollOpt) -> io::Result<()> {
        poll.register(&mio::unix::EventedFd(&self.as_raw_fd()), token, interest, opts)
    }

    fn reregister(&self, poll: &mio::Poll, token: mio::Token, interest: mio::Ready,
                  opts: mio::PollOpt) -> io::Result<()> {
        poll.reregister(&mio::unix::EventedFd(&self.as_raw_fd()), token, interest, opts)
    }

    fn deregister(&self, poll: &mio::Poll) -> io::Result<()> {
        poll.deregister(&mio::unix::EventedFd(&self.as_raw_fd()))
    }
}

impl<T, P> Drop for NlSocket<T, P> {
    /// Closes underlying file descriptor to avoid file descriptor leaks.
    fn drop(&mut self) {
        unsafe { libc::close(self.fd); }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use ffi::{CtrlCmd,Nlmsg};
    use genlhdr::GenlHdr;

    #[test]
    fn test_socket_creation() {
       NlSocket::<Nlmsg, GenlHdr<CtrlCmd>>::connect(NlFamily::Generic, None, None).unwrap();
    }

    #[ignore]
    #[test]
    fn test_genl_family_resolve() {
        let mut sock = NlSocket::new_genl().unwrap();
        assert_eq!(19, sock.resolve_genl_family("nl80211").unwrap());
    }

    #[ignore]
    #[test]
    fn test_nl_mcast_group_resolve() {
        let mut sock = NlSocket::new_genl().unwrap();
        assert_eq!(5, sock.resolve_nl_mcast_group("nl80211", "mlme").unwrap());
    }
}
<commit_msg>Fix send_nl to use asize as size is known before serialization<commit_after>//! # Socket code around `libc`
//!
//! ## Notes
//!
//! This module provides a low level one-to-one mapping between `libc` system call wrappers
//! with defaults specific to netlink sockets as well as a higher level API for simplification
//! of netlink code.

use std::io;
use std::os::unix::io::{AsRawFd,IntoRawFd,RawFd};
use std::marker::PhantomData;
use std::mem::{zeroed,size_of};
#[cfg(feature = "stream")]
use std::time::Duration;

use libc::{self,c_int,c_void};
#[cfg(feature = "evented")]
use mio::{self,Evented};
#[cfg(feature = "stream")]
use tokio::prelude::{Async,Stream};

use {Nl,MemRead,MemWrite,MAX_NL_LENGTH};
use err::NlError;
use ffi::{NlFamily,GenlId,CtrlCmd,CtrlAttr,CtrlAttrMcastGrp,NlmF};
use genlhdr::GenlHdr;
use nlhdr::{NlHdr,NlAttrHdr};

/// Handle for the socket file descriptor
#[cfg(feature = "stream")]
pub struct NlSocket<T, P> {
    fd: c_int,
    poll: mio::Poll,
    data_type: PhantomData<T>,
    data_payload: PhantomData<P>,
}

/// Handle for the socket file descriptor
#[cfg(not(feature = "stream"))]
pub struct NlSocket<T, P> {
    fd: c_int,
    data_type: PhantomData<T>,
    data_payload: PhantomData<P>,
}

impl<T, P> NlSocket<T, P> where T: Nl, P: Nl {
    /// Wrapper around `socket()` syscall filling in the netlink-specific information
    #[cfg(feature = "stream")]
    pub fn new(proto: NlFamily) -> Result<Self, io::Error> {
        let fd = match unsafe {
            libc::socket(libc::AF_NETLINK, libc::SOCK_RAW, proto.into())
        } {
            i if i >= 0 => Ok(i),
            _ => Err(io::Error::last_os_error()),
        }?;
        let poll = mio::Poll::new()?;
        let socket = NlSocket { fd, poll, data_type: PhantomData, data_payload: PhantomData };
        socket.register(&socket.poll, mio::Token(0), mio::Ready::readable(), mio::PollOpt::edge())?;
        Ok(socket)
    }

    /// Wrapper around `socket()` syscall filling in the netlink-specific information
    #[cfg(not(feature = "stream"))]
    pub fn new(proto: NlFamily) -> Result<Self, io::Error> {
        let fd = match unsafe {
            libc::socket(libc::AF_NETLINK, libc::SOCK_RAW, proto.into())
        } {
            i if i >= 0 => Ok(i),
            _ => Err(io::Error::last_os_error()),
        }?;
        Ok(NlSocket { fd, data_type: PhantomData, data_payload: PhantomData })
    }

    /// Use this function to bind to a netlink ID and subscribe to groups. See netlink(7)
    /// man pages for more information on netlink IDs and groups.
    pub fn bind(&mut self, pid: Option<u32>, groups: Option<u32>) -> Result<(), io::Error> {
        let mut nladdr = unsafe { zeroed::<libc::sockaddr_nl>() };
        nladdr.nl_family = libc::AF_NETLINK as u16;
        nladdr.nl_pid = pid.unwrap_or(0);
        nladdr.nl_groups = groups.unwrap_or(0);
        match unsafe {
            libc::bind(self.fd, &nladdr as *const _ as *const libc::sockaddr,
                       size_of::<libc::sockaddr_nl>() as u32)
        } {
            i if i >= 0 => Ok(()),
            _ => Err(io::Error::last_os_error()),
        }
    }

    /// Send message encoded as byte slice to the netlink ID specified in the netlink header
    /// (`neli::nlhdr::NlHdr`).
    pub fn send(&mut self, buf: MemRead, flags: i32) -> Result<isize, io::Error> {
        match unsafe {
            libc::send(self.fd, buf.as_slice() as *const _ as *const c_void, buf.len(), flags)
        } {
            i if i >= 0 => Ok(i),
            _ => Err(io::Error::last_os_error()),
        }
    }

    /// Convenience function to send an `NlHdr` struct
    pub fn send_nl(&mut self, msg: NlHdr<T, P>) -> Result<(), NlError> {
        let mut mem = MemWrite::new_vec(Some(msg.asize()));
        msg.serialize(&mut mem)?;
        self.send(mem.into(), 0)?;
        Ok(())
    }

    /// Receive message encoded as byte slice from the netlink socket.
    pub fn recv<'a>(&mut self, mut buf: MemWrite<'a>, flags: i32)
            -> Result<MemRead<'a>, io::Error> {
        match unsafe {
            libc::recv(self.fd, buf.as_mut_slice() as *mut _ as *mut c_void, buf.len(), flags)
        } {
            i if i >= 0 => Ok(buf.shrink(i as usize).into()),
            _ => Err(io::Error::last_os_error()),
        }
    }

    /// Convenience function to receive an `NlHdr` struct
    pub fn recv_nl(&mut self, buf_sz: Option<usize>) -> Result<NlHdr<T, P>, NlError> {
        let mem_write = MemWrite::new_vec(buf_sz.or(Some(MAX_NL_LENGTH)));
        let mut mem_read = self.recv(mem_write, 0)?;
        Ok(NlHdr::<T, P>::deserialize(&mut mem_read)?)
    }

    /// Equivalent of `socket` and `bind` calls.
    pub fn connect(proto: NlFamily, pid: Option<u32>, groups: Option<u32>)
                   -> Result<Self, io::Error> {
        let mut s = try!(NlSocket::new(proto));
        try!(s.bind(pid, groups));
        Ok(s)
    }
}

impl NlSocket<GenlId, GenlHdr<CtrlCmd>> {
    /// Create generic netlink resolution socket
    pub fn new_genl() -> Result<NlSocket<GenlId, GenlHdr<CtrlCmd>>, io::Error> {
        Self::connect(NlFamily::Generic, None, None)
    }

    fn get_genl_family(&mut self, family_name: &str)
            -> Result<NlHdr<GenlId, GenlHdr<CtrlCmd>>, NlError> {
        let attrs = vec![NlAttrHdr::new_str_payload(None, CtrlAttr::FamilyName, family_name)?];
        let genlhdr = GenlHdr::new(CtrlCmd::Getfamily, 2, attrs)?;
        let nlhdr = NlHdr::new(None, GenlId::Ctrl,
                               vec![NlmF::Request, NlmF::Ack], None, None, genlhdr);
        let mut mem_req = MemWrite::new_vec(Some(nlhdr.asize()));
        nlhdr.serialize(&mut mem_req)?;
        self.send(mem_req.into(), 0)?;

        let mem_resp = MemWrite::new_vec(Some(4096));
        let mut mem_resp_recv = self.recv(mem_resp, 0)?;
        Ok(NlHdr::<GenlId, GenlHdr<CtrlCmd>>::deserialize(&mut mem_resp_recv)?)
    }

    /// Convenience function for resolving a `&str` containing the multicast group name to a
    /// numeric netlink ID
    pub fn resolve_genl_family(&mut self, family_name: &str) -> Result<u16, NlError> {
        let nlhdr = self.get_genl_family(family_name)?;
        let mut handle = nlhdr.nl_payload.get_attr_handle::<CtrlAttr>();
        Ok(handle.get_payload_as::<u16>(CtrlAttr::FamilyId)?)
    }

    /// Convenience function for resolving a `&str` containing the multicast group name to a
    /// numeric netlink ID
    pub fn resolve_nl_mcast_group(&mut self, family_name: &str, mcast_name: &str)
            -> Result<u32, NlError> {
        let nlhdr = self.get_genl_family(family_name)?;
        let mut handle = nlhdr.nl_payload.get_attr_handle::<CtrlAttr>();
        let mut mcast_groups = handle.get_nested_attributes::<u16>(CtrlAttr::McastGroups)?;
        mcast_groups.parse_nested_attributes()?;
        let mut id = None;
        if let Some(iter) = mcast_groups.iter() {
            for attribute in iter {
                let attribute_len = attribute.nla_len;
                let mut handle = attribute.get_attr_handle();
                let string = handle.get_payload_with::<String>(CtrlAttrMcastGrp::Name,
                    Some(attribute_len as usize))?;
                if string.as_str() == mcast_name {
                    id = handle.get_payload_as::<u32>(CtrlAttrMcastGrp::Id).ok();
                }
            }
        }
        id.ok_or(NlError::new("Failed to resolve multicast group ID"))
    }
}

impl<T, P> AsRawFd for NlSocket<T, P> {
    fn as_raw_fd(&self) -> RawFd {
        self.fd
    }
}

impl<T, P> IntoRawFd for NlSocket<T, P> {
    fn into_raw_fd(self) -> RawFd {
        self.fd
    }
}

#[cfg(feature = "stream")]
impl<T, P> Stream for NlSocket<T, P> where T: Nl, P: Nl {
    type Item = NlHdr<T, P>;
    type Error = ();

    fn poll(&mut self) -> Result<Async<Option<Self::Item>>, Self::Error> {
        let mem = MemWrite::new_vec(Some(MAX_NL_LENGTH));
        let mut events = mio::Events::with_capacity(1);
        match self.poll.poll(&mut events, Some(Duration::from_secs(0))) {
            Ok(_) => (),
            Err(_) => return Err(()),
        };
        if let Some(event) = events.iter().nth(0) {
            if !event.readiness().is_readable() {
                return Ok(Async::NotReady);
            }
        }
        let mut mem_read = match self.recv(mem, 0) {
            Ok(mr) => mr,
            Err(_) => return Err(()),
        };
        if mem_read.as_slice().len() == 0 {
            return Ok(Async::Ready(None));
        }
        let hdr = match NlHdr::<T, P>::deserialize(&mut mem_read) {
            Ok(h) => h,
            Err(_) => return Err(()),
        };
        Ok(Async::Ready(Some(hdr)))
    }
}

#[cfg(feature = "evented")]
impl<T, P> Evented for NlSocket<T, P> {
    fn register(&self, poll: &mio::Poll, token: mio::Token, interest: mio::Ready,
                opts: mio::PollOpt) -> io::Result<()> {
        poll.register(&mio::unix::EventedFd(&self.as_raw_fd()), token, interest, opts)
    }

    fn reregister(&self, poll: &mio::Poll, token: mio::Token, interest: mio::Ready,
                  opts: mio::PollOpt) -> io::Result<()> {
        poll.reregister(&mio::unix::EventedFd(&self.as_raw_fd()), token, interest, opts)
    }

    fn deregister(&self, poll: &mio::Poll) -> io::Result<()> {
        poll.deregister(&mio::unix::EventedFd(&self.as_raw_fd()))
    }
}

impl<T, P> Drop for NlSocket<T, P> {
    /// Closes underlying file descriptor to avoid file descriptor leaks.
    fn drop(&mut self) {
        unsafe { libc::close(self.fd); }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use ffi::{CtrlCmd,Nlmsg};
    use genlhdr::GenlHdr;

    #[test]
    fn test_socket_creation() {
       NlSocket::<Nlmsg, GenlHdr<CtrlCmd>>::connect(NlFamily::Generic, None, None).unwrap();
    }

    #[ignore]
    #[test]
    fn test_genl_family_resolve() {
        let mut sock = NlSocket::new_genl().unwrap();
        assert_eq!(19, sock.resolve_genl_family("nl80211").unwrap());
    }

    #[ignore]
    #[test]
    fn test_nl_mcast_group_resolve() {
        let mut sock = NlSocket::new_genl().unwrap();
        assert_eq!(5, sock.resolve_nl_mcast_group("nl80211", "mlme").unwrap());
    }
}
<|endoftext|>


<commit_before>use libc;

use std::ffi::CStr;
use std::io::{self, Write};
use std::mem;
use std::os::raw::c_char;
use std::slice;
use std::str;
use ctxt::get_ctxt;
use mem::ptr::Ptr;
use object::{IntArray, Str};

pub extern "C" fn assert(val: bool) {
    if !val {
        unsafe {
            println!("assert failed");
            libc::_exit(101);
        }
    }
}

pub extern "C" fn to_string(val: i32) -> Str {
    let ctxt = get_ctxt();
    let mut gc = ctxt.gc.lock().unwrap();
    let buffer = val.to_string();

    Str::from_buffer(&mut gc, buffer.as_bytes())

}

pub extern "C" fn print(val: Str) {
    unsafe {
        let buf = CStr::from_ptr(val.data() as *const c_char);
        io::stdout().write(buf.to_bytes()).unwrap();
    };
}

pub extern "C" fn println(val: Str) {
    print(val);
    println!("");
}

pub extern "C" fn strcmp(lhs: Str, rhs: Str) -> i32 {
    unsafe {
        libc::strcmp(lhs.data() as *const i8, rhs.data() as *const i8)
    }
}

pub extern "C" fn strcat(lhs: Str, rhs: Str) -> Str {
    let ctxt = get_ctxt();
    let mut gc = ctxt.gc.lock().unwrap();

    Str::concat(&mut gc, lhs, rhs)
}

pub extern "C" fn gc_alloc(size: usize) -> Ptr {
    let ctxt = get_ctxt();
    let mut gc = ctxt.gc.lock().unwrap();

    gc.alloc(size)
}

pub extern "C" fn int_array_empty(ptr: Ptr) -> Ptr {
    let data = IntArray::empty();

    unsafe { *(ptr.raw() as *mut IntArray) = data; }

    ptr
}

pub extern "C" fn int_array_elem(ptr: Ptr, len: i32, value: i32) -> Ptr {
    let ctxt = get_ctxt();
    let mut gc = ctxt.gc.lock().unwrap();

    let data = IntArray::with_element(&mut gc, len as usize, value as isize);

    unsafe { *(ptr.raw() as *mut IntArray) = data; }

    ptr
}

pub extern "C" fn int_array_len(ptr: *const IntArray) -> i32 {
    let array = unsafe { &*ptr };

    array.len() as i32
}

pub extern "C" fn int_array_get(ptr: *const IntArray, ind: i32) -> i32 {
    let array = unsafe { &*ptr };

    array.get(ind)
}

pub extern "C" fn int_array_set(ptr: *const IntArray, ind: i32, value: i32) {
    let array = unsafe { &*ptr };

    array.set(ind, value);
}

pub extern "C" fn argc() -> i32 {
    let ctxt = get_ctxt();

    if let Some(ref args) = ctxt.args.arg_argument {
        args.len() as i32
    } else {
        0
    }
}

pub extern "C" fn argv(ind: i32) -> Str {
    let ctxt = get_ctxt();

    if let Some(ref args) = ctxt.args.arg_argument {
        if ind >= 0 && ind < args.len() as i32 {
            let mut gc = ctxt.gc.lock().unwrap();
            let value = &args[ind as usize];

            return Str::from_buffer(&mut gc, value.as_bytes());
        }
    }

    panic!("argument does not exist");
}

pub extern "C" fn parse(val: Str) -> i32 {
    let slice = unsafe { slice::from_raw_parts(val.data(), val.len()) };
    let val = str::from_utf8(slice).unwrap();

    val.parse::<i32>().unwrap_or(0)
}
<commit_msg>removed unused get/set fct for IntArray<commit_after>use libc;

use std::ffi::CStr;
use std::io::{self, Write};
use std::mem;
use std::os::raw::c_char;
use std::slice;
use std::str;
use ctxt::get_ctxt;
use mem::ptr::Ptr;
use object::{IntArray, Str};

pub extern "C" fn assert(val: bool) {
    if !val {
        unsafe {
            println!("assert failed");
            libc::_exit(101);
        }
    }
}

pub extern "C" fn to_string(val: i32) -> Str {
    let ctxt = get_ctxt();
    let mut gc = ctxt.gc.lock().unwrap();
    let buffer = val.to_string();

    Str::from_buffer(&mut gc, buffer.as_bytes())

}

pub extern "C" fn print(val: Str) {
    unsafe {
        let buf = CStr::from_ptr(val.data() as *const c_char);
        io::stdout().write(buf.to_bytes()).unwrap();
    };
}

pub extern "C" fn println(val: Str) {
    print(val);
    println!("");
}

pub extern "C" fn strcmp(lhs: Str, rhs: Str) -> i32 {
    unsafe {
        libc::strcmp(lhs.data() as *const i8, rhs.data() as *const i8)
    }
}

pub extern "C" fn strcat(lhs: Str, rhs: Str) -> Str {
    let ctxt = get_ctxt();
    let mut gc = ctxt.gc.lock().unwrap();

    Str::concat(&mut gc, lhs, rhs)
}

pub extern "C" fn gc_alloc(size: usize) -> Ptr {
    let ctxt = get_ctxt();
    let mut gc = ctxt.gc.lock().unwrap();

    gc.alloc(size)
}

pub extern "C" fn int_array_empty(ptr: Ptr) -> Ptr {
    let data = IntArray::empty();

    unsafe { *(ptr.raw() as *mut IntArray) = data; }

    ptr
}

pub extern "C" fn int_array_elem(ptr: Ptr, len: i32, value: i32) -> Ptr {
    let ctxt = get_ctxt();
    let mut gc = ctxt.gc.lock().unwrap();

    let data = IntArray::with_element(&mut gc, len as usize, value as isize);

    unsafe { *(ptr.raw() as *mut IntArray) = data; }

    ptr
}

pub extern "C" fn int_array_len(ptr: *const IntArray) -> i32 {
    let array = unsafe { &*ptr };

    array.len() as i32
}

pub extern "C" fn argc() -> i32 {
    let ctxt = get_ctxt();

    if let Some(ref args) = ctxt.args.arg_argument {
        args.len() as i32
    } else {
        0
    }
}

pub extern "C" fn argv(ind: i32) -> Str {
    let ctxt = get_ctxt();

    if let Some(ref args) = ctxt.args.arg_argument {
        if ind >= 0 && ind < args.len() as i32 {
            let mut gc = ctxt.gc.lock().unwrap();
            let value = &args[ind as usize];

            return Str::from_buffer(&mut gc, value.as_bytes());
        }
    }

    panic!("argument does not exist");
}

pub extern "C" fn parse(val: Str) -> i32 {
    let slice = unsafe { slice::from_raw_parts(val.data(), val.len()) };
    let val = str::from_utf8(slice).unwrap();

    val.parse::<i32>().unwrap_or(0)
}
<|endoftext|>


<commit_before>use std::io::{Read, Write, Result};
use std::net::{ToSocketAddrs, SocketAddr};
use socket::UtpSocket;

/// A structure that represents a uTP (Micro Transport Protocol) stream between a local socket and a
/// remote socket.
///
/// The connection will be closed when the value is dropped (either explicitly or when it goes out of
/// scope).
///
/// # Examples
///
/// ```no_run
/// use utp::UtpStream;
/// use std::io::{Read, Write};
///
/// let mut stream = UtpStream::bind("127.0.0.1:1234").unwrap();
/// let _ = stream.write(&[1]);
/// let _ = stream.read(&mut [0; 1000]);
/// ```
pub struct UtpStream {
    socket: UtpSocket,
}

impl UtpStream {
    /// Creates a uTP stream listening on the given address.
    ///
    /// The address type can be any implementor of the `ToSocketAddr` trait. See its documentation
    /// for concrete examples.
    ///
    /// If more than one valid address is specified, only the first will be used.
    pub fn bind<A: ToSocketAddrs>(addr: A) -> Result<UtpStream> {
        UtpSocket::bind(addr).and_then(|s| Ok(UtpStream { socket: s }))
    }

    /// Opens a uTP connection to a remote host by hostname or IP address.
    ///
    /// The address type can be any implementor of the `ToSocketAddr` trait. See its documentation
    /// for concrete examples.
    ///
    /// If more than one valid address is specified, only the first will be used.
    pub fn connect<A: ToSocketAddrs>(dst: A) -> Result<UtpStream> {
        // Port 0 means the operating system gets to choose it
        let my_addr = match dst.to_socket_addrs().unwrap().next().unwrap() {
            SocketAddr::V4(_) => "0.0.0.0:0",
            SocketAddr::V6(_) => ":::0",
        };
        UtpSocket::bind(my_addr)
            .and_then(|s| s.connect(dst))
            .and_then(|s| Ok(UtpStream { socket: s }))
    }

    /// Gracefully closes connection to peer.
    ///
    /// This method allows both peers to receive all packets still in
    /// flight.
    pub fn close(&mut self) -> Result<()> {
        self.socket.close()
    }
}

impl Read for UtpStream {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        self.socket.recv_from(buf).map(|(read, _src)| read)
    }
}

impl Write for UtpStream {
    fn write(&mut self, buf: &[u8]) -> Result<usize> {
        self.socket.send_to(buf)
    }

    fn flush(&mut self) -> Result<()> {
        self.socket.flush()
    }
}
<commit_msg>Add `Into` trait for conversion from socket to stream.<commit_after>use std::io::{Read, Write, Result};
use std::net::{ToSocketAddrs, SocketAddr};
use socket::UtpSocket;

/// A structure that represents a uTP (Micro Transport Protocol) stream between a local socket and a
/// remote socket.
///
/// The connection will be closed when the value is dropped (either explicitly or when it goes out of
/// scope).
///
/// # Examples
///
/// ```no_run
/// use utp::UtpStream;
/// use std::io::{Read, Write};
///
/// let mut stream = UtpStream::bind("127.0.0.1:1234").unwrap();
/// let _ = stream.write(&[1]);
/// let _ = stream.read(&mut [0; 1000]);
/// ```
pub struct UtpStream {
    socket: UtpSocket,
}

impl UtpStream {
    /// Creates a uTP stream listening on the given address.
    ///
    /// The address type can be any implementor of the `ToSocketAddr` trait. See its documentation
    /// for concrete examples.
    ///
    /// If more than one valid address is specified, only the first will be used.
    pub fn bind<A: ToSocketAddrs>(addr: A) -> Result<UtpStream> {
        UtpSocket::bind(addr).and_then(|s| Ok(UtpStream { socket: s }))
    }

    /// Opens a uTP connection to a remote host by hostname or IP address.
    ///
    /// The address type can be any implementor of the `ToSocketAddr` trait. See its documentation
    /// for concrete examples.
    ///
    /// If more than one valid address is specified, only the first will be used.
    pub fn connect<A: ToSocketAddrs>(dst: A) -> Result<UtpStream> {
        // Port 0 means the operating system gets to choose it
        let my_addr = match dst.to_socket_addrs().unwrap().next().unwrap() {
            SocketAddr::V4(_) => "0.0.0.0:0",
            SocketAddr::V6(_) => ":::0",
        };
        UtpSocket::bind(my_addr)
            .and_then(|s| s.connect(dst))
            .and_then(|s| Ok(UtpStream { socket: s }))
    }

    /// Gracefully closes connection to peer.
    ///
    /// This method allows both peers to receive all packets still in
    /// flight.
    pub fn close(&mut self) -> Result<()> {
        self.socket.close()
    }
}

impl Read for UtpStream {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        self.socket.recv_from(buf).map(|(read, _src)| read)
    }
}

impl Write for UtpStream {
    fn write(&mut self, buf: &[u8]) -> Result<usize> {
        self.socket.send_to(buf)
    }

    fn flush(&mut self) -> Result<()> {
        self.socket.flush()
    }
}

impl Into<UtpStream> for UtpSocket {
    fn into(self) -> UtpStream {
        UtpStream { socket: self }
    }
}
<|endoftext|>


<commit_before>use nom::{ConsumerState, ErrorKind, HexDisplay, IResult, Move};

use metadata::{Metadata, StreamInfo, metadata_parser};
use frame::{frame_parser, Frame};

enum ParserState {
  Marker,
  Metadata,
  Frame,
}

pub struct Stream {
  pub info: StreamInfo,
  pub metadata: Vec<Metadata>,
  pub frames: Vec<Frame>,
  state: ParserState,
  consumer_state: ConsumerState<(), ErrorKind, Move>,
}

named!(pub stream_parser <&[u8], Stream>,
  chain!(
    blocks: metadata_parser ~
    frames: many1!(apply!(frame_parser, &blocks.0)),
    move|| {
      let consumed = Move::Consume(0);

      Stream {
        info: blocks.0,
        metadata: blocks.1,
        frames: frames,
        state: ParserState::Marker,
        consumer_state: ConsumerState::Continue(consumed),
      }
    }
  )
);

impl Stream {
  fn handle_marker(&mut self, input: &[u8]) {
    match tag!(input, "fLaC") {
      IResult::Done(i, _)       => {
        let offset   = input.offset(i);
        let consumed = Move::Consume(offset);

        self.state          = ParserState::Metadata;
        self.consumer_state = ConsumerState::Continue(consumed);
      }
      IResult::Error(_)         => {
        let kind = ErrorKind::Custom(0);

        self.consumer_state = ConsumerState::Error(kind);
      }
      IResult::Incomplete(size) => {
        let needed = Move::Await(size);

        self.consumer_state = ConsumerState::Continue(needed);
      }
    }
  }

  fn handle_metadata(&mut self, input: &[u8]) {
    match metadata::block(input) {
      IResult::Done(i, block) => {
        let offset   = input.offset(i);
        let consumed = Move::Consume(offset);
        let is_last  = block.is_last;

        if let metadata::Data::StreamInfo(info) = block.data {
          self.info = info;
        } else {
          self.metadata.push(block);
        }

        if is_last {
          self.state = ParserState::Frame;
        }

        self.consumer_state = ConsumerState::Continue(consumed);
      }
      IResult::Error(_)       => {
        let kind = ErrorKind::Custom(1);

        self.consumer_state = ConsumerState::Error(kind);
      }
      IResult::Incomplete(s)  => {
        let size = if let Needed::Size(length) = s {
          length
        } else {
          1024
        };
        let needed = Move::Await(Needed::Size(size));

        self.consumer_state = ConsumerState::Continue(needed);
      }
    }
  }
}
<commit_msg>Add a implementation for handling frames<commit_after>use nom::{ConsumerState, ErrorKind, HexDisplay, IResult, Move};

use metadata::{Metadata, StreamInfo, metadata_parser};
use frame::{frame_parser, Frame};

enum ParserState {
  Marker,
  Metadata,
  Frame,
}

pub struct Stream {
  pub info: StreamInfo,
  pub metadata: Vec<Metadata>,
  pub frames: Vec<Frame>,
  state: ParserState,
  consumer_state: ConsumerState<(), ErrorKind, Move>,
}

named!(pub stream_parser <&[u8], Stream>,
  chain!(
    blocks: metadata_parser ~
    frames: many1!(apply!(frame_parser, &blocks.0)),
    move|| {
      let consumed = Move::Consume(0);

      Stream {
        info: blocks.0,
        metadata: blocks.1,
        frames: frames,
        state: ParserState::Marker,
        consumer_state: ConsumerState::Continue(consumed),
      }
    }
  )
);

impl Stream {
  fn handle_marker(&mut self, input: &[u8]) {
    match tag!(input, "fLaC") {
      IResult::Done(i, _)       => {
        let offset   = input.offset(i);
        let consumed = Move::Consume(offset);

        self.state          = ParserState::Metadata;
        self.consumer_state = ConsumerState::Continue(consumed);
      }
      IResult::Error(_)         => {
        let kind = ErrorKind::Custom(0);

        self.consumer_state = ConsumerState::Error(kind);
      }
      IResult::Incomplete(size) => {
        let needed = Move::Await(size);

        self.consumer_state = ConsumerState::Continue(needed);
      }
    }
  }

  fn handle_metadata(&mut self, input: &[u8]) {
    match metadata::block(input) {
      IResult::Done(i, block) => {
        let offset   = input.offset(i);
        let consumed = Move::Consume(offset);
        let is_last  = block.is_last;

        if let metadata::Data::StreamInfo(info) = block.data {
          self.info = info;
        } else {
          self.metadata.push(block);
        }

        if is_last {
          self.state = ParserState::Frame;
        }

        self.consumer_state = ConsumerState::Continue(consumed);
      }
      IResult::Error(_)       => {
        let kind = ErrorKind::Custom(1);

        self.consumer_state = ConsumerState::Error(kind);
      }
      IResult::Incomplete(s)  => {
        let size = if let Needed::Size(length) = s {
          length
        } else {
          1024
        };
        let needed = Move::Await(Needed::Size(size));

        self.consumer_state = ConsumerState::Continue(needed);
      }
    }
  }

  fn handle_frame(&mut self, input: &[u8]) {
    match frame_parser(input, &self.info) {
      IResult::Done(i, frame) => {
        let offset   = input.offset(i);
        let consumed = Move::Consume(offset);

        self.frames.push(frame);

        self.consumer_state = ConsumerState::Continue(consumed);
      }
      IResult::Error(_)       => {
        let kind = ErrorKind::Custom(2);

        self.consumer_state = ConsumerState::Error(kind);
      }
      IResult::Incomplete(s)  => {
        let size = if let Needed::Size(length) = s {
          length
        } else {
          self.info.max_frame_size as usize
        };
        let needed = Move::Await(Needed::Size(size));

        self.consumer_state = ConsumerState::Continue(needed);
      }
    }
  }
}
<|endoftext|>


<commit_before>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use address::Address;

/// A symbol within an executable or library. This is a named address.
#[derive(Debug)]
pub struct Symbol {
    /// The [address] of this symbol.
    ///
    /// [address]: struct.Address.html
    pub address: Address,
    /// The name of this symbol.
    pub name: String,
}

impl Symbol {
    /// Construct a `Symbol`.
    pub fn new(address: Address, name: &str) -> Self {
        Symbol {
            address: address,
            name: name.to_owned(),
        }
    }
}
<commit_msg>Link doc for address.<commit_after>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use address::Address;

/// A symbol within an executable or library. This is a named [address].
///
/// [address]: struct.Address.html
#[derive(Debug)]
pub struct Symbol {
    /// The [address] of this symbol.
    ///
    /// [address]: struct.Address.html
    pub address: Address,
    /// The name of this symbol.
    pub name: String,
}

impl Symbol {
    /// Construct a `Symbol`.
    pub fn new(address: Address, name: &str) -> Self {
        Symbol {
            address: address,
            name: name.to_owned(),
        }
    }
}
<|endoftext|>


<commit_before>use alloc::collections::VecDeque;
use alloc::vec::Vec;
use core::arch::asm;
use core::fmt::Write;
use core::hint;
use core::sync::atomic::{AtomicBool, Ordering};
use log::{Level, Metadata, Record};
use spin::Mutex;

/// Disable logging directly to the built-in vga buffer.
/// This MUST NOT BE done before memory map has been initialized,
/// or it causes page faults. (Requires allocation)
static DISABLE_DIRECT_VGA: AtomicBool = AtomicBool::new(false);

pub fn disable_direct_vga() {
    DISABLE_DIRECT_VGA.store(true, Ordering::Release);
}

/********************************* PORT E9 ***********************************/

struct PortE9;

static PORT: Mutex<cpuio::UnsafePort<u8>> = Mutex::new(unsafe { cpuio::UnsafePort::new(0xe9) });

/// Allow formatting
impl ::core::fmt::Write for PortE9 {
    fn write_str(&mut self, s: &str) -> ::core::fmt::Result {
        let mut port = PORT.lock();
        unsafe {
            for byte in s.bytes() {
                assert!(byte != 0);
                if byte == b'\n' {
                    port.write(b'\r');
                    port.write(b'\n');
                } else if 0x20 <= byte && byte <= 0x7e {
                    port.write(byte);
                } else {
                    port.write(b'?');
                    bochs_magic_bp!();
                    loop {
                        unsafe {
                            asm!("cli; hlt");
                        }
                    }
                }
            }
        }
        Ok(()) // Success. Always.
    }
}

static mut PORT_E9: PortE9 = PortE9;

macro_rules! e9_print {
    ($fmt:expr, $($arg:tt)*) => (
        unsafe {
            PORT_E9.write_fmt(format_args!(concat!($fmt, "\n"), $($arg)*)).unwrap()
        }
    );
}

/******************************* UART SERIAL *********************************/

static UART_LOCK: AtomicBool = AtomicBool::new(false);

struct Uart;

/// Allow formatting
impl ::core::fmt::Write for Uart {
    fn write_str(&mut self, s: &str) -> ::core::fmt::Result {
        use crate::driver::uart::{has_com1, write_com1};
        if has_com1() {
            // Acquire lock
            while UART_LOCK
                .compare_exchange_weak(false, true, Ordering::SeqCst, Ordering::SeqCst)
                .is_err()
            {
                hint::spin_loop();
            }

            for byte in s.bytes() {
                assert!(byte != 0);
                if byte == b'\n' {
                    write_com1(b'\r');
                    write_com1(b'\n');
                } else if 0x20 <= byte && byte <= 0x7e {
                    write_com1(byte);
                } else {
                    write_com1(b'?');
                    bochs_magic_bp!();
                    loop {
                        unsafe {
                            asm!("cli; hlt");
                        }
                    }
                }
            }

            // Release lock
            UART_LOCK.store(false, Ordering::SeqCst);
        }
        Ok(()) // Success. Always.
    }
}

static mut UART: Uart = Uart;

macro_rules! uart_print {
    ($fmt:expr, $($arg:tt)*) => (
        unsafe {
            UART.write_fmt(format_args!(concat!($fmt, "\n"), $($arg)*)).unwrap()
        }
    );
}

/**************************** BUFFER + SYSCALL *******************************/

lazy_static::lazy_static! {
    /// Write ahead log for kernel log messages
    static ref WRITE_AHEAD_LOG: Mutex<VecDeque<u8>> = Mutex::new(VecDeque::new());
}

pub fn syscall_read(buffer: &mut [u8]) -> usize {
    let mut wal = WRITE_AHEAD_LOG.try_lock().unwrap();
    let count = wal.len().min(buffer.len());
    for (i, b) in wal.drain(..count).enumerate() {
        buffer[i] = b;
    }
    count
}

/***************************** LOGGER ITSELF ********************************/

struct SystemLogger;

// pub const LEVEL_SCREEN: log::Level = log::Level::Info;
pub const LEVEL_SCREEN: log::Level = log::Level::Debug;
// pub const LEVEL_PORTE9: log::Level = log::Level::Trace;
pub const LEVEL_PORTE9: log::Level = log::Level::Debug;

impl log::Log for SystemLogger {
    fn enabled(&self, metadata: &Metadata) -> bool {
        metadata.level() <= LEVEL_SCREEN || metadata.level() <= LEVEL_PORTE9
    }

    fn log(&self, record: &Record) {
        let level = record.metadata().level();
        if level <= LEVEL_PORTE9 {
            e9_print!(
                "{:30} [{}] {:5} {}",
                record.target(),
                crate::smp::current_processor_id(),
                record.level(),
                record.args()
            );

            uart_print!(
                "{:30} [{}] {:5} {}",
                record.target(),
                crate::smp::current_processor_id(),
                record.level(),
                record.args()
            );
        }
        if level <= LEVEL_SCREEN {
            if crate::memory::can_allocate() {
                let message = format!(
                    "{:5} {} - {}\n",
                    record.level(),
                    record.target(),
                    record.args()
                );
                let mut wal = WRITE_AHEAD_LOG.lock();
                wal.extend(message.bytes());
            }

            if !DISABLE_DIRECT_VGA.load(Ordering::Acquire) {
                rprintln!(
                    "{:5} {} - {}",
                    record.level(),
                    record.target(),
                    record.args()
                );
            }
        }
    }

    fn flush(&self) {}
}

static LOGGER: SystemLogger = SystemLogger;

pub fn enable() {
    log::set_logger(&LOGGER).unwrap();
    log::set_max_level(log::LevelFilter::Trace);
}
<commit_msg>Output utf-8 characters to e9-hack and UART<commit_after>use alloc::collections::VecDeque;
use alloc::vec::Vec;
use core::arch::asm;
use core::fmt::Write;
use core::hint;
use core::sync::atomic::{AtomicBool, Ordering};
use log::{Level, Metadata, Record};
use spin::Mutex;

/// Disable logging directly to the built-in vga buffer.
/// This MUST NOT BE done before memory map has been initialized,
/// or it causes page faults. (Requires allocation)
static DISABLE_DIRECT_VGA: AtomicBool = AtomicBool::new(false);

pub fn disable_direct_vga() {
    DISABLE_DIRECT_VGA.store(true, Ordering::Release);
}

/********************************* PORT E9 ***********************************/

struct PortE9;

static PORT: Mutex<cpuio::UnsafePort<u8>> = Mutex::new(unsafe { cpuio::UnsafePort::new(0xe9) });

/// Allow formatting
impl ::core::fmt::Write for PortE9 {
    fn write_str(&mut self, s: &str) -> ::core::fmt::Result {
        let mut port = PORT.lock();
        unsafe {
            for byte in s.bytes() {
                assert!(byte != 0);
                if byte == b'\n' {
                    port.write(b'\r');
                    port.write(b'\n');
                } else {
                    port.write(byte);
                }
            }
        }
        Ok(()) // Success. Always.
    }
}

static mut PORT_E9: PortE9 = PortE9;

macro_rules! e9_print {
    ($fmt:expr, $($arg:tt)*) => (
        unsafe {
            PORT_E9.write_fmt(format_args!(concat!($fmt, "\n"), $($arg)*)).unwrap()
        }
    );
}

/******************************* UART SERIAL *********************************/

static UART_LOCK: AtomicBool = AtomicBool::new(false);

struct Uart;

/// Allow formatting
impl ::core::fmt::Write for Uart {
    fn write_str(&mut self, s: &str) -> ::core::fmt::Result {
        use crate::driver::uart::{has_com1, write_com1};
        if has_com1() {
            // Acquire lock
            while UART_LOCK
                .compare_exchange_weak(false, true, Ordering::SeqCst, Ordering::SeqCst)
                .is_err()
            {
                hint::spin_loop();
            }

            for byte in s.bytes() {
                assert!(byte != 0);
                if byte == b'\n' {
                    write_com1(b'\r');
                    write_com1(b'\n');
                } else {
                    write_com1(byte);
                }
            }

            // Release lock
            UART_LOCK.store(false, Ordering::SeqCst);
        }
        Ok(()) // Success. Always.
    }
}

static mut UART: Uart = Uart;

macro_rules! uart_print {
    ($fmt:expr, $($arg:tt)*) => (
        unsafe {
            UART.write_fmt(format_args!(concat!($fmt, "\n"), $($arg)*)).unwrap()
        }
    );
}

/**************************** BUFFER + SYSCALL *******************************/

lazy_static::lazy_static! {
    /// Write ahead log for kernel log messages
    static ref WRITE_AHEAD_LOG: Mutex<VecDeque<u8>> = Mutex::new(VecDeque::new());
}

pub fn syscall_read(buffer: &mut [u8]) -> usize {
    let mut wal = WRITE_AHEAD_LOG.try_lock().unwrap();
    let count = wal.len().min(buffer.len());
    for (i, b) in wal.drain(..count).enumerate() {
        buffer[i] = b;
    }
    count
}

/***************************** LOGGER ITSELF ********************************/

struct SystemLogger;

// pub const LEVEL_SCREEN: log::Level = log::Level::Info;
pub const LEVEL_SCREEN: log::Level = log::Level::Debug;
// pub const LEVEL_PORTE9: log::Level = log::Level::Trace;
pub const LEVEL_PORTE9: log::Level = log::Level::Debug;

impl log::Log for SystemLogger {
    fn enabled(&self, metadata: &Metadata) -> bool {
        metadata.level() <= LEVEL_SCREEN || metadata.level() <= LEVEL_PORTE9
    }

    fn log(&self, record: &Record) {
        let level = record.metadata().level();
        if level <= LEVEL_PORTE9 {
            e9_print!(
                "{:30} [{}] {:5} {}",
                record.target(),
                crate::smp::current_processor_id(),
                record.level(),
                record.args()
            );

            uart_print!(
                "{:30} [{}] {:5} {}",
                record.target(),
                crate::smp::current_processor_id(),
                record.level(),
                record.args()
            );
        }
        if level <= LEVEL_SCREEN {
            if crate::memory::can_allocate() {
                let message = format!(
                    "{:5} {} - {}\n",
                    record.level(),
                    record.target(),
                    record.args()
                );
                let mut wal = WRITE_AHEAD_LOG.lock();
                wal.extend(message.bytes());
            }

            if !DISABLE_DIRECT_VGA.load(Ordering::Acquire) {
                rprintln!(
                    "{:5} {} - {}",
                    record.level(),
                    record.target(),
                    record.args()
                );
            }
        }
    }

    fn flush(&self) {}
}

static LOGGER: SystemLogger = SystemLogger;

pub fn enable() {
    log::set_logger(&LOGGER).unwrap();
    log::set_max_level(log::LevelFilter::Trace);
}
<|endoftext|>