<commit_before>//! Implements a nullable integer. i.e. behaves similarly to
//! `Option<NonZero<T>>`
//! But freely serializes/deserializes/converts to T.
//!

use num::Zero;
use serde::{Serialize, Serializer, Deserialize, Deserializer};

use std::fmt::{Display, Formatter};
use std::fmt;

#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub struct NullableInt<T> {
    raw: T,
}

impl<T> NullableInt<T> {
    /// Relay NullableInt::new(x) to x.into() where
    /// x is convertible to NullableInt<T> (i.e. x = T or Option<T>)
    pub fn new<F>(raw: F) -> Self
        where F: Into<NullableInt<T>>
    {
        raw.into()
    }
}

impl<T: Copy + Zero> NullableInt<T> {
    /// Return None if self is null,
    /// else Some(value) where value != 0.
    pub fn get(&self) -> Option<T> {
        if self.raw.is_zero() {
            None
        } else {
            Some(self.raw)
        }
    }
    /// Cast self to T, where null is mapped to 0.
    pub fn get_raw(&self) -> T {
        self.raw
    }
}

/// T is directly convertable to `NullableInt<T>`
impl<T> From<T> for NullableInt<T> {
    fn from(raw: T) -> Self {
        Self{ raw }
    }
}
/// Option<T> is convertible to `NullableInt`:
/// None maps to null,
/// Some(0) maps to null
/// Some(x) maps to x
impl<T: Zero> From<Option<T>> for NullableInt<T> {
    fn from(maybe: Option<T>) -> Self {
        match maybe {
            None => Self{ raw: Zero::zero() },
            Some(raw) => Self{ raw }
        }
    }
}

impl<T: Zero + PartialEq + Copy> PartialEq<Option<T>> for NullableInt<T> {
    fn eq(&self, other: &Option<T>) -> bool {
        *self == Self::from(*other)
    }
}

impl<T: Display> Display for NullableInt<T> {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        self.raw.fmt(f)
    }
}

/// All `NullableInt`s Serialize as if they were normal ints.
impl<T: Serialize> Serialize for NullableInt<T> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer
    {
        self.raw.serialize(serializer)
    }
}

impl<'de, T: Deserialize<'de>> Deserialize<'de> for NullableInt<T> {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where D: Deserializer<'de>
    {
        let raw: T = Deserialize::deserialize(deserializer)?;
        Ok(Self{ raw })
    }
}
<commit_msg>Add 'is_null', 'is_nonnull' to NullableInt<commit_after>//! Implements a nullable integer. i.e. behaves similarly to
//! `Option<NonZero<T>>`
//! But freely serializes/deserializes/converts to T.
//!

use num::Zero;
use serde::{Serialize, Serializer, Deserialize, Deserializer};

use std::fmt::{Display, Formatter};
use std::fmt;

#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub struct NullableInt<T> {
    raw: T,
}

impl<T> NullableInt<T> {
    /// Relay NullableInt::new(x) to x.into() where
    /// x is convertible to NullableInt<T> (i.e. x = T or Option<T>)
    pub fn new<F>(raw: F) -> Self
        where F: Into<NullableInt<T>>
    {
        raw.into()
    }
}

impl<T: Zero> NullableInt<T> {
    /// Return true if the number has been nulled.
    pub fn is_null(&self) -> bool {
        self.raw.is_zero()
    }
    /// Return true is the number is not null.
    pub fn is_nonnull(&self) -> bool {
        !self.is_null()
    }
}

impl<T: Copy + Zero> NullableInt<T> {
    /// Return None if self is null,
    /// else Some(value) where value != 0.
    pub fn get(&self) -> Option<T> {
        if self.raw.is_zero() {
            None
        } else {
            Some(self.raw)
        }
    }
    /// Cast self to T, where null is mapped to 0.
    pub fn get_raw(&self) -> T {
        self.raw
    }
}

/// T is directly convertable to `NullableInt<T>`
impl<T> From<T> for NullableInt<T> {
    fn from(raw: T) -> Self {
        Self{ raw }
    }
}
/// Option<T> is convertible to `NullableInt`:
/// None maps to null,
/// Some(0) maps to null
/// Some(x) maps to x
impl<T: Zero> From<Option<T>> for NullableInt<T> {
    fn from(maybe: Option<T>) -> Self {
        match maybe {
            None => Self{ raw: Zero::zero() },
            Some(raw) => Self{ raw }
        }
    }
}

impl<T: Zero + PartialEq + Copy> PartialEq<Option<T>> for NullableInt<T> {
    fn eq(&self, other: &Option<T>) -> bool {
        *self == Self::from(*other)
    }
}

impl<T: Display> Display for NullableInt<T> {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        self.raw.fmt(f)
    }
}

/// All `NullableInt`s Serialize as if they were normal ints.
impl<T: Serialize> Serialize for NullableInt<T> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer
    {
        self.raw.serialize(serializer)
    }
}

impl<'de, T: Deserialize<'de>> Deserialize<'de> for NullableInt<T> {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where D: Deserializer<'de>
    {
        let raw: T = Deserialize::deserialize(deserializer)?;
        Ok(Self{ raw })
    }
}
<|endoftext|>


<commit_before>//! CPAL (Cross-Platform Audio Library) audio frontend

extern crate cpal;

use frontend_api::{FrontendResult, AudioSink};

use self::cpal::{get_default_endpoint, Voice, SampleFormat, SamplesRate, UnknownTypeBuffer};

pub struct CpalAudio {
    voice: Voice,
}

impl AudioSink for CpalAudio {
    fn create() -> FrontendResult<Self> {
        let endpoint = match get_default_endpoint() {
            Some(ep) => ep,
            None => return Err("Failed to get default endpoint".into()),
        };
        let mut formats = try!(endpoint.get_supported_formats_list());
        let format = match formats.find(|fmt| {
            fmt.data_type == SampleFormat::I16 && fmt.samples_rate == SamplesRate(32000) &&
            fmt.channels.len() == 2
        }) {
            Some(fmt) => fmt,
            None => return Err("no support for signed 16-bit data".into()),
        };

        info!("audio format: {:?}", format);

        let voice = try!(Voice::new(&endpoint, &format));

        Ok(CpalAudio {
            voice: voice,
        })
    }

    fn write(&mut self, mut data: &[(i16, i16)]) {
        while !data.is_empty() {
            match self.voice.append_data(data.len() * 2) {
                UnknownTypeBuffer::I16(mut buffer) => {
                    for out in buffer.chunks_mut(2) {
                        let (first, rest) = data.split_first().unwrap();
                        out[0] = first.0;
                        out[1] = first.1;
                        data = rest;
                    }
                },
                _ => unimplemented!(),
            }
        }
    }
}
<commit_msg>Add cpal debug output<commit_after>//! CPAL (Cross-Platform Audio Library) audio frontend

extern crate cpal;

use frontend_api::{FrontendResult, AudioSink};

use self::cpal::{get_default_endpoint, Voice, SampleFormat, SamplesRate, UnknownTypeBuffer};

pub struct CpalAudio {
    voice: Voice,
}

impl AudioSink for CpalAudio {
    fn create() -> FrontendResult<Self> {
        let endpoint = match get_default_endpoint() {
            Some(ep) => ep,
            None => return Err("Failed to get default endpoint".into()),
        };
        let mut formats = try!(endpoint.get_supported_formats_list());
        for fmt in &formats {
            debug!("supported format: {:?}", fmt);
        }

        let format = match formats.find(|fmt| {
            fmt.data_type == SampleFormat::I16 && fmt.samples_rate == SamplesRate(32000) &&
            fmt.channels.len() == 2
        }) {
            Some(fmt) => fmt,
            None => return Err("no support for signed 16-bit data".into()),
        };

        info!("audio format: {:?}", format);

        let voice = try!(Voice::new(&endpoint, &format));

        Ok(CpalAudio {
            voice: voice,
        })
    }

    fn write(&mut self, mut data: &[(i16, i16)]) {
        while !data.is_empty() {
            match self.voice.append_data(data.len() * 2) {
                UnknownTypeBuffer::I16(mut buffer) => {
                    for out in buffer.chunks_mut(2) {
                        let (first, rest) = data.split_first().unwrap();
                        out[0] = first.0;
                        out[1] = first.1;
                        data = rest;
                    }
                },
                _ => unimplemented!(),
            }
        }
    }
}
<|endoftext|>


<commit_before>//use core;

use cortex_m;
use stm32f0x2::{TIM7 as TIMER7, NVIC, RCC, GPIOC};
use stm32f0x2::interrupt::*;

pub fn setup(timeout: u16) {
    cortex_m::interrupt::free(|cs| {
        let gpio = GPIOC.borrow(cs);
        let rcc = RCC.borrow(cs);
        let timer = TIMER7.borrow(cs);
        let nvic = NVIC.borrow(cs);

        // LED Test
        rcc.ahbenr.modify(|_, w| w.iopcen().enabled());
        gpio.moder.modify(|_, w| w.moder7().output());

        //Enable TIM7 clock
        rcc.apb1enr.modify(|_, w| w.tim7en().enabled());

        // configure Time Out
        // Set Prescaler Register - 16 bits
        timer.psc.modify(|_, w| w.psc().bits(47));
        // Set Auto-Reload register - 32 bits
        timer.arr.modify(|_, w| w.arr().bits(timeout - 1));

        timer.cr1.modify(|_, w| w.opm().continuous());
        // Enable interrupt
        timer.dier.modify(|_, w| w.uie().enabled());
        // Interrupt activated
        nvic.enable(Interrupt::TIM7);
        nvic.clear_pending(Interrupt::TIM7);
    });
}

pub fn pause() {
    cortex_m::interrupt::free(|cs| {
        let timer = TIMER7.borrow(cs);
        // Disable counter
        timer.cr1.modify(|_, w| w.cen().disabled());
    });
}

pub fn restart() {
    cortex_m::interrupt::free(|cs| {
        let timer = TIMER7.borrow(cs);
        // Reset counter
        timer.cnt.write(|w| w.cnt().bits(0));
    });
}

pub fn resume() {
    cortex_m::interrupt::free(|cs| {
        let timer = TIMER7.borrow(cs);
        // Enable counter
        timer.cr1.modify(|_, w| w.cen().enabled());
    });
}

interrupt!(TIM7, led);

pub fn led() {
    cortex_m::interrupt::free(|cs| {
        let timer = TIMER7.borrow(cs);
        let gpio = GPIOC.borrow(cs);
        // Clear interrupt flag
        timer.sr.modify(|_, w| w.uif().clear_bit());
        if gpio.idr.read().idr7().bit_is_set() {
            gpio.bsrr.write(|w| w.br7().set_bit());
        } else {
            gpio.bsrr.write(|w| w.bs7().set_bit());
        }
    });
}
<commit_msg>Remove default timer interrupt.<commit_after>//use core;

use cortex_m;
use stm32f0x2::{TIM7 as TIMER7, NVIC, RCC, GPIOC};
use stm32f0x2::interrupt::*;

pub fn setup(timeout: u16) {
    cortex_m::interrupt::free(|cs| {
        let gpio = GPIOC.borrow(cs);
        let rcc = RCC.borrow(cs);
        let timer = TIMER7.borrow(cs);
        let nvic = NVIC.borrow(cs);

        // LED Test
        rcc.ahbenr.modify(|_, w| w.iopcen().enabled());
        gpio.moder.modify(|_, w| w.moder7().output());

        //Enable TIM7 clock
        rcc.apb1enr.modify(|_, w| w.tim7en().enabled());

        // configure Time Out
        // Set Prescaler Register - 16 bits
        timer.psc.modify(|_, w| w.psc().bits(47));
        // Set Auto-Reload register - 32 bits
        timer.arr.modify(|_, w| w.arr().bits(timeout - 1));

        timer.cr1.modify(|_, w| w.opm().continuous());
        // Enable interrupt
        timer.dier.modify(|_, w| w.uie().enabled());
        // Interrupt activated
        nvic.enable(Interrupt::TIM7);
        nvic.clear_pending(Interrupt::TIM7);
    });
}

pub fn pause() {
    cortex_m::interrupt::free(|cs| {
        let timer = TIMER7.borrow(cs);
        // Disable counter
        timer.cr1.modify(|_, w| w.cen().disabled());
    });
}

pub fn restart() {
    cortex_m::interrupt::free(|cs| {
        let timer = TIMER7.borrow(cs);
        // Reset counter
        timer.cnt.write(|w| w.cnt().bits(0));
    });
}

pub fn resume() {
    cortex_m::interrupt::free(|cs| {
        let timer = TIMER7.borrow(cs);
        // Enable counter
        timer.cr1.modify(|_, w| w.cen().enabled());
    });
}
<|endoftext|>


<commit_before>// Copyright 2014-2016 Johannes Köster, Martin Larralde.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

//! GC counter over an `IntoTextIterator` object.

//! Complexity: o(n)

use std::borrow::Borrow;

/// Base gc content counter
fn gcn_content<C: Borrow<u8>, T: IntoIterator<Item = C>>(sequence: T, step: usize) -> f32 {
    let mut l = 0f32;
    let mut count = 0.0;
    for (i, n) in sequence.into_iter().enumerate() {
        if i % step == 0 {
            count += match *n.borrow() {
                b'c' | b'g' | b'G' | b'C' => 1f32, // G or C
                _ => 0f32,
            };
        }
        l = i as f32;
    }
    count / (l + 1f32)
}

/// gc content counter for every nucleotide
pub fn gc_content<C: Borrow<u8>, T: IntoIterator<Item = C>>(sequence: T) -> f32 {
    gcn_content(sequence, 1usize)
}

/// gc content counter for the nucleotide in 3rd position
pub fn gc3_content<C: Borrow<u8>, T: IntoIterator<Item = C>>(sequence: T) -> f32 {
    gcn_content(sequence, 3usize)
}
<commit_msg>Add test for calculating GC content (#205)<commit_after>// Copyright 2014-2016 Johannes Köster, Martin Larralde.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

//! GC counter over an `IntoTextIterator` object.

//! Complexity: o(n)

use std::borrow::Borrow;

/// Base gc content counter
fn gcn_content<C: Borrow<u8>, T: IntoIterator<Item = C>>(sequence: T, step: usize) -> f32 {
    let mut l = 0f32;
    let mut count = 0.0;
    for (i, n) in sequence.into_iter().enumerate() {
        if i % step == 0 {
            count += match *n.borrow() {
                b'c' | b'g' | b'G' | b'C' => 1f32, // G or C
                _ => 0f32,
            };
        }
        l = i as f32;
    }
    count / (l + 1f32)
}

/// gc content counter for every nucleotide
pub fn gc_content<C: Borrow<u8>, T: IntoIterator<Item = C>>(sequence: T) -> f32 {
    gcn_content(sequence, 1usize)
}

/// gc content counter for the nucleotide in 3rd position
pub fn gc3_content<C: Borrow<u8>, T: IntoIterator<Item = C>>(sequence: T) -> f32 {
    gcn_content(sequence, 3usize)
}

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

    #[test]
    fn test_gc_content() {
        let gc0 = b"ATAT";
        assert_eq!(gc_content(gc0), 0.0);
        let gc50 = b"ATGC";
        assert_eq!(gc_content(gc50), 0.5);
        let gc100 = b"GCGC";
        assert_eq!(gc_content(gc100), 1.0);
    }
}
<|endoftext|>


<commit_before>#![cfg_attr(feature = "cargo-clippy", allow(redundant_field_names))]

use bytes::{BufMut, BytesMut};
use futures::{Async, Poll};
use std::io;
use std::rc::Rc;
use tokio_io::AsyncWrite;

use super::helpers;
use super::output::{Output, ResponseInfo, ResponseLength};
use super::settings::WorkerSettings;
use super::Request;
use super::{Writer, WriterState, MAX_WRITE_BUFFER_SIZE};
use body::{Binary, Body};
use header::ContentEncoding;
use http::header::{
    HeaderValue, CONNECTION, CONTENT_ENCODING, CONTENT_LENGTH, DATE, TRANSFER_ENCODING,
};
use http::{Method, Version};
use httpresponse::HttpResponse;

const AVERAGE_HEADER_SIZE: usize = 30; // totally scientific

bitflags! {
    struct Flags: u8 {
        const STARTED = 0b0000_0001;
        const UPGRADE = 0b0000_0010;
        const KEEPALIVE = 0b0000_0100;
        const DISCONNECTED = 0b0000_1000;
    }
}

pub(crate) struct H1Writer<T: AsyncWrite, H: 'static> {
    flags: Flags,
    stream: T,
    written: u64,
    headers_size: u32,
    buffer: Output,
    buffer_capacity: usize,
    settings: Rc<WorkerSettings<H>>,
}

impl<T: AsyncWrite, H: 'static> H1Writer<T, H> {
    pub fn new(stream: T, settings: Rc<WorkerSettings<H>>) -> H1Writer<T, H> {
        H1Writer {
            flags: Flags::KEEPALIVE,
            written: 0,
            headers_size: 0,
            buffer: Output::Buffer(settings.get_bytes()),
            buffer_capacity: 0,
            stream,
            settings,
        }
    }

    pub fn get_mut(&mut self) -> &mut T {
        &mut self.stream
    }

    pub fn reset(&mut self) {
        self.written = 0;
        self.flags = Flags::KEEPALIVE;
    }

    pub fn disconnected(&mut self) {}

    pub fn keepalive(&self) -> bool {
        self.flags.contains(Flags::KEEPALIVE) && !self.flags.contains(Flags::UPGRADE)
    }

    fn write_data(stream: &mut T, data: &[u8]) -> io::Result<usize> {
        let mut written = 0;
        while written < data.len() {
            match stream.write(&data[written..]) {
                Ok(0) => {
                    return Err(io::Error::new(io::ErrorKind::WriteZero, ""));
                }
                Ok(n) => {
                    written += n;
                }
                Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
                    return Ok(written)
                }
                Err(err) => return Err(err),
            }
        }
        Ok(written)
    }
}

impl<T: AsyncWrite, H: 'static> Drop for H1Writer<T, H> {
    fn drop(&mut self) {
        if let Some(bytes) = self.buffer.take_option() {
            self.settings.release_bytes(bytes);
        }
    }
}

impl<T: AsyncWrite, H: 'static> Writer for H1Writer<T, H> {
    #[inline]
    fn written(&self) -> u64 {
        self.written
    }

    #[inline]
    fn set_date(&mut self) {
        self.settings.set_date(self.buffer.as_mut(), true)
    }

    #[inline]
    fn buffer(&mut self) -> &mut BytesMut {
        self.buffer.as_mut()
    }

    fn start(
        &mut self, req: &Request, msg: &mut HttpResponse, encoding: ContentEncoding,
    ) -> io::Result<WriterState> {
        // prepare task
        let mut info = ResponseInfo::new(req.inner.method == Method::HEAD);
        self.buffer.for_server(&mut info, &req.inner, msg, encoding);
        if msg.keep_alive().unwrap_or_else(|| req.keep_alive()) {
            self.flags = Flags::STARTED | Flags::KEEPALIVE;
        } else {
            self.flags = Flags::STARTED;
        }

        // Connection upgrade
        let version = msg.version().unwrap_or_else(|| req.inner.version);
        if msg.upgrade() {
            self.flags.insert(Flags::UPGRADE);
            msg.headers_mut()
                .insert(CONNECTION, HeaderValue::from_static("upgrade"));
        }
        // keep-alive
        else if self.flags.contains(Flags::KEEPALIVE) {
            if version < Version::HTTP_11 {
                msg.headers_mut()
                    .insert(CONNECTION, HeaderValue::from_static("keep-alive"));
            }
        } else if version >= Version::HTTP_11 {
            msg.headers_mut()
                .insert(CONNECTION, HeaderValue::from_static("close"));
        }
        let body = msg.replace_body(Body::Empty);

        // render message
        {
            // output buffer
            let mut buffer = self.buffer.as_mut();

            let reason = msg.reason().as_bytes();
            if let Body::Binary(ref bytes) = body {
                buffer.reserve(
                    256
                        + msg.headers().len() * AVERAGE_HEADER_SIZE
                        + bytes.len()
                        + reason.len(),
                );
            } else {
                buffer.reserve(
                    256 + msg.headers().len() * AVERAGE_HEADER_SIZE + reason.len(),
                );
            }

            // status line
            helpers::write_status_line(version, msg.status().as_u16(), &mut buffer);
            buffer.extend_from_slice(reason);

            // content length
            match info.length {
                ResponseLength::Chunked => {
                    buffer.extend_from_slice(b"\r\ntransfer-encoding: chunked\r\n")
                }
                ResponseLength::Zero => {
                    buffer.extend_from_slice(b"\r\ncontent-length: 0\r\n")
                }
                ResponseLength::Length(len) => {
                    helpers::write_content_length(len, &mut buffer)
                }
                ResponseLength::Length64(len) => {
                    let s = format!("{}", len);
                    buffer.extend_from_slice(b"\r\ncontent-length: ");
                    buffer.extend_from_slice(s.as_ref());
                    buffer.extend_from_slice(b"\r\n");
                }
                ResponseLength::None => buffer.extend_from_slice(b"\r\n"),
            }
            if let Some(ce) = info.content_encoding {
                buffer.extend_from_slice(b"content-encoding: ");
                buffer.extend_from_slice(ce.as_ref());
                buffer.extend_from_slice(b"\r\n");
            }

            // write headers
            let mut pos = 0;
            let mut has_date = false;
            let mut remaining = buffer.remaining_mut();
            unsafe {
                let mut buf = &mut *(buffer.bytes_mut() as *mut [u8]);
                for (key, value) in msg.headers() {
                    match *key {
                        TRANSFER_ENCODING => continue,
                        CONTENT_ENCODING => if encoding != ContentEncoding::Identity {
                            continue;
                        },
                        CONTENT_LENGTH => match info.length {
                            ResponseLength::None => (),
                            _ => continue,
                        },
                        DATE => {
                            has_date = true;
                        }
                        _ => (),
                    }

                    let v = value.as_ref();
                    let k = key.as_str().as_bytes();
                    let len = k.len() + v.len() + 4;
                    if len > remaining {
                        buffer.advance_mut(pos);
                        pos = 0;
                        buffer.reserve(len);
                        remaining = buffer.remaining_mut();
                        buf = &mut *(buffer.bytes_mut() as *mut _);
                    }

                    buf[pos..pos + k.len()].copy_from_slice(k);
                    pos += k.len();
                    buf[pos..pos + 2].copy_from_slice(b": ");
                    pos += 2;
                    buf[pos..pos + v.len()].copy_from_slice(v);
                    pos += v.len();
                    buf[pos..pos + 2].copy_from_slice(b"\r\n");
                    pos += 2;
                    remaining -= len;
                }
                buffer.advance_mut(pos);
            }

            // optimized date header, set_date writes \r\n
            if !has_date {
                self.settings.set_date(&mut buffer, true);
            } else {
                // msg eof
                buffer.extend_from_slice(b"\r\n");
            }
            self.headers_size = buffer.len() as u32;
        }

        if let Body::Binary(bytes) = body {
            self.written = bytes.len() as u64;
            self.buffer.write(bytes.as_ref())?;
        } else {
            // capacity, makes sense only for streaming or actor
            self.buffer_capacity = msg.write_buffer_capacity();

            msg.replace_body(body);
        }
        Ok(WriterState::Done)
    }

    fn write(&mut self, payload: &Binary) -> io::Result<WriterState> {
        self.written += payload.len() as u64;
        if !self.flags.contains(Flags::DISCONNECTED) {
            if self.flags.contains(Flags::STARTED) {
                // shortcut for upgraded connection
                if self.flags.contains(Flags::UPGRADE) {
                    if self.buffer.is_empty() {
                        let pl: &[u8] = payload.as_ref();
                        let n = match Self::write_data(&mut self.stream, pl) {
                            Err(err) => {
                                if err.kind() == io::ErrorKind::WriteZero {
                                    self.disconnected();
                                }

                                return Err(err);
                            }
                            Ok(val) => val,
                        };
                        if n < pl.len() {
                            self.buffer.write(&pl[n..])?;
                            return Ok(WriterState::Done);
                        }
                    } else {
                        self.buffer.write(payload.as_ref())?;
                    }
                } else {
                    // TODO: add warning, write after EOF
                    self.buffer.write(payload.as_ref())?;
                }
            } else {
                // could be response to EXCEPT header
                self.buffer.write(payload.as_ref())?;
            }
        }

        if self.buffer.len() > self.buffer_capacity {
            Ok(WriterState::Pause)
        } else {
            Ok(WriterState::Done)
        }
    }

    fn write_eof(&mut self) -> io::Result<WriterState> {
        if !self.buffer.write_eof()? {
            Err(io::Error::new(
                io::ErrorKind::Other,
                "Last payload item, but eof is not reached",
            ))
        } else if self.buffer.len() > MAX_WRITE_BUFFER_SIZE {
            Ok(WriterState::Pause)
        } else {
            Ok(WriterState::Done)
        }
    }

    #[inline]
    fn poll_completed(&mut self, shutdown: bool) -> Poll<(), io::Error> {
        if !self.buffer.is_empty() {
            let written = {
                match Self::write_data(&mut self.stream, self.buffer.as_ref().as_ref()) {
                    Err(err) => {
                        if err.kind() == io::ErrorKind::WriteZero {
                            self.disconnected();
                        }

                        return Err(err);
                    }
                    Ok(val) => val,
                }
            };
            let _ = self.buffer.split_to(written);
            if shutdown && !self.buffer.is_empty()
                || (self.buffer.len() > self.buffer_capacity)
            {
                return Ok(Async::NotReady);
            }
        }
        if shutdown {
            self.stream.shutdown()
        } else {
            Ok(Async::Ready(()))
        }
    }
}
<commit_msg>use write instead format<commit_after>// #![cfg_attr(feature = "cargo-clippy", allow(redundant_field_names))]

use std::io::{self, Write};
use std::rc::Rc;

use bytes::{BufMut, BytesMut};
use futures::{Async, Poll};
use tokio_io::AsyncWrite;

use super::helpers;
use super::output::{Output, ResponseInfo, ResponseLength};
use super::settings::WorkerSettings;
use super::Request;
use super::{Writer, WriterState, MAX_WRITE_BUFFER_SIZE};
use body::{Binary, Body};
use header::ContentEncoding;
use http::header::{
    HeaderValue, CONNECTION, CONTENT_ENCODING, CONTENT_LENGTH, DATE, TRANSFER_ENCODING,
};
use http::{Method, Version};
use httpresponse::HttpResponse;

const AVERAGE_HEADER_SIZE: usize = 30; // totally scientific

bitflags! {
    struct Flags: u8 {
        const STARTED = 0b0000_0001;
        const UPGRADE = 0b0000_0010;
        const KEEPALIVE = 0b0000_0100;
        const DISCONNECTED = 0b0000_1000;
    }
}

pub(crate) struct H1Writer<T: AsyncWrite, H: 'static> {
    flags: Flags,
    stream: T,
    written: u64,
    headers_size: u32,
    buffer: Output,
    buffer_capacity: usize,
    settings: Rc<WorkerSettings<H>>,
}

impl<T: AsyncWrite, H: 'static> H1Writer<T, H> {
    pub fn new(stream: T, settings: Rc<WorkerSettings<H>>) -> H1Writer<T, H> {
        H1Writer {
            flags: Flags::KEEPALIVE,
            written: 0,
            headers_size: 0,
            buffer: Output::Buffer(settings.get_bytes()),
            buffer_capacity: 0,
            stream,
            settings,
        }
    }

    pub fn get_mut(&mut self) -> &mut T {
        &mut self.stream
    }

    pub fn reset(&mut self) {
        self.written = 0;
        self.flags = Flags::KEEPALIVE;
    }

    pub fn disconnected(&mut self) {}

    pub fn keepalive(&self) -> bool {
        self.flags.contains(Flags::KEEPALIVE) && !self.flags.contains(Flags::UPGRADE)
    }

    fn write_data(stream: &mut T, data: &[u8]) -> io::Result<usize> {
        let mut written = 0;
        while written < data.len() {
            match stream.write(&data[written..]) {
                Ok(0) => {
                    return Err(io::Error::new(io::ErrorKind::WriteZero, ""));
                }
                Ok(n) => {
                    written += n;
                }
                Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
                    return Ok(written)
                }
                Err(err) => return Err(err),
            }
        }
        Ok(written)
    }
}

impl<T: AsyncWrite, H: 'static> Drop for H1Writer<T, H> {
    fn drop(&mut self) {
        if let Some(bytes) = self.buffer.take_option() {
            self.settings.release_bytes(bytes);
        }
    }
}

impl<T: AsyncWrite, H: 'static> Writer for H1Writer<T, H> {
    #[inline]
    fn written(&self) -> u64 {
        self.written
    }

    #[inline]
    fn set_date(&mut self) {
        self.settings.set_date(self.buffer.as_mut(), true)
    }

    #[inline]
    fn buffer(&mut self) -> &mut BytesMut {
        self.buffer.as_mut()
    }

    fn start(
        &mut self, req: &Request, msg: &mut HttpResponse, encoding: ContentEncoding,
    ) -> io::Result<WriterState> {
        // prepare task
        let mut info = ResponseInfo::new(req.inner.method == Method::HEAD);
        self.buffer.for_server(&mut info, &req.inner, msg, encoding);
        if msg.keep_alive().unwrap_or_else(|| req.keep_alive()) {
            self.flags = Flags::STARTED | Flags::KEEPALIVE;
        } else {
            self.flags = Flags::STARTED;
        }

        // Connection upgrade
        let version = msg.version().unwrap_or_else(|| req.inner.version);
        if msg.upgrade() {
            self.flags.insert(Flags::UPGRADE);
            msg.headers_mut()
                .insert(CONNECTION, HeaderValue::from_static("upgrade"));
        }
        // keep-alive
        else if self.flags.contains(Flags::KEEPALIVE) {
            if version < Version::HTTP_11 {
                msg.headers_mut()
                    .insert(CONNECTION, HeaderValue::from_static("keep-alive"));
            }
        } else if version >= Version::HTTP_11 {
            msg.headers_mut()
                .insert(CONNECTION, HeaderValue::from_static("close"));
        }
        let body = msg.replace_body(Body::Empty);

        // render message
        {
            // output buffer
            let mut buffer = self.buffer.as_mut();

            let reason = msg.reason().as_bytes();
            if let Body::Binary(ref bytes) = body {
                buffer.reserve(
                    256
                        + msg.headers().len() * AVERAGE_HEADER_SIZE
                        + bytes.len()
                        + reason.len(),
                );
            } else {
                buffer.reserve(
                    256 + msg.headers().len() * AVERAGE_HEADER_SIZE + reason.len(),
                );
            }

            // status line
            helpers::write_status_line(version, msg.status().as_u16(), &mut buffer);
            buffer.extend_from_slice(reason);

            // content length
            match info.length {
                ResponseLength::Chunked => {
                    buffer.extend_from_slice(b"\r\ntransfer-encoding: chunked\r\n")
                }
                ResponseLength::Zero => {
                    buffer.extend_from_slice(b"\r\ncontent-length: 0\r\n")
                }
                ResponseLength::Length(len) => {
                    helpers::write_content_length(len, &mut buffer)
                }
                ResponseLength::Length64(len) => {
                    buffer.extend_from_slice(b"\r\ncontent-length: ");
                    write!(buffer.writer(), "{}", len)?;
                    buffer.extend_from_slice(b"\r\n");
                }
                ResponseLength::None => buffer.extend_from_slice(b"\r\n"),
            }
            if let Some(ce) = info.content_encoding {
                buffer.extend_from_slice(b"content-encoding: ");
                buffer.extend_from_slice(ce.as_ref());
                buffer.extend_from_slice(b"\r\n");
            }

            // write headers
            let mut pos = 0;
            let mut has_date = false;
            let mut remaining = buffer.remaining_mut();
            unsafe {
                let mut buf = &mut *(buffer.bytes_mut() as *mut [u8]);
                for (key, value) in msg.headers() {
                    match *key {
                        TRANSFER_ENCODING => continue,
                        CONTENT_ENCODING => if encoding != ContentEncoding::Identity {
                            continue;
                        },
                        CONTENT_LENGTH => match info.length {
                            ResponseLength::None => (),
                            _ => continue,
                        },
                        DATE => {
                            has_date = true;
                        }
                        _ => (),
                    }

                    let v = value.as_ref();
                    let k = key.as_str().as_bytes();
                    let len = k.len() + v.len() + 4;
                    if len > remaining {
                        buffer.advance_mut(pos);
                        pos = 0;
                        buffer.reserve(len);
                        remaining = buffer.remaining_mut();
                        buf = &mut *(buffer.bytes_mut() as *mut _);
                    }

                    buf[pos..pos + k.len()].copy_from_slice(k);
                    pos += k.len();
                    buf[pos..pos + 2].copy_from_slice(b": ");
                    pos += 2;
                    buf[pos..pos + v.len()].copy_from_slice(v);
                    pos += v.len();
                    buf[pos..pos + 2].copy_from_slice(b"\r\n");
                    pos += 2;
                    remaining -= len;
                }
                buffer.advance_mut(pos);
            }

            // optimized date header, set_date writes \r\n
            if !has_date {
                self.settings.set_date(&mut buffer, true);
            } else {
                // msg eof
                buffer.extend_from_slice(b"\r\n");
            }
            self.headers_size = buffer.len() as u32;
        }

        if let Body::Binary(bytes) = body {
            self.written = bytes.len() as u64;
            self.buffer.write(bytes.as_ref())?;
        } else {
            // capacity, makes sense only for streaming or actor
            self.buffer_capacity = msg.write_buffer_capacity();

            msg.replace_body(body);
        }
        Ok(WriterState::Done)
    }

    fn write(&mut self, payload: &Binary) -> io::Result<WriterState> {
        self.written += payload.len() as u64;
        if !self.flags.contains(Flags::DISCONNECTED) {
            if self.flags.contains(Flags::STARTED) {
                // shortcut for upgraded connection
                if self.flags.contains(Flags::UPGRADE) {
                    if self.buffer.is_empty() {
                        let pl: &[u8] = payload.as_ref();
                        let n = match Self::write_data(&mut self.stream, pl) {
                            Err(err) => {
                                if err.kind() == io::ErrorKind::WriteZero {
                                    self.disconnected();
                                }

                                return Err(err);
                            }
                            Ok(val) => val,
                        };
                        if n < pl.len() {
                            self.buffer.write(&pl[n..])?;
                            return Ok(WriterState::Done);
                        }
                    } else {
                        self.buffer.write(payload.as_ref())?;
                    }
                } else {
                    // TODO: add warning, write after EOF
                    self.buffer.write(payload.as_ref())?;
                }
            } else {
                // could be response to EXCEPT header
                self.buffer.write(payload.as_ref())?;
            }
        }

        if self.buffer.len() > self.buffer_capacity {
            Ok(WriterState::Pause)
        } else {
            Ok(WriterState::Done)
        }
    }

    fn write_eof(&mut self) -> io::Result<WriterState> {
        if !self.buffer.write_eof()? {
            Err(io::Error::new(
                io::ErrorKind::Other,
                "Last payload item, but eof is not reached",
            ))
        } else if self.buffer.len() > MAX_WRITE_BUFFER_SIZE {
            Ok(WriterState::Pause)
        } else {
            Ok(WriterState::Done)
        }
    }

    #[inline]
    fn poll_completed(&mut self, shutdown: bool) -> Poll<(), io::Error> {
        if !self.buffer.is_empty() {
            let written = {
                match Self::write_data(&mut self.stream, self.buffer.as_ref().as_ref()) {
                    Err(err) => {
                        if err.kind() == io::ErrorKind::WriteZero {
                            self.disconnected();
                        }

                        return Err(err);
                    }
                    Ok(val) => val,
                }
            };
            let _ = self.buffer.split_to(written);
            if shutdown && !self.buffer.is_empty()
                || (self.buffer.len() > self.buffer_capacity)
            {
                return Ok(Async::NotReady);
            }
        }
        if shutdown {
            self.stream.shutdown()
        } else {
            Ok(Async::Ready(()))
        }
    }
}
<|endoftext|>


<commit_before>//! Handlers for the server.

use iron::modifiers::Header;
use iron::prelude::*;
use iron::{headers, middleware, status};
use log::{debug, error, info, warn};
use router::Router;
use serde::ser::{Serialize, SerializeMap, Serializer};

use crate::api;
use crate::modifiers;
use crate::sensors;
use crate::types::RedisPool;

#[derive(Debug)]
struct ErrorResponse {
    reason: String,
}

impl Serialize for ErrorResponse {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let mut map = serializer.serialize_map(Some(2))?;
        map.serialize_entry("status", "error")?;
        map.serialize_entry("reason", &self.reason)?;
        map.end()
    }
}

pub(crate) struct ReadHandler {
    status: api::Status,
    redis_pool: RedisPool,
    sensor_specs: sensors::SafeSensorSpecs,
    status_modifiers: Vec<Box<dyn modifiers::StatusModifier>>,
}

impl ReadHandler {
    pub(crate) fn new(
        status: api::Status,
        redis_pool: RedisPool,
        sensor_specs: sensors::SafeSensorSpecs,
        status_modifiers: Vec<Box<dyn modifiers::StatusModifier>>,
    ) -> ReadHandler {
        ReadHandler {
            status,
            redis_pool,
            sensor_specs,
            status_modifiers,
        }
    }

    fn build_response_json(&self) -> String {
        // Create a mutable copy of the status struct
        let mut status_copy = self.status.clone();

        // Process registered sensors
        for sensor_spec in self.sensor_specs.iter() {
            match sensor_spec.get_sensor_value(&self.redis_pool) {
                // Value could be read successfullly
                Ok(value) => {
                    if status_copy.sensors.is_none() {
                        status_copy.sensors = Some(api::Sensors {
                            people_now_present: vec![],
                            temperature: vec![],
                        });
                    }
                    sensor_spec
                        .template
                        .to_sensor(&value, &mut status_copy.sensors.as_mut().unwrap());
                }

                // Value could not be read, do error logging
                Err(err) => {
                    warn!(
                        "Could not retrieve key '{}' from Redis, omiting the sensor",
                        &sensor_spec.data_key
                    );
                    match err {
                        sensors::SensorError::Redis(e) => debug!("Error: {:?}", e),
                        sensors::SensorError::R2d2(e) => debug!("Error: {:?}", e),
                        sensors::SensorError::UnknownSensor(e) => warn!("Error: {:?}", e),
                    }
                }
            }
        }

        for status_modifier in &self.status_modifiers {
            status_modifier.modify(&mut status_copy);
        }

        // Serialize to JSON
        serde_json::to_string(&status_copy).expect(
            "Status object could not be serialized to JSON. \
             Please open an issue at https://github.com/spaceapi-community/spaceapi-server-rs/issues",
        )
    }
}

impl middleware::Handler for ReadHandler {
    /// Return the current status JSON.
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        info!("{} /{} from {}", req.method, req.url.path()[0], req.remote_addr);

        // Get response body
        let body = self.build_response_json();

        // Create response
        let response = Response::with((status::Ok, body))
            // Set headers
            .set(Header(headers::ContentType(
                "application/json; charset=utf-8".parse().unwrap(),
            )))
            .set(Header(headers::CacheControl(vec![
                headers::CacheDirective::NoCache,
            ])))
            .set(Header(headers::AccessControlAllowOrigin::Any));

        Ok(response)
    }
}

pub(crate) struct UpdateHandler {
    redis_pool: RedisPool,
    sensor_specs: sensors::SafeSensorSpecs,
}

impl UpdateHandler {
    pub(crate) fn new(redis_pool: RedisPool, sensor_specs: sensors::SafeSensorSpecs) -> UpdateHandler {
        UpdateHandler {
            redis_pool,
            sensor_specs,
        }
    }

    /// Update sensor value in Redis
    fn update_sensor(&self, sensor: &str, value: &str) -> Result<(), sensors::SensorError> {
        // Validate sensor
        let sensor_spec = self
            .sensor_specs
            .iter()
            .find(|&spec| spec.data_key == sensor)
            .ok_or_else(|| sensors::SensorError::UnknownSensor(sensor.into()))?;

        // Store data
        sensor_spec.set_sensor_value(&self.redis_pool, value)
    }

    /// Build an OK response with the `HTTP 204 No Content` status code.
    fn ok_response(&self) -> Response {
        Response::with(status::NoContent)
            // Set headers
            .set(Header(headers::ContentType(
                "application/json; charset=utf-8".parse().unwrap(),
            )))
            .set(Header(headers::CacheControl(vec![
                headers::CacheDirective::NoCache,
            ])))
            .set(Header(headers::AccessControlAllowOrigin::Any))
    }

    /// Build an error response with the specified `error_code` and the specified `reason` text.
    fn err_response(&self, error_code: status::Status, reason: &str) -> Response {
        let error = ErrorResponse {
            reason: reason.into(),
        };
        let error_string = serde_json::to_string(&error).expect("Could not serialize error");
        Response::with((error_code, error_string))
            // Set headers
            .set(Header(headers::ContentType(
                "application/json; charset=utf-8".parse().unwrap(),
            )))
            .set(Header(headers::CacheControl(vec![
                headers::CacheDirective::NoCache,
            ])))
            .set(Header(headers::AccessControlAllowOrigin::Any))
    }
}

impl middleware::Handler for UpdateHandler {
    /// Update the sensor, return correct status code.
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        // TODO: create macro for these info! invocations.
        info!("{} /{} from {}", req.method, req.url.path()[0], req.remote_addr);

        // Get sensor name
        let sensor_name;
        {
            // TODO: Properly propagate errors
            let params = req.extensions.get::<Router>().unwrap();
            sensor_name = params.find("sensor").unwrap().to_string();
        }

        // Get sensor value
        let sensor_value;
        {
            let params = req.get_ref::<urlencoded::UrlEncodedBody>().unwrap();
            sensor_value = match params.get("value") {
                Some(ref values) => match values.len() {
                    1 => values[0].to_string(),
                    _ => return Ok(self.err_response(status::BadRequest, "Too many values specified")),
                },
                None => return Ok(self.err_response(status::BadRequest, "\"value\" parameter not specified")),
            }
        }

        // Update values in Redis
        if let Err(e) = self.update_sensor(&sensor_name, &sensor_value) {
            error!(
                "Updating sensor value for sensor \"{}\" failed: {:?}",
                &sensor_name, e
            );
            let response = match e {
                sensors::SensorError::UnknownSensor(sensor) => {
                    self.err_response(status::BadRequest, &format!("Unknown sensor: {}", sensor))
                }
                sensors::SensorError::Redis(_) | sensors::SensorError::R2d2(_) => {
                    self.err_response(status::InternalServerError, "Updating values in datastore failed")
                }
            };
            return Ok(response);
        };

        // Create response
        Ok(self.ok_response())
    }
}

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

    #[test]
    fn test_serialize_error_response() {
        let error = ErrorResponse {
            reason: "foobared".into(),
        };
        let json = serde_json::to_string(&error).unwrap();
        assert_eq!(json, r#"{"status":"error","reason":"foobared"}"#);
    }
}
<commit_msg>Fix newer clippy warning<commit_after>//! Handlers for the server.

use iron::modifiers::Header;
use iron::prelude::*;
use iron::{headers, middleware, status};
use log::{debug, error, info, warn};
use router::Router;
use serde::ser::{Serialize, SerializeMap, Serializer};

use crate::api;
use crate::modifiers;
use crate::sensors;
use crate::types::RedisPool;

#[derive(Debug)]
struct ErrorResponse {
    reason: String,
}

impl Serialize for ErrorResponse {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let mut map = serializer.serialize_map(Some(2))?;
        map.serialize_entry("status", "error")?;
        map.serialize_entry("reason", &self.reason)?;
        map.end()
    }
}

pub(crate) struct ReadHandler {
    status: api::Status,
    redis_pool: RedisPool,
    sensor_specs: sensors::SafeSensorSpecs,
    status_modifiers: Vec<Box<dyn modifiers::StatusModifier>>,
}

impl ReadHandler {
    pub(crate) fn new(
        status: api::Status,
        redis_pool: RedisPool,
        sensor_specs: sensors::SafeSensorSpecs,
        status_modifiers: Vec<Box<dyn modifiers::StatusModifier>>,
    ) -> ReadHandler {
        ReadHandler {
            status,
            redis_pool,
            sensor_specs,
            status_modifiers,
        }
    }

    fn build_response_json(&self) -> String {
        // Create a mutable copy of the status struct
        let mut status_copy = self.status.clone();

        // Process registered sensors
        for sensor_spec in self.sensor_specs.iter() {
            match sensor_spec.get_sensor_value(&self.redis_pool) {
                // Value could be read successfullly
                Ok(value) => {
                    if status_copy.sensors.is_none() {
                        status_copy.sensors = Some(api::Sensors {
                            people_now_present: vec![],
                            temperature: vec![],
                        });
                    }
                    sensor_spec
                        .template
                        .to_sensor(&value, &mut status_copy.sensors.as_mut().unwrap());
                }

                // Value could not be read, do error logging
                Err(err) => {
                    warn!(
                        "Could not retrieve key '{}' from Redis, omiting the sensor",
                        &sensor_spec.data_key
                    );
                    match err {
                        sensors::SensorError::Redis(e) => debug!("Error: {:?}", e),
                        sensors::SensorError::R2d2(e) => debug!("Error: {:?}", e),
                        sensors::SensorError::UnknownSensor(e) => warn!("Error: {:?}", e),
                    }
                }
            }
        }

        for status_modifier in &self.status_modifiers {
            status_modifier.modify(&mut status_copy);
        }

        // Serialize to JSON
        serde_json::to_string(&status_copy).expect(
            "Status object could not be serialized to JSON. \
             Please open an issue at https://github.com/spaceapi-community/spaceapi-server-rs/issues",
        )
    }
}

impl middleware::Handler for ReadHandler {
    /// Return the current status JSON.
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        info!("{} /{} from {}", req.method, req.url.path()[0], req.remote_addr);

        // Get response body
        let body = self.build_response_json();

        // Create response
        let response = Response::with((status::Ok, body))
            // Set headers
            .set(Header(headers::ContentType(
                "application/json; charset=utf-8".parse().unwrap(),
            )))
            .set(Header(headers::CacheControl(vec![
                headers::CacheDirective::NoCache,
            ])))
            .set(Header(headers::AccessControlAllowOrigin::Any));

        Ok(response)
    }
}

pub(crate) struct UpdateHandler {
    redis_pool: RedisPool,
    sensor_specs: sensors::SafeSensorSpecs,
}

impl UpdateHandler {
    pub(crate) fn new(redis_pool: RedisPool, sensor_specs: sensors::SafeSensorSpecs) -> UpdateHandler {
        UpdateHandler {
            redis_pool,
            sensor_specs,
        }
    }

    /// Update sensor value in Redis
    fn update_sensor(&self, sensor: &str, value: &str) -> Result<(), sensors::SensorError> {
        // Validate sensor
        let sensor_spec = self
            .sensor_specs
            .iter()
            .find(|&spec| spec.data_key == sensor)
            .ok_or_else(|| sensors::SensorError::UnknownSensor(sensor.into()))?;

        // Store data
        sensor_spec.set_sensor_value(&self.redis_pool, value)
    }

    /// Build an OK response with the `HTTP 204 No Content` status code.
    fn ok_response(&self) -> Response {
        Response::with(status::NoContent)
            // Set headers
            .set(Header(headers::ContentType(
                "application/json; charset=utf-8".parse().unwrap(),
            )))
            .set(Header(headers::CacheControl(vec![
                headers::CacheDirective::NoCache,
            ])))
            .set(Header(headers::AccessControlAllowOrigin::Any))
    }

    /// Build an error response with the specified `error_code` and the specified `reason` text.
    fn err_response(&self, error_code: status::Status, reason: &str) -> Response {
        let error = ErrorResponse {
            reason: reason.into(),
        };
        let error_string = serde_json::to_string(&error).expect("Could not serialize error");
        Response::with((error_code, error_string))
            // Set headers
            .set(Header(headers::ContentType(
                "application/json; charset=utf-8".parse().unwrap(),
            )))
            .set(Header(headers::CacheControl(vec![
                headers::CacheDirective::NoCache,
            ])))
            .set(Header(headers::AccessControlAllowOrigin::Any))
    }
}

impl middleware::Handler for UpdateHandler {
    /// Update the sensor, return correct status code.
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        // TODO: create macro for these info! invocations.
        info!("{} /{} from {}", req.method, req.url.path()[0], req.remote_addr);

        // Get sensor name
        let sensor_name;
        {
            // TODO: Properly propagate errors
            let params = req.extensions.get::<Router>().unwrap();
            sensor_name = params.find("sensor").unwrap().to_string();
        }

        // Get sensor value
        let sensor_value;
        {
            let params = req.get_ref::<urlencoded::UrlEncodedBody>().unwrap();
            sensor_value = match params.get("value") {
                Some(values) => match values.len() {
                    1 => values[0].to_string(),
                    _ => return Ok(self.err_response(status::BadRequest, "Too many values specified")),
                },
                None => return Ok(self.err_response(status::BadRequest, "\"value\" parameter not specified")),
            }
        }

        // Update values in Redis
        if let Err(e) = self.update_sensor(&sensor_name, &sensor_value) {
            error!(
                "Updating sensor value for sensor \"{}\" failed: {:?}",
                &sensor_name, e
            );
            let response = match e {
                sensors::SensorError::UnknownSensor(sensor) => {
                    self.err_response(status::BadRequest, &format!("Unknown sensor: {}", sensor))
                }
                sensors::SensorError::Redis(_) | sensors::SensorError::R2d2(_) => {
                    self.err_response(status::InternalServerError, "Updating values in datastore failed")
                }
            };
            return Ok(response);
        };

        // Create response
        Ok(self.ok_response())
    }
}

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

    #[test]
    fn test_serialize_error_response() {
        let error = ErrorResponse {
            reason: "foobared".into(),
        };
        let json = serde_json::to_string(&error).unwrap();
        assert_eq!(json, r#"{"status":"error","reason":"foobared"}"#);
    }
}
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
extern crate rand;

use std::error::Error;
use std::path::Path;
use std::process::Command;

use consts::IEC;

use devicemapper::DM;
use devicemapper::Bytes;
use devicemapper::{ThinDev, ThinStatus};
use devicemapper::ThinPoolDev;

use engine::{EngineError, EngineResult, ErrorEnum, Filesystem};
use super::super::engine::{FilesystemUuid, HasName, HasUuid, PoolUuid};
use super::dmdevice::{ThinRole, format_thin_name};

#[derive(Debug)]
pub struct StratFilesystem {
    fs_id: FilesystemUuid,
    name: String,
    thin_dev: ThinDev,
}

pub enum FilesystemStatus {
    Good,
    Failed,
}

impl StratFilesystem {
    pub fn initialize(pool_id: &PoolUuid,
                      fs_id: FilesystemUuid,
                      name: &str,
                      dm: &DM,
                      thin_pool: &ThinPoolDev)
                      -> EngineResult<StratFilesystem> {
        // TODO should replace with proper id generation. DM takes a 24 bit
        // number for the thin_id.  Generate a u16 to avoid the possibility of
        // "too big". Should this be moved into the DM binding (or lower)?
        // How can a client be expected to avoid collisions?
        let thin_id = rand::random::<u16>();
        let device_name = format_thin_name(pool_id, ThinRole::Filesystem(fs_id));
        // TODO We don't require a size to be provided for create_filesystems -
        // but devicemapper requires an initial size for a thin provisioned
        // device - currently hard coded to 1GB.
        let new_thin_dev = try!(ThinDev::new(&device_name,
                                             dm,
                                             thin_pool,
                                             thin_id as u32,
                                             Bytes(IEC::Gi).sectors()));
        try!(create_fs(new_thin_dev.devnode().unwrap().as_path()));
        Ok(StratFilesystem {
               fs_id: fs_id,
               name: name.to_owned(),
               thin_dev: new_thin_dev,
           })
    }

    pub fn check(&self, dm: &DM) -> EngineResult<FilesystemStatus> {
        match try!(self.thin_dev.status(dm)) {
            ThinStatus::Good((_mapped, _highest)) => {
                // TODO: check if filesystem is getting full and might need to
                // be extended (hint: use statfs(2))
                // TODO: periodically kick off fstrim?
            }
            ThinStatus::Fail => return Ok(FilesystemStatus::Failed),
        }
        Ok(FilesystemStatus::Good)
    }
}

impl HasName for StratFilesystem {
    fn name(&self) -> &str {
        &self.name
    }
}

impl HasUuid for StratFilesystem {
    fn uuid(&self) -> &FilesystemUuid {
        &self.fs_id
    }
}

impl Filesystem for StratFilesystem {
    fn rename(&mut self, name: &str) {
        self.name = name.to_owned();
    }

    fn destroy(self) -> EngineResult<()> {
        let dm = try!(DM::new());
        match self.thin_dev.teardown(&dm) {
            Ok(_) => Ok(()),
            Err(e) => Err(EngineError::Engine(ErrorEnum::Error, e.description().into())),
        }
    }
}

pub fn create_fs(dev_path: &Path) -> EngineResult<()> {

    debug!("Create filesystem for : {:?}", dev_path);
    let output = try!(Command::new("mkfs.xfs")
                          .arg("-f")
                          .arg(&dev_path)
                          .output());

    if output.status.success() {
        debug!("Created xfs filesystem on {:?}", dev_path)
    } else {
        let message = String::from_utf8_lossy(&output.stderr);
        debug!("stderr: {}", message);
        return Err(EngineError::Engine(ErrorEnum::Error, message.into()));
    }
    Ok(())
}

pub fn mount_fs(dev_path: &Path, mount_point: &Path) -> EngineResult<()> {

    debug!("Mount filesystem {:?} on : {:?}", dev_path, mount_point);
    let output = try!(Command::new("mount")
                          .arg(&dev_path)
                          .arg(mount_point)
                          .output());

    if output.status.success() {
        debug!("Mounted filesystem on {:?}", mount_point)
    } else {
        let message = String::from_utf8_lossy(&output.stderr);
        debug!("stderr: {}", message);
        return Err(EngineError::Engine(ErrorEnum::Error, message.into()));
    }
    Ok(())
}

pub fn unmount_fs(mount_point: &Path) -> EngineResult<()> {
    debug!("Unmount filesystem {:?}", mount_point);

    let output = try!(Command::new("umount").arg(mount_point).output());

    if output.status.success() {
        debug!("Unmounted filesystem {:?}", mount_point)
    } else {
        let message = String::from_utf8_lossy(&output.stderr);
        debug!("stderr: {}", message);
        return Err(EngineError::Engine(ErrorEnum::Error, message.into()));
    }
    Ok(())
}
<commit_msg>Get rid of an unwrap() in source code<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
extern crate rand;

use std::error::Error;
use std::path::Path;
use std::process::Command;

use consts::IEC;

use devicemapper::DM;
use devicemapper::Bytes;
use devicemapper::{ThinDev, ThinStatus};
use devicemapper::ThinPoolDev;

use engine::{EngineError, EngineResult, ErrorEnum, Filesystem};
use super::super::engine::{FilesystemUuid, HasName, HasUuid, PoolUuid};
use super::dmdevice::{ThinRole, format_thin_name};

#[derive(Debug)]
pub struct StratFilesystem {
    fs_id: FilesystemUuid,
    name: String,
    thin_dev: ThinDev,
}

pub enum FilesystemStatus {
    Good,
    Failed,
}

impl StratFilesystem {
    pub fn initialize(pool_id: &PoolUuid,
                      fs_id: FilesystemUuid,
                      name: &str,
                      dm: &DM,
                      thin_pool: &ThinPoolDev)
                      -> EngineResult<StratFilesystem> {
        // TODO should replace with proper id generation. DM takes a 24 bit
        // number for the thin_id.  Generate a u16 to avoid the possibility of
        // "too big". Should this be moved into the DM binding (or lower)?
        // How can a client be expected to avoid collisions?
        let thin_id = rand::random::<u16>();
        let device_name = format_thin_name(pool_id, ThinRole::Filesystem(fs_id));
        // TODO We don't require a size to be provided for create_filesystems -
        // but devicemapper requires an initial size for a thin provisioned
        // device - currently hard coded to 1GB.
        let new_thin_dev = try!(ThinDev::new(&device_name,
                                             dm,
                                             thin_pool,
                                             thin_id as u32,
                                             Bytes(IEC::Gi).sectors()));
        try!(create_fs(try!(new_thin_dev.devnode()).as_path()));
        Ok(StratFilesystem {
               fs_id: fs_id,
               name: name.to_owned(),
               thin_dev: new_thin_dev,
           })
    }

    pub fn check(&self, dm: &DM) -> EngineResult<FilesystemStatus> {
        match try!(self.thin_dev.status(dm)) {
            ThinStatus::Good((_mapped, _highest)) => {
                // TODO: check if filesystem is getting full and might need to
                // be extended (hint: use statfs(2))
                // TODO: periodically kick off fstrim?
            }
            ThinStatus::Fail => return Ok(FilesystemStatus::Failed),
        }
        Ok(FilesystemStatus::Good)
    }
}

impl HasName for StratFilesystem {
    fn name(&self) -> &str {
        &self.name
    }
}

impl HasUuid for StratFilesystem {
    fn uuid(&self) -> &FilesystemUuid {
        &self.fs_id
    }
}

impl Filesystem for StratFilesystem {
    fn rename(&mut self, name: &str) {
        self.name = name.to_owned();
    }

    fn destroy(self) -> EngineResult<()> {
        let dm = try!(DM::new());
        match self.thin_dev.teardown(&dm) {
            Ok(_) => Ok(()),
            Err(e) => Err(EngineError::Engine(ErrorEnum::Error, e.description().into())),
        }
    }
}

pub fn create_fs(dev_path: &Path) -> EngineResult<()> {

    debug!("Create filesystem for : {:?}", dev_path);
    let output = try!(Command::new("mkfs.xfs")
                          .arg("-f")
                          .arg(&dev_path)
                          .output());

    if output.status.success() {
        debug!("Created xfs filesystem on {:?}", dev_path)
    } else {
        let message = String::from_utf8_lossy(&output.stderr);
        debug!("stderr: {}", message);
        return Err(EngineError::Engine(ErrorEnum::Error, message.into()));
    }
    Ok(())
}

pub fn mount_fs(dev_path: &Path, mount_point: &Path) -> EngineResult<()> {

    debug!("Mount filesystem {:?} on : {:?}", dev_path, mount_point);
    let output = try!(Command::new("mount")
                          .arg(&dev_path)
                          .arg(mount_point)
                          .output());

    if output.status.success() {
        debug!("Mounted filesystem on {:?}", mount_point)
    } else {
        let message = String::from_utf8_lossy(&output.stderr);
        debug!("stderr: {}", message);
        return Err(EngineError::Engine(ErrorEnum::Error, message.into()));
    }
    Ok(())
}

pub fn unmount_fs(mount_point: &Path) -> EngineResult<()> {
    debug!("Unmount filesystem {:?}", mount_point);

    let output = try!(Command::new("umount").arg(mount_point).output());

    if output.status.success() {
        debug!("Unmounted filesystem {:?}", mount_point)
    } else {
        let message = String::from_utf8_lossy(&output.stderr);
        debug!("stderr: {}", message);
        return Err(EngineError::Engine(ErrorEnum::Error, message.into()));
    }
    Ok(())
}
<|endoftext|>


<commit_before>use core::prelude::*;

use aspace::mapflag;
use con;
use con::write;
use cpu;
use process;
use process::Handle;
use process::Process;
use start32::kernel_base;
use util::abort;

static log_syscall : bool = false;
static log_transfer_message : bool = false;

pub mod nr {
    #![allow(dead_code)]
    pub static RECV : uint = 0;
    pub static MAP : uint = 1;
    pub static PFAULT : uint = 2;
    pub static UNMAP : uint = 3;
    pub static HMOD : uint = 4;
    pub static NEWPROC : uint = 5;
    pub static WRITE : uint = 6;
    pub static PORTIO : uint = 7;
    pub static GRANT : uint = 8;
    pub static PULSE : uint = 9;

    pub static USER : uint = 16;

    pub static MSG_MASK : uint = 0xff;
    pub static MSG_KIND_MASK : uint = 0x300;
    pub static MSG_KIND_SEND : uint = 0x000;
    pub static MSG_KIND_CALL : uint = 0x100;
}

// Note: tail-called from the syscall code, "return" by switching to a process.
#[no_mangle]
pub fn syscall(
    arg0: uint,
    arg1: uint,
    arg2: uint,
    arg3: uint,
    arg4: uint,
    arg5: uint,
    nr : uint, // saved_rax
) -> ! {
    use syscall::nr::*;

    let p = unsafe { cpu().get_process() };
    // FIXME cpu.leave_proc?
    p.unset(process::Running);
    p.set(process::FastRet);

    if log_syscall {
        write("syscall! nr=");
        con::writeUInt(nr);
        write(" from process ");
        con::writeMutPtr(p);
        con::newline();
    }

    if nr >= USER {
        match nr & MSG_KIND_MASK {
            MSG_KIND_CALL => ipc_call(p, nr & MSG_MASK, arg0, arg1, arg2, arg3, arg4, arg5),
            MSG_KIND_SEND => ipc_send(p, nr & MSG_MASK, arg0, arg1, arg2, arg3, arg4, arg5),
            _ => abort("Unknown IPC kind")
        }
        unsafe { cpu().run(); }
    }

    match nr {
    RECV => ipc_recv(p, arg0),
    MAP => syscall_map(p, arg0, arg1, arg2, arg3, arg4),
    PFAULT => syscall_pfault(p, arg1, arg2), // arg0 is always 0
    HMOD => syscall_hmod(p, arg0, arg1, arg2),
    PORTIO => syscall_portio(p, arg0, arg1, arg2),
    _ => abort("Unhandled syscall"),
    }

    unsafe { cpu().run(); }
}

fn ipc_call(p : &mut Process, msg : uint, to : uint, arg1: uint, arg2: uint,
    arg3: uint, arg4: uint, arg5: uint) {
    write("ipc_call to ");
    con::writeUInt(to);
    con::newline();

    let handle = p.find_handle(to);
    match handle {
    Some(h) => {
        write("==> process ");
        con::writeMutPtr(h.process());
        con::newline();
        p.set(process::InSend);
        p.set(process::InRecv);
        p.regs.rdi = to;
        send_or_block(h, msg, arg1, arg2, arg3, arg4, arg5);
    },
    None => abort("ipc_call: no recipient")
    }
    write("ipc_call: blocked\n");
}

fn transfer_set_handle(target: &mut Process, source: &mut Process) {
    let mut rcpt = target.regs.rdi;
    let from = source.regs.rdi;

    let h = source.find_handle(from).unwrap();
    if rcpt == 0 {
        rcpt = h.other().unwrap().id();
    } else if !target.find_handle(rcpt).is_some() {
        match h.other() {
            // Already associated, "junk" the fresh handle and just update the
            // recipient-side handle.
            Some(g) => rcpt = g.id(),
            // Associate handles now.
            None => {
                let g = target.new_handle(rcpt, source);
                g.associate(h);
            },
        }
    } else {
        // TODO Assert that rcpt <-> from. (But the caller is responsible for
        // checking that first.)
    }
    target.regs.rdi = rcpt;
}

fn transfer_message(target: &mut Process, source: &mut Process) -> ! {
    transfer_set_handle(target, source);

    if log_transfer_message {
        write("transfer_message ");
        con::writeMutPtr(target);
        write(" <- ");
        con::writeMutPtr(source);
        con::newline();
    }

    target.regs.rax = source.regs.rax;
    target.regs.rdi = source.regs.rdi;
    target.regs.rsi = source.regs.rsi;
    target.regs.rdx = source.regs.rdx;
    target.regs.r8 = source.regs.r8;
    target.regs.r9 = source.regs.r9;
    target.regs.r10 = source.regs.r10;

    target.unset(process::InRecv);
    source.unset(process::InSend);

    let c = cpu();
    c.queue(target);
    if source.ipc_state() == 0 {
        c.queue(source);
    }
    unsafe { c.run(); }
}

fn send_or_block(h : &mut Handle, msg: uint, arg1: uint, arg2: uint,
        arg3: uint, arg4: uint, arg5: uint) {
    match h.other() {
        Some(g) => {
            let p = h.process();
            let sender = g.process();

            // Save regs - either we'll copy these in transfer_message or we'll
            // need to store them until later on when the transfer can finish.
            sender.regs.rax = msg;
            sender.regs.rdi = h.id();
            sender.regs.rsi = arg1;
            sender.regs.rdx = arg2;
            sender.regs.r10 = arg3;
            sender.regs.r8 = arg4;
            sender.regs.r9 = arg5;

            // p is the recipient, the sender is in g.process().
            if p.ipc_state() == process::InRecv.mask() {
                let rcpt = h.process().regs.rdi;
                // Check the receiving process' receipt handle
                //   0 ==> transfer
                //   !0, connected to our handle ==> transfer
                //   !0, fresh ==> transfer
                //   !0 otherwise ==> block
                if rcpt == 0
                || rcpt == g.id()
                || !p.find_handle(rcpt).is_some() {
                    transfer_message(p, sender);
                }
            }

            p.add_waiter(sender)
        },
        None => abort("sending to unconnected handle"),
    }
}

fn ipc_send(p : &mut Process, msg : uint, to : uint, arg1: uint, arg2: uint,
        arg3: uint, arg4: uint, arg5: uint) {
    let handle = p.find_handle(to);
    match handle {
    Some(h) => {
        p.set(process::InSend);
        send_or_block(h, msg, arg1, arg2, arg3, arg4, arg5);
    },
    None => abort("ipc_send: no recipient")
    }
}

fn ipc_recv(p : &mut Process, from : uint) {
    let mut handle = None;
    if from != 0 {
        handle = p.find_handle(from);
    }

    write("recv from ");
    con::writeUInt(from);
    con::newline();

    p.set(process::InRecv);
    p.regs.rdi = from;
    match handle {
        Some(h) => {
            write("==> process ");
            con::writeMutPtr(h.process());
            con::newline();
            recv(p, h)
        },
        None => {
            if from != 0 {
                write("==> fresh\n");
            }
            recv_from_any(p, from)
        }
    }
}

fn recv(p: &mut Process, handle: &mut Handle) {
    let rcpt = handle.process();
    if rcpt.is(process::InSend) {
        abort("recv-from-specific not implemented");
    } else {
        rcpt.add_waiter(p);
    }
}

fn recv_from_any(p : &mut Process, _id: uint) {
    for waiter in p.waiters.iter() {
        if waiter.is(process::InSend) {
            abort("found sender!");
        }
    }
    // TODO Look for pending pulse
    // 2. Look for pending pulses
    // 3. Switch next
}

fn syscall_map(p: &mut Process, handle: uint, mut prot: uint, addr: uint, mut offset: uint, size: uint) {
    prot &= mapflag::UserAllowed;
    // TODO Check (and return failure) on:
    // * unaligned addr, offset, size (must be page-aligned)
    if (prot & mapflag::DMA) == mapflag::DMA {
        offset = match cpu().memory.alloc_frame() {
            None => 0,
            Some(p) => p as uint - kernel_base,
        }
    }

    p.aspace().map_range(addr, addr + size, handle, (offset - addr) | prot);

    if (prot & mapflag::Phys) == 0 {
        offset = 0;
    }
    cpu().syscall_return(p, offset);
}

fn syscall_pfault(p : &mut Process, mut vaddr: uint, access: uint) {
    vaddr &= !0xfff;

    // set fault address
    p.fault_addr = vaddr;
    p.regs.rsi = vaddr;
    p.regs.rdx = access & mapflag::RWX;
    // Look up vaddr, get handle, offset and flags
    let card = p.aspace().mapcard_find_def(vaddr);
    p.regs.rsi += card.offset; // proc.rsi is now translated into offset
    p.regs.rdi = card.handle;
    p.set(process::PFault);

    // Now do the equivalent of sendrcv with rdi=handle, rsi=offset, rdx=flags
}

fn syscall_hmod(p : &mut Process, id: uint, rename: uint, copy: uint) {
    let handle = p.find_handle(id);
    match handle {
    None => return,
    Some(h) => {
        // Fresh/dissociated handle for the same process as the original
        if copy != 0 {
            p.new_handle(copy, h.process());
        }
        if rename != 0 {
            p.rename_handle(h, rename);
        } else {
            p.delete_handle(h);
        }
    }
    }
}

fn syscall_portio(p : &mut Process, port : uint, op : uint, data: uint) -> ! {
    let mut res : uint = 0;
    unsafe { match op {
    0x01 => asm!("inb %dx, %al" : "={al}"(res) : "{dx}"(port)),
    0x02 => asm!("inw %dx, %ax" : "={ax}"(res) : "{dx}"(port)),
    0x04 => asm!("inl %dx, %eax" : "={eax}"(res) : "{dx}"(port)),
    0x11 => asm!("outb %al, %dx" :: "{al}"(data), "{dx}"(port)),
    0x12 => asm!("outw %ax, %dx" :: "{ax}"(data), "{dx}"(port)),
    0x14 => asm!("outl %eax, %dx" :: "{eax}"(data), "{dx}"(port)),
    _ => abort("unhandled portio operation")
    } }
    cpu().syscall_return(p, res);
}
<commit_msg>Implement WRITE syscall<commit_after>use core::prelude::*;

use aspace::mapflag;
use con;
use con::write;
use cpu;
use process;
use process::Handle;
use process::Process;
use start32::kernel_base;
use util::abort;

static log_syscall : bool = false;
static log_transfer_message : bool = false;

pub mod nr {
    #![allow(dead_code)]
    pub static RECV : uint = 0;
    pub static MAP : uint = 1;
    pub static PFAULT : uint = 2;
    pub static UNMAP : uint = 3;
    pub static HMOD : uint = 4;
    pub static NEWPROC : uint = 5;
    pub static WRITE : uint = 6;
    pub static PORTIO : uint = 7;
    pub static GRANT : uint = 8;
    pub static PULSE : uint = 9;

    pub static USER : uint = 16;

    pub static MSG_MASK : uint = 0xff;
    pub static MSG_KIND_MASK : uint = 0x300;
    pub static MSG_KIND_SEND : uint = 0x000;
    pub static MSG_KIND_CALL : uint = 0x100;
}

// Note: tail-called from the syscall code, "return" by switching to a process.
#[no_mangle]
pub fn syscall(
    arg0: uint,
    arg1: uint,
    arg2: uint,
    arg3: uint,
    arg4: uint,
    arg5: uint,
    nr : uint, // saved_rax
) -> ! {
    use syscall::nr::*;

    let p = unsafe { cpu().get_process() };
    // FIXME cpu.leave_proc?
    p.unset(process::Running);
    p.set(process::FastRet);

    if log_syscall {
        write("syscall! nr=");
        con::writeUInt(nr);
        write(" from process ");
        con::writeMutPtr(p);
        con::newline();
    }

    if nr >= USER {
        match nr & MSG_KIND_MASK {
            MSG_KIND_CALL => ipc_call(p, nr & MSG_MASK, arg0, arg1, arg2, arg3, arg4, arg5),
            MSG_KIND_SEND => ipc_send(p, nr & MSG_MASK, arg0, arg1, arg2, arg3, arg4, arg5),
            _ => abort("Unknown IPC kind")
        }
        unsafe { cpu().run(); }
    }

    match nr {
    RECV => ipc_recv(p, arg0),
    MAP => syscall_map(p, arg0, arg1, arg2, arg3, arg4),
    PFAULT => syscall_pfault(p, arg1, arg2), // arg0 is always 0
    HMOD => syscall_hmod(p, arg0, arg1, arg2),
    PORTIO => syscall_portio(p, arg0, arg1, arg2),
    WRITE => {
        con::putc(arg0 as u8 as char);
        cpu().syscall_return(p, 0);
    },
    _ => abort("Unhandled syscall"),
    }

    unsafe { cpu().run(); }
}

fn ipc_call(p : &mut Process, msg : uint, to : uint, arg1: uint, arg2: uint,
    arg3: uint, arg4: uint, arg5: uint) {
    write("ipc_call to ");
    con::writeUInt(to);
    con::newline();

    let handle = p.find_handle(to);
    match handle {
    Some(h) => {
        write("==> process ");
        con::writeMutPtr(h.process());
        con::newline();
        p.set(process::InSend);
        p.set(process::InRecv);
        p.regs.rdi = to;
        send_or_block(h, msg, arg1, arg2, arg3, arg4, arg5);
    },
    None => abort("ipc_call: no recipient")
    }
    write("ipc_call: blocked\n");
}

fn transfer_set_handle(target: &mut Process, source: &mut Process) {
    let mut rcpt = target.regs.rdi;
    let from = source.regs.rdi;

    let h = source.find_handle(from).unwrap();
    if rcpt == 0 {
        rcpt = h.other().unwrap().id();
    } else if !target.find_handle(rcpt).is_some() {
        match h.other() {
            // Already associated, "junk" the fresh handle and just update the
            // recipient-side handle.
            Some(g) => rcpt = g.id(),
            // Associate handles now.
            None => {
                let g = target.new_handle(rcpt, source);
                g.associate(h);
            },
        }
    } else {
        // TODO Assert that rcpt <-> from. (But the caller is responsible for
        // checking that first.)
    }
    target.regs.rdi = rcpt;
}

fn transfer_message(target: &mut Process, source: &mut Process) -> ! {
    transfer_set_handle(target, source);

    if log_transfer_message {
        write("transfer_message ");
        con::writeMutPtr(target);
        write(" <- ");
        con::writeMutPtr(source);
        con::newline();
    }

    target.regs.rax = source.regs.rax;
    target.regs.rdi = source.regs.rdi;
    target.regs.rsi = source.regs.rsi;
    target.regs.rdx = source.regs.rdx;
    target.regs.r8 = source.regs.r8;
    target.regs.r9 = source.regs.r9;
    target.regs.r10 = source.regs.r10;

    target.unset(process::InRecv);
    source.unset(process::InSend);

    let c = cpu();
    c.queue(target);
    if source.ipc_state() == 0 {
        c.queue(source);
    }
    unsafe { c.run(); }
}

fn send_or_block(h : &mut Handle, msg: uint, arg1: uint, arg2: uint,
        arg3: uint, arg4: uint, arg5: uint) {
    match h.other() {
        Some(g) => {
            let p = h.process();
            let sender = g.process();

            // Save regs - either we'll copy these in transfer_message or we'll
            // need to store them until later on when the transfer can finish.
            sender.regs.rax = msg;
            sender.regs.rdi = h.id();
            sender.regs.rsi = arg1;
            sender.regs.rdx = arg2;
            sender.regs.r10 = arg3;
            sender.regs.r8 = arg4;
            sender.regs.r9 = arg5;

            // p is the recipient, the sender is in g.process().
            if p.ipc_state() == process::InRecv.mask() {
                let rcpt = h.process().regs.rdi;
                // Check the receiving process' receipt handle
                //   0 ==> transfer
                //   !0, connected to our handle ==> transfer
                //   !0, fresh ==> transfer
                //   !0 otherwise ==> block
                if rcpt == 0
                || rcpt == g.id()
                || !p.find_handle(rcpt).is_some() {
                    transfer_message(p, sender);
                }
            }

            p.add_waiter(sender)
        },
        None => abort("sending to unconnected handle"),
    }
}

fn ipc_send(p : &mut Process, msg : uint, to : uint, arg1: uint, arg2: uint,
        arg3: uint, arg4: uint, arg5: uint) {
    let handle = p.find_handle(to);
    match handle {
    Some(h) => {
        p.set(process::InSend);
        send_or_block(h, msg, arg1, arg2, arg3, arg4, arg5);
    },
    None => abort("ipc_send: no recipient")
    }
}

fn ipc_recv(p : &mut Process, from : uint) {
    let mut handle = None;
    if from != 0 {
        handle = p.find_handle(from);
    }

    write("recv from ");
    con::writeUInt(from);
    con::newline();

    p.set(process::InRecv);
    p.regs.rdi = from;
    match handle {
        Some(h) => {
            write("==> process ");
            con::writeMutPtr(h.process());
            con::newline();
            recv(p, h)
        },
        None => {
            if from != 0 {
                write("==> fresh\n");
            }
            recv_from_any(p, from)
        }
    }
}

fn recv(p: &mut Process, handle: &mut Handle) {
    let rcpt = handle.process();
    if rcpt.is(process::InSend) {
        abort("recv-from-specific not implemented");
    } else {
        rcpt.add_waiter(p);
    }
}

fn recv_from_any(p : &mut Process, _id: uint) {
    for waiter in p.waiters.iter() {
        if waiter.is(process::InSend) {
            abort("found sender!");
        }
    }
    // TODO Look for pending pulse
    // 2. Look for pending pulses
    // 3. Switch next
}

fn syscall_map(p: &mut Process, handle: uint, mut prot: uint, addr: uint, mut offset: uint, size: uint) {
    prot &= mapflag::UserAllowed;
    // TODO Check (and return failure) on:
    // * unaligned addr, offset, size (must be page-aligned)
    if (prot & mapflag::DMA) == mapflag::DMA {
        offset = match cpu().memory.alloc_frame() {
            None => 0,
            Some(p) => p as uint - kernel_base,
        }
    }

    p.aspace().map_range(addr, addr + size, handle, (offset - addr) | prot);

    if (prot & mapflag::Phys) == 0 {
        offset = 0;
    }
    cpu().syscall_return(p, offset);
}

fn syscall_pfault(p : &mut Process, mut vaddr: uint, access: uint) {
    vaddr &= !0xfff;

    // set fault address
    p.fault_addr = vaddr;
    p.regs.rsi = vaddr;
    p.regs.rdx = access & mapflag::RWX;
    // Look up vaddr, get handle, offset and flags
    let card = p.aspace().mapcard_find_def(vaddr);
    p.regs.rsi += card.offset; // proc.rsi is now translated into offset
    p.regs.rdi = card.handle;
    p.set(process::PFault);

    // Now do the equivalent of sendrcv with rdi=handle, rsi=offset, rdx=flags
}

fn syscall_hmod(p : &mut Process, id: uint, rename: uint, copy: uint) {
    let handle = p.find_handle(id);
    match handle {
    None => return,
    Some(h) => {
        // Fresh/dissociated handle for the same process as the original
        if copy != 0 {
            p.new_handle(copy, h.process());
        }
        if rename != 0 {
            p.rename_handle(h, rename);
        } else {
            p.delete_handle(h);
        }
    }
    }
}

fn syscall_portio(p : &mut Process, port : uint, op : uint, data: uint) -> ! {
    let mut res : uint = 0;
    unsafe { match op {
    0x01 => asm!("inb %dx, %al" : "={al}"(res) : "{dx}"(port)),
    0x02 => asm!("inw %dx, %ax" : "={ax}"(res) : "{dx}"(port)),
    0x04 => asm!("inl %dx, %eax" : "={eax}"(res) : "{dx}"(port)),
    0x11 => asm!("outb %al, %dx" :: "{al}"(data), "{dx}"(port)),
    0x12 => asm!("outw %ax, %dx" :: "{ax}"(data), "{dx}"(port)),
    0x14 => asm!("outl %eax, %dx" :: "{eax}"(data), "{dx}"(port)),
    _ => abort("unhandled portio operation")
    } }
    cpu().syscall_return(p, res);
}
<|endoftext|>